[PIE-1580] Metrics for smart contract permissioning actions (#1492)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Chris Mckay 6 years ago committed by GitHub
parent 2abe4366e7
commit d325989017
  1. 1
      ethereum/permissioning/build.gradle
  2. 10
      ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/NodePermissioningControllerFactory.java
  3. 36
      ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/NodeSmartContractPermissioningController.java
  4. 36
      ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/TransactionSmartContractPermissioningController.java
  5. 40
      ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProvider.java
  6. 90
      ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java
  7. 75
      ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java
  8. 36
      ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/node/NodePermissioningControllerFactoryTest.java
  9. 60
      ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/node/provider/SyncStatusNodePermissioningProviderTest.java
  10. 1
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java
  11. 8
      pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java

@ -29,6 +29,7 @@ dependencies {
implementation project(':util') implementation project(':util')
implementation project(':ethereum:core') implementation project(':ethereum:core')
implementation project(':crypto') implementation project(':crypto')
implementation project(':metrics:core')
implementation 'com.google.guava:guava' implementation 'com.google.guava:guava'
implementation 'net.consensys.cava:cava-toml' implementation 'net.consensys.cava:cava-toml'

@ -17,6 +17,7 @@ import tech.pegasys.pantheon.ethereum.permissioning.node.NodePermissioningContro
import tech.pegasys.pantheon.ethereum.permissioning.node.NodePermissioningProvider; import tech.pegasys.pantheon.ethereum.permissioning.node.NodePermissioningProvider;
import tech.pegasys.pantheon.ethereum.permissioning.node.provider.SyncStatusNodePermissioningProvider; import tech.pegasys.pantheon.ethereum.permissioning.node.provider.SyncStatusNodePermissioningProvider;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.enode.EnodeURL; import tech.pegasys.pantheon.util.enode.EnodeURL;
@ -32,7 +33,8 @@ public class NodePermissioningControllerFactory {
final Synchronizer synchronizer, final Synchronizer synchronizer,
final Collection<EnodeURL> fixedNodes, final Collection<EnodeURL> fixedNodes,
final BytesValue localNodeId, final BytesValue localNodeId,
final TransactionSimulator transactionSimulator) { final TransactionSimulator transactionSimulator,
final MetricsSystem metricsSystem) {
Optional<SyncStatusNodePermissioningProvider> syncStatusProviderOptional; Optional<SyncStatusNodePermissioningProvider> syncStatusProviderOptional;
@ -55,7 +57,8 @@ public class NodePermissioningControllerFactory {
NodeSmartContractPermissioningController smartContractProvider = NodeSmartContractPermissioningController smartContractProvider =
new NodeSmartContractPermissioningController( new NodeSmartContractPermissioningController(
smartContractPermissioningConfiguration.getNodeSmartContractAddress(), smartContractPermissioningConfiguration.getNodeSmartContractAddress(),
transactionSimulator); transactionSimulator,
metricsSystem);
providers.add(smartContractProvider); providers.add(smartContractProvider);
} }
@ -63,7 +66,8 @@ public class NodePermissioningControllerFactory {
syncStatusProviderOptional = Optional.empty(); syncStatusProviderOptional = Optional.empty();
} else { } else {
syncStatusProviderOptional = syncStatusProviderOptional =
Optional.of(new SyncStatusNodePermissioningProvider(synchronizer, fixedNodes)); Optional.of(
new SyncStatusNodePermissioningProvider(synchronizer, fixedNodes, metricsSystem));
} }
} else { } else {
syncStatusProviderOptional = Optional.empty(); syncStatusProviderOptional = Optional.empty();

@ -20,6 +20,9 @@ import tech.pegasys.pantheon.ethereum.permissioning.node.NodePermissioningProvid
import tech.pegasys.pantheon.ethereum.transaction.CallParameter; import tech.pegasys.pantheon.ethereum.transaction.CallParameter;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulatorResult; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulatorResult;
import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.bytes.BytesValues; import tech.pegasys.pantheon.util.bytes.BytesValues;
import tech.pegasys.pantheon.util.enode.EnodeURL; import tech.pegasys.pantheon.util.enode.EnodeURL;
@ -40,6 +43,9 @@ public class NodeSmartContractPermissioningController implements NodePermissioni
"connectionAllowed(bytes32,bytes32,bytes16,uint16,bytes32,bytes32,bytes16,uint16)"; "connectionAllowed(bytes32,bytes32,bytes16,uint16,bytes32,bytes32,bytes16,uint16)";
// hashed function signature for connection allowed call // hashed function signature for connection allowed call
private static final BytesValue FUNCTION_SIGNATURE_HASH = hashSignature(FUNCTION_SIGNATURE); private static final BytesValue FUNCTION_SIGNATURE_HASH = hashSignature(FUNCTION_SIGNATURE);
private final Counter checkCounter;
private final Counter checkCounterPermitted;
private final Counter checkCounterUnpermitted;
// The first 4 bytes of the hash of the full textual signature of the function is used in // The first 4 bytes of the hash of the full textual signature of the function is used in
// contract calls to determine the function being called // contract calls to determine the function being called
@ -60,11 +66,30 @@ public class NodeSmartContractPermissioningController implements NodePermissioni
* *
* @param contractAddress The address at which the permissioning smart contract resides * @param contractAddress The address at which the permissioning smart contract resides
* @param transactionSimulator A transaction simulator with attached blockchain and world state * @param transactionSimulator A transaction simulator with attached blockchain and world state
* @param metricsSystem The metrics provider that is to be reported to
*/ */
public NodeSmartContractPermissioningController( public NodeSmartContractPermissioningController(
final Address contractAddress, final TransactionSimulator transactionSimulator) { final Address contractAddress,
final TransactionSimulator transactionSimulator,
final MetricsSystem metricsSystem) {
this.contractAddress = contractAddress; this.contractAddress = contractAddress;
this.transactionSimulator = transactionSimulator; this.transactionSimulator = transactionSimulator;
this.checkCounter =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"node_smart_contract_check_count",
"Number of times the node smart contract permissioning provider has been checked");
this.checkCounterPermitted =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"node_smart_contract_check_count_permitted",
"Number of times the node smart contract permissioning provider has been checked and returned permitted");
this.checkCounterUnpermitted =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"node_smart_contract_check_count_unpermitted",
"Number of times the node smart contract permissioning provider has been checked and returned unpermitted");
} }
/** /**
@ -76,6 +101,7 @@ public class NodeSmartContractPermissioningController implements NodePermissioni
*/ */
@Override @Override
public boolean isPermitted(final EnodeURL sourceEnode, final EnodeURL destinationEnode) { public boolean isPermitted(final EnodeURL sourceEnode, final EnodeURL destinationEnode) {
this.checkCounter.inc();
final BytesValue payload = createPayload(sourceEnode, destinationEnode); final BytesValue payload = createPayload(sourceEnode, destinationEnode);
final CallParameter callParams = final CallParameter callParams =
new CallParameter(null, contractAddress, -1, null, null, payload); new CallParameter(null, contractAddress, -1, null, null, payload);
@ -101,7 +127,13 @@ public class NodeSmartContractPermissioningController implements NodePermissioni
} }
} }
return result.map(r -> checkTransactionResult(r.getOutput())).orElse(false); if (result.map(r -> checkTransactionResult(r.getOutput())).orElse(false)) {
this.checkCounterPermitted.inc();
return true;
} else {
this.checkCounterUnpermitted.inc();
return false;
}
} }
// Checks the returned bytes from the permissioning contract call to see if it's a value we // Checks the returned bytes from the permissioning contract call to see if it's a value we

@ -22,6 +22,9 @@ import tech.pegasys.pantheon.ethereum.permissioning.account.TransactionPermissio
import tech.pegasys.pantheon.ethereum.transaction.CallParameter; import tech.pegasys.pantheon.ethereum.transaction.CallParameter;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulatorResult; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulatorResult;
import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.bytes.BytesValues; import tech.pegasys.pantheon.util.bytes.BytesValues;
@ -41,6 +44,9 @@ public class TransactionSmartContractPermissioningController
"transactionAllowed(address,address,uint256,uint256,uint256,bytes)"; "transactionAllowed(address,address,uint256,uint256,uint256,bytes)";
// hashed function signature for connection allowed call // hashed function signature for connection allowed call
private static final BytesValue FUNCTION_SIGNATURE_HASH = hashSignature(FUNCTION_SIGNATURE); private static final BytesValue FUNCTION_SIGNATURE_HASH = hashSignature(FUNCTION_SIGNATURE);
private final Counter checkCounterPermitted;
private final Counter checkCounter;
private final Counter checkCounterUnpermitted;
// The first 4 bytes of the hash of the full textual signature of the function is used in // The first 4 bytes of the hash of the full textual signature of the function is used in
// contract calls to determine the function being called // contract calls to determine the function being called
@ -61,11 +67,30 @@ public class TransactionSmartContractPermissioningController
* *
* @param contractAddress The address at which the permissioning smart contract resides * @param contractAddress The address at which the permissioning smart contract resides
* @param transactionSimulator A transaction simulator with attached blockchain and world state * @param transactionSimulator A transaction simulator with attached blockchain and world state
* @param metricsSystem The metrics provider that is to be reported to
*/ */
public TransactionSmartContractPermissioningController( public TransactionSmartContractPermissioningController(
final Address contractAddress, final TransactionSimulator transactionSimulator) { final Address contractAddress,
final TransactionSimulator transactionSimulator,
final MetricsSystem metricsSystem) {
this.contractAddress = contractAddress; this.contractAddress = contractAddress;
this.transactionSimulator = transactionSimulator; this.transactionSimulator = transactionSimulator;
this.checkCounter =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"transaction_smart_contract_check_count",
"Number of times the transaction smart contract permissioning provider has been checked");
this.checkCounterPermitted =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"transaction_smart_contract_check_count_permitted",
"Number of times the transaction smart contract permissioning provider has been checked and returned permitted");
this.checkCounterUnpermitted =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"transaction_smart_contract_check_count_unpermitted",
"Number of times the transaction smart contract permissioning provider has been checked and returned unpermitted");
} }
/** /**
@ -76,6 +101,7 @@ public class TransactionSmartContractPermissioningController
*/ */
@Override @Override
public boolean isPermitted(final Transaction transaction) { public boolean isPermitted(final Transaction transaction) {
this.checkCounter.inc();
final BytesValue payload = createPayload(transaction); final BytesValue payload = createPayload(transaction);
final CallParameter callParams = final CallParameter callParams =
new CallParameter(null, contractAddress, -1, null, null, payload); new CallParameter(null, contractAddress, -1, null, null, payload);
@ -103,7 +129,13 @@ public class TransactionSmartContractPermissioningController
} }
} }
return result.map(r -> checkTransactionResult(r.getOutput())).orElse(false); if (result.map(r -> checkTransactionResult(r.getOutput())).orElse(false)) {
this.checkCounterPermitted.inc();
return true;
} else {
this.checkCounterUnpermitted.inc();
return false;
}
} }
// Checks the returned bytes from the permissioning contract call to see if it's a value we // Checks the returned bytes from the permissioning contract call to see if it's a value we

@ -17,6 +17,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
import tech.pegasys.pantheon.ethereum.core.SyncStatus; import tech.pegasys.pantheon.ethereum.core.SyncStatus;
import tech.pegasys.pantheon.ethereum.core.Synchronizer; import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.permissioning.node.NodePermissioningProvider; import tech.pegasys.pantheon.ethereum.permissioning.node.NodePermissioningProvider;
import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.enode.EnodeURL; import tech.pegasys.pantheon.util.enode.EnodeURL;
import java.util.Collection; import java.util.Collection;
@ -27,16 +30,42 @@ public class SyncStatusNodePermissioningProvider implements NodePermissioningPro
private final Synchronizer synchronizer; private final Synchronizer synchronizer;
private final Collection<EnodeURL> fixedNodes = new HashSet<>(); private final Collection<EnodeURL> fixedNodes = new HashSet<>();
private final Counter checkCounter;
private final Counter checkCounterPermitted;
private final Counter checkCounterUnpermitted;
private OptionalLong syncStatusObserverId; private OptionalLong syncStatusObserverId;
private boolean hasReachedSync = false; private boolean hasReachedSync = false;
public SyncStatusNodePermissioningProvider( public SyncStatusNodePermissioningProvider(
final Synchronizer synchronizer, final Collection<EnodeURL> fixedNodes) { final Synchronizer synchronizer,
final Collection<EnodeURL> fixedNodes,
final MetricsSystem metricsSystem) {
checkNotNull(synchronizer); checkNotNull(synchronizer);
this.synchronizer = synchronizer; this.synchronizer = synchronizer;
long id = this.synchronizer.observeSyncStatus(this::handleSyncStatusUpdate); long id = this.synchronizer.observeSyncStatus(this::handleSyncStatusUpdate);
this.syncStatusObserverId = OptionalLong.of(id); this.syncStatusObserverId = OptionalLong.of(id);
this.fixedNodes.addAll(fixedNodes); this.fixedNodes.addAll(fixedNodes);
metricsSystem.createIntegerGauge(
MetricCategory.PERMISSIONING,
"sync_status_node_sync_reached",
"Whether the sync status permissioning provider has realised sync yet",
() -> hasReachedSync ? 1 : 0);
this.checkCounter =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"sync_status_node_check_count",
"Number of times the sync status permissioning provider has been checked");
this.checkCounterPermitted =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"sync_status_node_check_count_permitted",
"Number of times the sync status permissioning provider has been checked and returned permitted");
this.checkCounterUnpermitted =
metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"sync_status_node_check_count_unpermitted",
"Number of times the sync status permissioning provider has been checked and returned unpermitted");
} }
private void handleSyncStatusUpdate(final SyncStatus syncStatus) { private void handleSyncStatusUpdate(final SyncStatus syncStatus) {
@ -73,7 +102,14 @@ public class SyncStatusNodePermissioningProvider implements NodePermissioningPro
if (hasReachedSync) { if (hasReachedSync) {
return true; return true;
} else { } else {
return fixedNodes.contains(destinationEnode); checkCounter.inc();
if (fixedNodes.contains(destinationEnode)) {
checkCounterPermitted.inc();
return true;
} else {
checkCounterUnpermitted.inc();
return false;
}
} }
} }

@ -15,6 +15,9 @@ package tech.pegasys.pantheon.ethereum.permissioning;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain;
import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive;
@ -26,14 +29,25 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.enode.EnodeURL; import tech.pegasys.pantheon.util.enode.EnodeURL;
import java.io.IOException; import java.io.IOException;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class NodeSmartContractPermissioningControllerTest { public class NodeSmartContractPermissioningControllerTest {
@Mock private MetricsSystem metricsSystem;
@Mock private Counter checkCounter;
@Mock private Counter checkPermittedCounter;
@Mock private Counter checkUnpermittedCounter;
private NodeSmartContractPermissioningController setupController( private NodeSmartContractPermissioningController setupController(
final String resourceName, final String contractAddressString) throws IOException { final String resourceName, final String contractAddressString) throws IOException {
@ -53,7 +67,49 @@ public class NodeSmartContractPermissioningControllerTest {
new TransactionSimulator(blockchain, worldArchive, protocolSchedule); new TransactionSimulator(blockchain, worldArchive, protocolSchedule);
final Address contractAddress = Address.fromHexString(contractAddressString); final Address contractAddress = Address.fromHexString(contractAddressString);
return new NodeSmartContractPermissioningController(contractAddress, ts); when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"node_smart_contract_check_count",
"Number of times the node smart contract permissioning provider has been checked"))
.thenReturn(checkCounter);
when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"node_smart_contract_check_count_permitted",
"Number of times the node smart contract permissioning provider has been checked and returned permitted"))
.thenReturn(checkPermittedCounter);
when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"node_smart_contract_check_count_unpermitted",
"Number of times the node smart contract permissioning provider has been checked and returned unpermitted"))
.thenReturn(checkUnpermittedCounter);
return new NodeSmartContractPermissioningController(contractAddress, ts, metricsSystem);
}
private void verifyCountersUntouched() {
verify(checkCounter, times(0)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
}
private void verifyCountersPermitted() {
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(1)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
}
private void verifyCountersUnpermitted() {
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(1)).inc();
}
private void verifyCountersFailedCheck() {
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
} }
@Test @Test
@ -63,6 +119,8 @@ public class NodeSmartContractPermissioningControllerTest {
"/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json", "/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThat( assertThat(
controller.isPermitted( controller.isPermitted(
EnodeURL.fromString( EnodeURL.fromString(
@ -70,6 +128,8 @@ public class NodeSmartContractPermissioningControllerTest {
EnodeURL.fromString( EnodeURL.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:30304"))) "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:30304")))
.isTrue(); .isTrue();
verifyCountersPermitted();
} }
@Test @Test
@ -79,6 +139,8 @@ public class NodeSmartContractPermissioningControllerTest {
"/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json", "/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThat( assertThat(
controller.isPermitted( controller.isPermitted(
EnodeURL.fromString( EnodeURL.fromString(
@ -86,6 +148,8 @@ public class NodeSmartContractPermissioningControllerTest {
EnodeURL.fromString( EnodeURL.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:30305"))) "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:30305")))
.isFalse(); .isFalse();
verifyCountersUnpermitted();
} }
@Test @Test
@ -95,6 +159,8 @@ public class NodeSmartContractPermissioningControllerTest {
"/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json", "/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThat( assertThat(
controller.isPermitted( controller.isPermitted(
EnodeURL.fromString( EnodeURL.fromString(
@ -102,6 +168,8 @@ public class NodeSmartContractPermissioningControllerTest {
EnodeURL.fromString( EnodeURL.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:30304"))) "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:30304")))
.isFalse(); .isFalse();
verifyCountersUnpermitted();
} }
@Test @Test
@ -111,6 +179,8 @@ public class NodeSmartContractPermissioningControllerTest {
"/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json", "/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThat( assertThat(
controller.isPermitted( controller.isPermitted(
EnodeURL.fromString( EnodeURL.fromString(
@ -118,6 +188,8 @@ public class NodeSmartContractPermissioningControllerTest {
EnodeURL.fromString( EnodeURL.fromString(
"enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab62@[1:2:3:4:5:6:7:8]:30304"))) "enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab62@[1:2:3:4:5:6:7:8]:30304")))
.isTrue(); .isTrue();
verifyCountersPermitted();
} }
@Test @Test
@ -127,6 +199,8 @@ public class NodeSmartContractPermissioningControllerTest {
"/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json", "/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThat( assertThat(
controller.isPermitted( controller.isPermitted(
EnodeURL.fromString( EnodeURL.fromString(
@ -134,6 +208,8 @@ public class NodeSmartContractPermissioningControllerTest {
EnodeURL.fromString( EnodeURL.fromString(
"enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab62@[1:2:3:4:5:6:7:8]:30304"))) "enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab62@[1:2:3:4:5:6:7:8]:30304")))
.isFalse(); .isFalse();
verifyCountersUnpermitted();
} }
@Test @Test
@ -143,6 +219,8 @@ public class NodeSmartContractPermissioningControllerTest {
"/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json", "/NodeSmartContractPermissioningControllerTest/preseededSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThat( assertThat(
controller.isPermitted( controller.isPermitted(
EnodeURL.fromString( EnodeURL.fromString(
@ -150,6 +228,8 @@ public class NodeSmartContractPermissioningControllerTest {
EnodeURL.fromString( EnodeURL.fromString(
"enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab63@[1:2:3:4:5:6:7:8]:30304"))) "enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab63@[1:2:3:4:5:6:7:8]:30304")))
.isFalse(); .isFalse();
verifyCountersUnpermitted();
} }
@Test @Test
@ -159,6 +239,8 @@ public class NodeSmartContractPermissioningControllerTest {
"/NodeSmartContractPermissioningControllerTest/noSmartPermissioning.json", "/NodeSmartContractPermissioningControllerTest/noSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThatThrownBy( assertThatThrownBy(
() -> () ->
controller.isPermitted( controller.isPermitted(
@ -168,6 +250,8 @@ public class NodeSmartContractPermissioningControllerTest {
"enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab63@[1:2:3:4:5:6:7:8]:30304"))) "enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab63@[1:2:3:4:5:6:7:8]:30304")))
.isInstanceOf(IllegalStateException.class) .isInstanceOf(IllegalStateException.class)
.hasMessage("Permissioning contract does not exist"); .hasMessage("Permissioning contract does not exist");
verifyCountersFailedCheck();
} }
@Test @Test
@ -177,6 +261,8 @@ public class NodeSmartContractPermissioningControllerTest {
"/NodeSmartContractPermissioningControllerTest/corruptSmartPermissioning.json", "/NodeSmartContractPermissioningControllerTest/corruptSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThatThrownBy( assertThatThrownBy(
() -> () ->
controller.isPermitted( controller.isPermitted(
@ -186,5 +272,7 @@ public class NodeSmartContractPermissioningControllerTest {
"enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab63@[1:2:3:4:5:6:7:8]:30304"))) "enode://1234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab63@[1:2:3:4:5:6:7:8]:30304")))
.isInstanceOf(IllegalStateException.class) .isInstanceOf(IllegalStateException.class)
.hasMessage("Permissioning transaction failed when processing"); .hasMessage("Permissioning transaction failed when processing");
verifyCountersFailedCheck();
} }
} }

@ -15,6 +15,9 @@ package tech.pegasys.pantheon.ethereum.permissioning;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain;
import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive;
@ -28,14 +31,26 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.io.IOException; import java.io.IOException;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class TransactionSmartContractPermissioningControllerTest { public class TransactionSmartContractPermissioningControllerTest {
@Mock private MetricsSystem metricsSystem;
@Mock private Counter checkCounter;
@Mock private Counter checkPermittedCounter;
@Mock private Counter checkUnpermittedCounter;
private TransactionSmartContractPermissioningController setupController( private TransactionSmartContractPermissioningController setupController(
final String resourceName, final String contractAddressString) throws IOException { final String resourceName, final String contractAddressString) throws IOException {
final ProtocolSchedule<Void> protocolSchedule = MainnetProtocolSchedule.create(); final ProtocolSchedule<Void> protocolSchedule = MainnetProtocolSchedule.create();
@ -54,7 +69,25 @@ public class TransactionSmartContractPermissioningControllerTest {
new TransactionSimulator(blockchain, worldArchive, protocolSchedule); new TransactionSimulator(blockchain, worldArchive, protocolSchedule);
final Address contractAddress = Address.fromHexString(contractAddressString); final Address contractAddress = Address.fromHexString(contractAddressString);
return new TransactionSmartContractPermissioningController(contractAddress, ts); when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"transaction_smart_contract_check_count",
"Number of times the transaction smart contract permissioning provider has been checked"))
.thenReturn(checkCounter);
when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"transaction_smart_contract_check_count_permitted",
"Number of times the transaction smart contract permissioning provider has been checked and returned permitted"))
.thenReturn(checkPermittedCounter);
when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"transaction_smart_contract_check_count_unpermitted",
"Number of times the transaction smart contract permissioning provider has been checked and returned unpermitted"))
.thenReturn(checkUnpermittedCounter);
return new TransactionSmartContractPermissioningController(contractAddress, ts, metricsSystem);
} }
private Transaction transactionForAccount(final Address address) { private Transaction transactionForAccount(final Address address) {
@ -67,6 +100,30 @@ public class TransactionSmartContractPermissioningControllerTest {
.build(); .build();
} }
private void verifyCountersUntouched() {
verify(checkCounter, times(0)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
}
private void verifyCountersPermitted() {
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(1)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
}
private void verifyCountersUnpermitted() {
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(1)).inc();
}
private void verifyCountersFailedCheck() {
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
}
@Test @Test
public void testAccountIncluded() throws IOException { public void testAccountIncluded() throws IOException {
final TransactionSmartContractPermissioningController controller = final TransactionSmartContractPermissioningController controller =
@ -74,8 +131,12 @@ public class TransactionSmartContractPermissioningControllerTest {
"/TransactionSmartContractPermissioningControllerTest/preseededSmartPermissioning.json", "/TransactionSmartContractPermissioningControllerTest/preseededSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThat(controller.isPermitted(transactionForAccount(Address.fromHexString("0x1")))) assertThat(controller.isPermitted(transactionForAccount(Address.fromHexString("0x1"))))
.isTrue(); .isTrue();
verifyCountersPermitted();
} }
@Test @Test
@ -85,8 +146,12 @@ public class TransactionSmartContractPermissioningControllerTest {
"/TransactionSmartContractPermissioningControllerTest/preseededSmartPermissioning.json", "/TransactionSmartContractPermissioningControllerTest/preseededSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThat(controller.isPermitted(transactionForAccount(Address.fromHexString("0x2")))) assertThat(controller.isPermitted(transactionForAccount(Address.fromHexString("0x2"))))
.isFalse(); .isFalse();
verifyCountersUnpermitted();
} }
@Test @Test
@ -96,10 +161,14 @@ public class TransactionSmartContractPermissioningControllerTest {
"/TransactionSmartContractPermissioningControllerTest/noSmartPermissioning.json", "/TransactionSmartContractPermissioningControllerTest/noSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThatThrownBy( assertThatThrownBy(
() -> controller.isPermitted(transactionForAccount(Address.fromHexString("0x1")))) () -> controller.isPermitted(transactionForAccount(Address.fromHexString("0x1"))))
.isInstanceOf(IllegalStateException.class) .isInstanceOf(IllegalStateException.class)
.hasMessage("Transaction permissioning contract does not exist"); .hasMessage("Transaction permissioning contract does not exist");
verifyCountersFailedCheck();
} }
@Test @Test
@ -109,9 +178,13 @@ public class TransactionSmartContractPermissioningControllerTest {
"/TransactionSmartContractPermissioningControllerTest/corruptSmartPermissioning.json", "/TransactionSmartContractPermissioningControllerTest/corruptSmartPermissioning.json",
"0x0000000000000000000000000000000000001234"); "0x0000000000000000000000000000000000001234");
verifyCountersUntouched();
assertThatThrownBy( assertThatThrownBy(
() -> controller.isPermitted(transactionForAccount(Address.fromHexString("0x1")))) () -> controller.isPermitted(transactionForAccount(Address.fromHexString("0x1"))))
.isInstanceOf(IllegalStateException.class) .isInstanceOf(IllegalStateException.class)
.hasMessage("Transaction permissioning transaction failed when processing"); .hasMessage("Transaction permissioning transaction failed when processing");
verifyCountersFailedCheck();
} }
} }

@ -23,6 +23,7 @@ import tech.pegasys.pantheon.ethereum.permissioning.NodeSmartContractPermissioni
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.SmartContractPermissioningConfiguration; import tech.pegasys.pantheon.ethereum.permissioning.SmartContractPermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import tech.pegasys.pantheon.util.enode.EnodeURL; import tech.pegasys.pantheon.util.enode.EnodeURL;
import java.util.Collection; import java.util.Collection;
@ -55,7 +56,12 @@ public class NodePermissioningControllerFactoryTest {
NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory();
NodePermissioningController controller = NodePermissioningController controller =
factory.create( factory.create(
config, synchronizer, bootnodes, selfEnode.getNodeId(), transactionSimulator); config,
synchronizer,
bootnodes,
selfEnode.getNodeId(),
transactionSimulator,
new NoOpMetricsSystem());
List<NodePermissioningProvider> providers = controller.getProviders(); List<NodePermissioningProvider> providers = controller.getProviders();
assertThat(providers.size()).isEqualTo(0); assertThat(providers.size()).isEqualTo(0);
@ -75,7 +81,12 @@ public class NodePermissioningControllerFactoryTest {
NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory();
NodePermissioningController controller = NodePermissioningController controller =
factory.create( factory.create(
config, synchronizer, bootnodes, selfEnode.getNodeId(), transactionSimulator); config,
synchronizer,
bootnodes,
selfEnode.getNodeId(),
transactionSimulator,
new NoOpMetricsSystem());
List<NodePermissioningProvider> providers = controller.getProviders(); List<NodePermissioningProvider> providers = controller.getProviders();
assertThat(providers.size()).isEqualTo(1); assertThat(providers.size()).isEqualTo(1);
@ -96,7 +107,12 @@ public class NodePermissioningControllerFactoryTest {
NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory();
NodePermissioningController controller = NodePermissioningController controller =
factory.create( factory.create(
config, synchronizer, bootnodes, selfEnode.getNodeId(), transactionSimulator); config,
synchronizer,
bootnodes,
selfEnode.getNodeId(),
transactionSimulator,
new NoOpMetricsSystem());
List<NodePermissioningProvider> providers = controller.getProviders(); List<NodePermissioningProvider> providers = controller.getProviders();
assertThat(providers.size()).isEqualTo(1); assertThat(providers.size()).isEqualTo(1);
@ -124,7 +140,12 @@ public class NodePermissioningControllerFactoryTest {
NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory();
NodePermissioningController controller = NodePermissioningController controller =
factory.create( factory.create(
config, synchronizer, bootnodes, selfEnode.getNodeId(), transactionSimulator); config,
synchronizer,
bootnodes,
selfEnode.getNodeId(),
transactionSimulator,
new NoOpMetricsSystem());
List<NodePermissioningProvider> providers = controller.getProviders(); List<NodePermissioningProvider> providers = controller.getProviders();
assertThat(providers.size()).isEqualTo(2); assertThat(providers.size()).isEqualTo(2);
@ -155,7 +176,12 @@ public class NodePermissioningControllerFactoryTest {
NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory(); NodePermissioningControllerFactory factory = new NodePermissioningControllerFactory();
NodePermissioningController controller = NodePermissioningController controller =
factory.create( factory.create(
config, synchronizer, fixedNodes, selfEnode.getNodeId(), transactionSimulator); config,
synchronizer,
fixedNodes,
selfEnode.getNodeId(),
transactionSimulator,
new NoOpMetricsSystem());
assertThat(controller.getSyncStatusNodePermissioningProvider()).isPresent(); assertThat(controller.getSyncStatusNodePermissioningProvider()).isPresent();
} }

@ -14,16 +14,22 @@ package tech.pegasys.pantheon.ethereum.permissioning.node.provider;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.ethereum.core.SyncStatus; import tech.pegasys.pantheon.ethereum.core.SyncStatus;
import tech.pegasys.pantheon.ethereum.core.Synchronizer; import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.Synchronizer.SyncStatusListener; import tech.pegasys.pantheon.ethereum.core.Synchronizer.SyncStatusListener;
import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.enode.EnodeURL; import tech.pegasys.pantheon.util.enode.EnodeURL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.function.Supplier;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -34,6 +40,11 @@ import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class SyncStatusNodePermissioningProviderTest { public class SyncStatusNodePermissioningProviderTest {
@Mock private MetricsSystem metricsSystem;
@Mock private Counter checkCounter;
@Mock private Counter checkPermittedCounter;
@Mock private Counter checkUnpermittedCounter;
private Supplier<Integer> syncGauge;
private static final EnodeURL bootnode = private static final EnodeURL bootnode =
EnodeURL.fromString( EnodeURL.fromString(
@ -58,8 +69,34 @@ public class SyncStatusNodePermissioningProviderTest {
when(synchronizer.observeSyncStatus(captor.capture())).thenReturn(syncStatusObserverId); when(synchronizer.observeSyncStatus(captor.capture())).thenReturn(syncStatusObserverId);
bootnodes.add(bootnode); bootnodes.add(bootnode);
this.provider = new SyncStatusNodePermissioningProvider(synchronizer, bootnodes); @SuppressWarnings("unchecked")
final ArgumentCaptor<Supplier<Integer>> syncGaugeCallbackCaptor =
ArgumentCaptor.forClass(Supplier.class);
when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"sync_status_node_check_count",
"Number of times the sync status permissioning provider has been checked"))
.thenReturn(checkCounter);
when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"sync_status_node_check_count_permitted",
"Number of times the sync status permissioning provider has been checked and returned permitted"))
.thenReturn(checkPermittedCounter);
when(metricsSystem.createCounter(
MetricCategory.PERMISSIONING,
"sync_status_node_check_count_unpermitted",
"Number of times the sync status permissioning provider has been checked and returned unpermitted"))
.thenReturn(checkUnpermittedCounter);
this.provider = new SyncStatusNodePermissioningProvider(synchronizer, bootnodes, metricsSystem);
this.syncStatusListener = captor.getValue(); this.syncStatusListener = captor.getValue();
verify(metricsSystem)
.createIntegerGauge(
eq(MetricCategory.PERMISSIONING),
eq("sync_status_node_sync_reached"),
eq("Whether the sync status permissioning provider has realised sync yet"),
syncGaugeCallbackCaptor.capture());
this.syncGauge = syncGaugeCallbackCaptor.getValue();
verify(synchronizer).observeSyncStatus(any()); verify(synchronizer).observeSyncStatus(any());
} }
@ -69,6 +106,7 @@ public class SyncStatusNodePermissioningProviderTest {
syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2)); syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2));
assertThat(provider.hasReachedSync()).isFalse(); assertThat(provider.hasReachedSync()).isFalse();
assertThat(syncGauge.get()).isEqualTo(0);
} }
@Test @Test
@ -76,57 +114,77 @@ public class SyncStatusNodePermissioningProviderTest {
syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 1)); syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 1));
assertThat(provider.hasReachedSync()).isTrue(); assertThat(provider.hasReachedSync()).isTrue();
assertThat(syncGauge.get()).isEqualTo(1);
} }
@Test @Test
public void whenInSyncChangesFromTrueToFalseHasReachedSyncShouldReturnTrue() { public void whenInSyncChangesFromTrueToFalseHasReachedSyncShouldReturnTrue() {
syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2)); syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2));
assertThat(provider.hasReachedSync()).isFalse(); assertThat(provider.hasReachedSync()).isFalse();
assertThat(syncGauge.get()).isEqualTo(0);
syncStatusListener.onSyncStatus(new SyncStatus(0, 2, 1)); syncStatusListener.onSyncStatus(new SyncStatus(0, 2, 1));
assertThat(provider.hasReachedSync()).isTrue(); assertThat(provider.hasReachedSync()).isTrue();
assertThat(syncGauge.get()).isEqualTo(1);
syncStatusListener.onSyncStatus(new SyncStatus(0, 2, 3)); syncStatusListener.onSyncStatus(new SyncStatus(0, 2, 3));
assertThat(provider.hasReachedSync()).isTrue(); assertThat(provider.hasReachedSync()).isTrue();
assertThat(syncGauge.get()).isEqualTo(1);
} }
@Test @Test
public void whenHasNotSyncedNonBootnodeShouldNotBePermitted() { public void whenHasNotSyncedNonBootnodeShouldNotBePermitted() {
syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2)); syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2));
assertThat(provider.hasReachedSync()).isFalse(); assertThat(provider.hasReachedSync()).isFalse();
assertThat(syncGauge.get()).isEqualTo(0);
boolean isPermitted = provider.isPermitted(enode1, enode2); boolean isPermitted = provider.isPermitted(enode1, enode2);
assertThat(isPermitted).isFalse(); assertThat(isPermitted).isFalse();
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(1)).inc();
} }
@Test @Test
public void whenHasNotSyncedBootnodeIncomingConnectionShouldNotBePermitted() { public void whenHasNotSyncedBootnodeIncomingConnectionShouldNotBePermitted() {
syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2)); syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2));
assertThat(provider.hasReachedSync()).isFalse(); assertThat(provider.hasReachedSync()).isFalse();
assertThat(syncGauge.get()).isEqualTo(0);
boolean isPermitted = provider.isPermitted(bootnode, enode1); boolean isPermitted = provider.isPermitted(bootnode, enode1);
assertThat(isPermitted).isFalse(); assertThat(isPermitted).isFalse();
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(1)).inc();
} }
@Test @Test
public void whenHasNotSyncedBootnodeOutgoingConnectionShouldBePermitted() { public void whenHasNotSyncedBootnodeOutgoingConnectionShouldBePermitted() {
syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2)); syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2));
assertThat(provider.hasReachedSync()).isFalse(); assertThat(provider.hasReachedSync()).isFalse();
assertThat(syncGauge.get()).isEqualTo(0);
boolean isPermitted = provider.isPermitted(enode1, bootnode); boolean isPermitted = provider.isPermitted(enode1, bootnode);
assertThat(isPermitted).isTrue(); assertThat(isPermitted).isTrue();
verify(checkCounter, times(1)).inc();
verify(checkPermittedCounter, times(1)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
} }
@Test @Test
public void whenHasSyncedIsPermittedShouldReturnTrue() { public void whenHasSyncedIsPermittedShouldReturnTrue() {
syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 1)); syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 1));
assertThat(provider.hasReachedSync()).isTrue(); assertThat(provider.hasReachedSync()).isTrue();
assertThat(syncGauge.get()).isEqualTo(1);
boolean isPermitted = provider.isPermitted(enode1, enode2); boolean isPermitted = provider.isPermitted(enode1, enode2);
assertThat(isPermitted).isTrue(); assertThat(isPermitted).isTrue();
verify(checkCounter, times(0)).inc();
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
} }
} }

@ -23,6 +23,7 @@ public enum MetricCategory {
NETWORK("network"), NETWORK("network"),
PEERS("peers"), PEERS("peers"),
PROCESS("process", false), PROCESS("process", false),
PERMISSIONING("permissioning"),
KVSTORE_ROCKSDB("rocksdb"), KVSTORE_ROCKSDB("rocksdb"),
KVSTORE_ROCKSDB_STATS("rocksdb", false), KVSTORE_ROCKSDB_STATS("rocksdb", false),
RPC("rpc"), RPC("rpc"),

@ -427,7 +427,13 @@ public class RunnerBuilder {
return permissioningConfiguration.map( return permissioningConfiguration.map(
config -> config ->
new NodePermissioningControllerFactory() new NodePermissioningControllerFactory()
.create(config, synchronizer, fixedNodes, localNodeId, transactionSimulator)); .create(
config,
synchronizer,
fixedNodes,
localNodeId,
transactionSimulator,
metricsSystem));
} }
@VisibleForTesting @VisibleForTesting

Loading…
Cancel
Save