diff --git a/acceptance-tests/build.gradle b/acceptance-tests/build.gradle index c04a753065..4bb3ccfec4 100644 --- a/acceptance-tests/build.gradle +++ b/acceptance-tests/build.gradle @@ -16,14 +16,15 @@ dependencies { testRuntime 'org.apache.logging.log4j:log4j-core' testRuntime 'org.apache.logging.log4j:log4j-slf4j-impl' + testImplementation project(':config') + testImplementation project(':consensus:clique') testImplementation project(':crypto') testImplementation project(':ethereum:eth') testImplementation project(':ethereum:core') testImplementation project(':ethereum:blockcreation') testImplementation project(':ethereum:jsonrpc') + testImplementation project(':metrics') testImplementation project(':pantheon') - testImplementation project(':config') - testImplementation project(':consensus:clique') testImplementation project(':util') testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java index fe892293d2..81d66cbd32 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java @@ -21,6 +21,8 @@ import tech.pegasys.pantheon.cli.PantheonControllerBuilder; import tech.pegasys.pantheon.controller.KeyPairUtil; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import java.io.IOException; import java.util.Collections; @@ -48,6 +50,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { nodeExecutor = Executors.newCachedThreadPool(); } + final MetricsSystem noOpMetricsSystem = new NoOpMetricsSystem(); final PantheonControllerBuilder builder = new PantheonControllerBuilder(); final EthNetworkConfig ethNetworkConfig = node.ethNetworkConfig() @@ -63,6 +66,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { .miningParameters(node.getMiningParameters()) .devMode(node.isDevMode()) .nodePrivateKeyFile(KeyPairUtil.getDefaultKeyFile(node.homeDirectory())) + .metricsSystem(noOpMetricsSystem) .build(); } catch (final IOException e) { throw new RuntimeException("Error building PantheonController", e); @@ -81,6 +85,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { .webSocketConfiguration(node.webSocketConfiguration()) .dataDir(node.homeDirectory()) .bannedNodeIds(Collections.emptySet()) + .metricsSystem(noOpMetricsSystem) .build(); nodeExecutor.submit(runner::execute); diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 90c123a6bb..1a3c5f2071 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -30,6 +30,7 @@ dependencies { implementation project(':crypto') implementation project(':ethereum:rlp') implementation project(':ethereum:trie') + implementation project(':metrics') implementation project(':services:kvstore') implementation 'com.fasterxml.jackson.core:jackson-databind' diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java index 03e2fad824..308e95b19f 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java @@ -29,6 +29,8 @@ import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; +import tech.pegasys.pantheon.metrics.MetricCategory; +import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.uint.UInt256; @@ -51,10 +53,23 @@ public class DefaultMutableBlockchain implements MutableBlockchain { private final Subscribers blockAddedObservers = new Subscribers<>(); public DefaultMutableBlockchain( - final Block genesisBlock, final BlockchainStorage blockchainStorage) { + final Block genesisBlock, + final BlockchainStorage blockchainStorage, + final MetricsSystem metricsSystem) { checkNotNull(genesisBlock); this.blockchainStorage = blockchainStorage; this.setGenesis(genesisBlock); + + metricsSystem.createGauge( + MetricCategory.BLOCKCHAIN, + "height", + "Height of the chainhead", + () -> (double) this.getChainHeadBlockNumber()); + metricsSystem.createGauge( + MetricCategory.BLOCKCHAIN, + "difficulty_total", + "Total difficulty of the chainhead", + () -> (double) this.getChainHead().getTotalDifficulty().toLong()); } @Override diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java index 6f33efd5c4..3d9bfa96df 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStorageWorldStateStorage; import tech.pegasys.pantheon.ethereum.worldstate.DefaultMutableWorldState; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; @@ -50,7 +51,8 @@ public class ExecutionContextTestFixture { new DefaultMutableBlockchain( genesis, new KeyValueStoragePrefixedKeyBlockchainStorage( - keyValueStorage, MainnetBlockHashFunction::createHash)); + keyValueStorage, MainnetBlockHashFunction::createHash), + new NoOpMetricsSystem()); this.stateArchive = new WorldStateArchive(new KeyValueStorageWorldStateStorage(keyValueStorage)); this.protocolSchedule = protocolSchedule; diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java index b2e56e38a5..6621f287d6 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java @@ -23,6 +23,7 @@ import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStorageWorldStateStorage; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; public class InMemoryStorageProvider implements StorageProvider { @@ -36,7 +37,8 @@ public class InMemoryStorageProvider implements StorageProvider { final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage(); return new DefaultMutableBlockchain( genesisBlock, - new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHashFunction)); + new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHashFunction), + new NoOpMetricsSystem()); } public static WorldStateArchive createInMemoryWorldStateArchive() { diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchainTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchainTest.java index 9cd6cdac40..d90cd863cc 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchainTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchainTest.java @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator.BlockOptions; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; import tech.pegasys.pantheon.util.uint.UInt256; @@ -713,6 +714,7 @@ public class DefaultMutableBlockchainTest { return new DefaultMutableBlockchain( genesisBlock, new KeyValueStoragePrefixedKeyBlockchainStorage( - kvStore, MainnetBlockHashFunction::createHash)); + kvStore, MainnetBlockHashFunction::createHash), + new NoOpMetricsSystem()); } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java index c610596c34..bb03ca0147 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.core.LogsBloomFilter; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; import tech.pegasys.pantheon.util.bytes.Bytes32; @@ -73,7 +74,8 @@ public class GenesisBlockMismatchTest { new DefaultMutableBlockchain( genesisBlock00, new KeyValueStoragePrefixedKeyBlockchainStorage( - kvStore, MainnetBlockHashFunction::createHash)); + kvStore, MainnetBlockHashFunction::createHash), + new NoOpMetricsSystem()); final BlockHeader genesisHeader01 = BlockHeaderBuilder.create() diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java index b3fa3022ce..4af2ca3f62 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java @@ -34,6 +34,9 @@ import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason; import tech.pegasys.pantheon.ethereum.rlp.RLPException; +import tech.pegasys.pantheon.metrics.MetricCategory; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.OperationTimer; import tech.pegasys.pantheon.util.uint.UInt256; import java.util.ArrayList; @@ -64,6 +67,7 @@ public class BlockPropagationManager { private final Set requestedBlocks = new ConcurrentSet<>(); private final PendingBlocks pendingBlocks; + private final OperationTimer announcedBlockIngestTimer; BlockPropagationManager( final SynchronizerConfiguration config, @@ -71,7 +75,8 @@ public class BlockPropagationManager { final ProtocolContext protocolContext, final EthContext ethContext, final SyncState syncState, - final PendingBlocks pendingBlocks) { + final PendingBlocks pendingBlocks, + final MetricsSystem metricsSystem) { this.config = config; this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; @@ -79,6 +84,12 @@ public class BlockPropagationManager { this.syncState = syncState; this.pendingBlocks = pendingBlocks; + + this.announcedBlockIngestTimer = + metricsSystem.createTimer( + MetricCategory.BLOCKCHAIN, + "pantheon_blockchain_announcedBlock_ingest", + "Time to ingest a single announced block"); } public void start() { @@ -241,21 +252,24 @@ public class BlockPropagationManager { final PersistBlockTask importTask = PersistBlockTask.create( protocolSchedule, protocolContext, block, HeaderValidationMode.FULL); + final OperationTimer.TimingContext blockTimer = announcedBlockIngestTimer.startTimer(); return ethContext .getScheduler() .scheduleWorkerTask(importTask::run) .whenComplete( (r, t) -> { if (t != null) { + // TODO do we time failures? But we cannot drop a label in at this point. LOG.warn( "Failed to import announced block {} ({}).", block.getHeader().getNumber(), block.getHash()); } else { + final double timeInMs = blockTimer.stopTimer() * 1000; LOG.info( - "Successfully imported announced block {} ({}).", - block.getHeader().getNumber(), - block.getHash()); + String.format( + "Successfully imported announced block %d (%s) in %01.3fms.", + block.getHeader().getNumber(), block.getHash(), timeInMs)); } }); } diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java index 3a1f40f755..20fcb3fafd 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java @@ -19,6 +19,7 @@ import tech.pegasys.pantheon.ethereum.eth.manager.EthContext; import tech.pegasys.pantheon.ethereum.eth.sync.state.PendingBlocks; import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; @@ -40,7 +41,8 @@ public class DefaultSynchronizer implements Synchronizer { final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, - final SyncState syncState) { + final SyncState syncState, + final MetricsSystem metricsSystem) { this.syncState = syncState; this.blockPropagationManager = new BlockPropagationManager<>( @@ -49,7 +51,8 @@ public class DefaultSynchronizer implements Synchronizer { protocolContext, ethContext, syncState, - new PendingBlocks()); + new PendingBlocks(), + metricsSystem); this.downloader = new Downloader<>(syncConfig, protocolSchedule, protocolContext, ethContext, syncState); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java index 9d51def6ba..da051d3c96 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java @@ -35,6 +35,8 @@ import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator.BlockOptions; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.util.uint.UInt256; import java.util.Collections; @@ -56,6 +58,7 @@ public class BlockPropagationManagerTest { private SynchronizerConfiguration syncConfig; private final PendingBlocks pendingBlocks = new PendingBlocks(); private SyncState syncState; + private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); @BeforeClass public static void setupSuite() { @@ -87,7 +90,8 @@ public class BlockPropagationManagerTest { protocolContext, ethProtocolManager.ethContext(), syncState, - pendingBlocks); + pendingBlocks, + metricsSystem); } @Test @@ -462,7 +466,8 @@ public class BlockPropagationManagerTest { protocolContext, ethProtocolManager.ethContext(), syncState, - pendingBlocks); + pendingBlocks, + metricsSystem); final BlockDataGenerator gen = new BlockDataGenerator(); // Import some blocks diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java index 12d78a4ca9..5ce28f38fb 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java @@ -295,7 +295,7 @@ public class PeerDiscoveryAgentTest extends AbstractPeerDiscoveryTest { @Test public void shouldBeActiveWhenConfigIsTrue() { final DiscoveryConfiguration config = new DiscoveryConfiguration(); - config.setActive(true); + config.setActive(true).setBindPort(0); final PeerDiscoveryAgent agent = startDiscoveryAgent(config, new PeerBlacklist()); @@ -305,7 +305,7 @@ public class PeerDiscoveryAgentTest extends AbstractPeerDiscoveryTest { @Test public void shouldNotBeActiveWhenConfigIsFalse() { final DiscoveryConfiguration config = new DiscoveryConfiguration(); - config.setActive(false); + config.setActive(false).setBindPort(0); final PeerDiscoveryAgent agent = startDiscoveryAgent(config, new PeerBlacklist()); diff --git a/metrics/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java b/metrics/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java index 8798501b25..d1b12e40f3 100644 --- a/metrics/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java +++ b/metrics/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java @@ -16,7 +16,8 @@ public enum MetricCategory { PEERS("peers"), RPC("rpc"), JVM("jvm", false), - PROCESS("process", false); + PROCESS("process", false), + BLOCKCHAIN("blockchain"); private final String name; private final boolean pantheonSpecific; diff --git a/metrics/src/main/java/tech/pegasys/pantheon/metrics/OperationTimer.java b/metrics/src/main/java/tech/pegasys/pantheon/metrics/OperationTimer.java index e16bc15dca..e5d13d237e 100644 --- a/metrics/src/main/java/tech/pegasys/pantheon/metrics/OperationTimer.java +++ b/metrics/src/main/java/tech/pegasys/pantheon/metrics/OperationTimer.java @@ -19,7 +19,8 @@ public interface OperationTimer { TimingContext startTimer(); interface TimingContext extends Closeable { - void stopTimer(); + /** @return Elapsed time in seconds. */ + double stopTimer(); @Override default void close() { diff --git a/metrics/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java b/metrics/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java index 090c98058c..9b0f43d9a7 100644 --- a/metrics/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java +++ b/metrics/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java @@ -26,7 +26,7 @@ import java.util.stream.Stream; public class NoOpMetricsSystem implements MetricsSystem { private static final Counter NO_OP_COUNTER = new NoOpCounter(); - private static final TimingContext NO_OP_TIMING_CONTEXT = () -> {}; + private static final TimingContext NO_OP_TIMING_CONTEXT = () -> 0; private static final OperationTimer NO_OP_TIMER = () -> NO_OP_TIMING_CONTEXT; @Override diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java index a3f8cccbf7..977eba9c68 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java @@ -53,7 +53,6 @@ import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.metrics.MetricsSystem; -import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.nio.file.Path; @@ -80,6 +79,7 @@ public class RunnerBuilder { private WebSocketConfiguration webSocketConfiguration; private Path dataDir; private Collection bannedNodeIds; + private MetricsSystem metricsSystem; private PermissioningConfiguration permissioningConfiguration; public RunnerBuilder vertx(final Vertx vertx) { @@ -143,11 +143,15 @@ public class RunnerBuilder { return this; } + public RunnerBuilder metricsSystem(final MetricsSystem metricsSystem) { + this.metricsSystem = metricsSystem; + return this; + } + public Runner build() { Preconditions.checkNotNull(pantheonController); - final MetricsSystem metricsSystem = PrometheusMetricsSystem.init(); final DiscoveryConfiguration discoveryConfiguration; if (discovery) { final Collection bootstrap; diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java index cda7fdbc64..8347b5961c 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -36,6 +36,8 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration; import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem; import tech.pegasys.pantheon.util.BlockImporter; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -120,6 +122,8 @@ public class PantheonCommand implements DefaultCommandValues, Runnable { private final Builder synchronizerConfigurationBuilder; private final RunnerBuilder runnerBuilder; + private final MetricsSystem metricsSystem = PrometheusMetricsSystem.init(); + // Public IP stored to prevent having to research it each time we need it. private InetAddress autoDiscoveredDefaultIP = null; @@ -446,6 +450,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable { new MiningParameters(coinbase, minTransactionGasPrice, extraData, isMiningEnabled)) .devMode(isDevMode) .nodePrivateKeyFile(getNodePrivateKeyFile()) + .metricsSystem(metricsSystem) .build(); } catch (final InvalidConfigurationException e) { throw new ExecutionException(new CommandLine(this), e.getMessage()); @@ -520,6 +525,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable { .webSocketConfiguration(webSocketConfiguration) .dataDir(dataDir()) .bannedNodeIds(bannedNodeIds) + .metricsSystem(metricsSystem) .permissioningConfiguration(permissioningConfiguration) .build(); diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java index b429842445..01505223da 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java @@ -24,6 +24,7 @@ import tech.pegasys.pantheon.ethereum.development.DevelopmentProtocolSchedule; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.storage.keyvalue.RocksDbStorageProvider; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.io.File; import java.io.IOException; @@ -38,6 +39,7 @@ public class PantheonControllerBuilder { private MiningParameters miningParameters; private boolean devMode; private File nodePrivateKeyFile; + private MetricsSystem metricsSystem; public PantheonControllerBuilder synchronizerConfiguration( final SynchronizerConfiguration synchronizerConfiguration) { @@ -75,6 +77,11 @@ public class PantheonControllerBuilder { return this; } + public PantheonControllerBuilder metricsSystem(final MetricsSystem metricsSystem) { + this.metricsSystem = metricsSystem; + return this; + } + public PantheonController build() throws IOException { // instantiate a controller with mainnet config if no genesis file is defined // otherwise use the indicated genesis file @@ -90,7 +97,8 @@ public class PantheonControllerBuilder { DevelopmentProtocolSchedule.create(genesisConfig.getConfigOptions()), synchronizerConfiguration, miningParameters, - nodeKeys); + nodeKeys, + metricsSystem); } else { final String genesisConfig = ethNetworkConfig.getGenesisConfig(); final GenesisConfigFile genesisConfigFile = GenesisConfigFile.fromConfig(genesisConfig); @@ -101,7 +109,8 @@ public class PantheonControllerBuilder { syncWithOttoman, ethNetworkConfig.getNetworkId(), miningParameters, - nodeKeys); + nodeKeys, + metricsSystem); } } } diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java index c2bd2558c3..28c44cbf9e 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java @@ -54,6 +54,7 @@ import tech.pegasys.pantheon.ethereum.p2p.api.ProtocolManager; import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.io.IOException; import java.time.Clock; @@ -104,7 +105,8 @@ public class CliquePantheonController implements PantheonController init( @@ -101,14 +105,15 @@ public class IbftLegacyPantheonController implements PantheonController protocolSchedule = IbftProtocolSchedule.create(genesisConfig.getConfigOptions()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); final BlockchainStorage blockchainStorage = storageProvider.createBlockchainStorage(protocolSchedule); final MutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage); + new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage, metricsSystem); final WorldStateStorage worldStateStorage = storageProvider.createWorldStateStorage(); final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); @@ -159,7 +164,8 @@ public class IbftLegacyPantheonController implements PantheonController { @@ -183,7 +189,8 @@ public class IbftLegacyPantheonController implements PantheonController { final SynchronizerConfiguration taintedSyncConfig, final MiningParameters miningParams, final int networkId, - final KeyPair nodeKeys) { + final KeyPair nodeKeys, + final MetricsSystem metricsSystem) { final ProtocolSchedule protocolSchedule = IbftProtocolSchedule.create(genesisConfig.getConfigOptions()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); final BlockchainStorage blockchainStorage = storageProvider.createBlockchainStorage(protocolSchedule); final MutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage); + new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage, metricsSystem); final WorldStateStorage worldStateStorage = storageProvider.createWorldStateStorage(); final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); @@ -160,7 +162,8 @@ public class IbftPantheonController implements PantheonController { protocolSchedule, protocolContext, ethProtocolManager.ethContext(), - syncState); + syncState, + metricsSystem); final TransactionPool transactionPool = TransactionPoolFactory.createTransactionPool( diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java index fcc4353608..90e135620d 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java @@ -41,6 +41,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.p2p.api.ProtocolManager; import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.io.IOException; import java.time.Clock; @@ -90,13 +91,14 @@ public class MainnetPantheonController implements PantheonController { final ProtocolSchedule protocolSchedule, final SynchronizerConfiguration taintedSyncConfig, final MiningParameters miningParams, - final KeyPair nodeKeys) { + final KeyPair nodeKeys, + final MetricsSystem metricsSystem) { final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); final BlockchainStorage blockchainStorage = storageProvider.createBlockchainStorage(protocolSchedule); final MutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage); + new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage, metricsSystem); final WorldStateArchive worldStateArchive = new WorldStateArchive(storageProvider.createWorldStateStorage()); @@ -125,7 +127,8 @@ public class MainnetPantheonController implements PantheonController { protocolSchedule, protocolContext, ethProtocolManager.ethContext(), - syncState); + syncState, + metricsSystem); final TransactionPool transactionPool = TransactionPoolFactory.createTransactionPool( diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java index af57b872ed..c4d229e205 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java @@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.io.Closeable; import java.util.Collection; @@ -45,7 +46,8 @@ public interface PantheonController extends Closeable { final boolean ottomanTestnetOperation, final int networkId, final MiningParameters miningParameters, - final KeyPair nodeKeys) { + final KeyPair nodeKeys, + final MetricsSystem metricsSystem) { final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions(); @@ -56,10 +58,17 @@ public interface PantheonController extends Closeable { MainnetProtocolSchedule.fromConfig(configOptions), syncConfig, miningParameters, - nodeKeys); + nodeKeys, + metricsSystem); } else if (configOptions.isRevisedIbft()) { return IbftPantheonController.init( - storageProvider, genesisConfigFile, syncConfig, miningParameters, networkId, nodeKeys); + storageProvider, + genesisConfigFile, + syncConfig, + miningParameters, + networkId, + nodeKeys, + metricsSystem); } else if (configOptions.isIbft()) { return IbftLegacyPantheonController.init( storageProvider, @@ -67,10 +76,17 @@ public interface PantheonController extends Closeable { syncConfig, ottomanTestnetOperation, networkId, - nodeKeys); + nodeKeys, + metricsSystem); } else if (configOptions.isClique()) { return CliquePantheonController.init( - storageProvider, genesisConfigFile, syncConfig, miningParameters, networkId, nodeKeys); + storageProvider, + genesisConfigFile, + syncConfig, + miningParameters, + networkId, + nodeKeys, + metricsSystem); } else { throw new IllegalArgumentException("Unknown consensus mechanism defined"); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java index 166f0e24f6..add7efdb05 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java @@ -37,6 +37,8 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.storage.keyvalue.RocksDbStorageProvider; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.util.uint.UInt256; import java.io.IOException; @@ -93,6 +95,7 @@ public final class RunnerTest { // .fastSyncPivotDistance(blockCount / 2).build(); .fastSyncPivotDistance(0) .build(); + final MetricsSystem noOpMetricsSystem = new NoOpMetricsSystem(); // Setup state with block data try (final PantheonController controller = @@ -102,7 +105,8 @@ public final class RunnerTest { MainnetProtocolSchedule.create(), fastSyncConfig, new MiningParametersTestBuilder().enabled(false).build(), - aheadDbNodeKeys)) { + aheadDbNodeKeys, + noOpMetricsSystem)) { setupState(blockCount, controller.getProtocolSchedule(), controller.getProtocolContext()); } @@ -114,7 +118,8 @@ public final class RunnerTest { MainnetProtocolSchedule.create(), fastSyncConfig, new MiningParametersTestBuilder().enabled(false).build(), - aheadDbNodeKeys); + aheadDbNodeKeys, + noOpMetricsSystem); final String listenHost = InetAddress.getLoopbackAddress().getHostAddress(); final ExecutorService executorService = Executors.newFixedThreadPool(2); final JsonRpcConfiguration aheadJsonRpcConfiguration = jsonRpcConfiguration(); @@ -127,6 +132,7 @@ public final class RunnerTest { .discoveryHost(listenHost) .discoveryPort(0) .maxPeers(3) + .metricsSystem(noOpMetricsSystem) .bannedNodeIds(Collections.emptySet()); final Runner runnerAhead = @@ -152,7 +158,8 @@ public final class RunnerTest { MainnetProtocolSchedule.create(), fastSyncConfig, new MiningParametersTestBuilder().enabled(false).build(), - KeyPair.generate()); + KeyPair.generate(), + noOpMetricsSystem); final Runner runnerBehind = runnerBuilder .pantheonController(controllerBehind) @@ -166,6 +173,7 @@ public final class RunnerTest { .jsonRpcConfiguration(behindJsonRpcConfiguration) .webSocketConfiguration(behindWebSocketConfiguration) .dataDir(temp.newFolder().toPath()) + .metricsSystem(noOpMetricsSystem) .build(); executorService.submit(runnerBehind::execute); diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java index b8a668eafd..d477ce1029 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java @@ -85,6 +85,7 @@ public abstract class CommandTestAbstract { when(mockControllerBuilder.miningParameters(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.devMode(anyBoolean())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.nodePrivateKeyFile(any())).thenReturn(mockControllerBuilder); + when(mockControllerBuilder.metricsSystem(any())).thenReturn(mockControllerBuilder); when(mockSyncConfBuilder.build()).thenReturn(mockSyncConf); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java index 4993ec775f..8f96e0da85 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java @@ -102,6 +102,7 @@ public class PantheonCommandTest extends CommandTestAbstract { when(mockRunnerBuilder.permissioningConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.dataDir(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.bannedNodeIds(any())).thenReturn(mockRunnerBuilder); + when(mockRunnerBuilder.metricsSystem(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.build()).thenReturn(mockRunner); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java index 32344c044c..d06b86bb88 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java @@ -21,6 +21,7 @@ import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider; import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.testutil.BlockTestUtil; import tech.pegasys.pantheon.util.uint.UInt256; @@ -53,7 +54,8 @@ public final class BlockImporterTest { false, 1, new MiningParametersTestBuilder().enabled(false).build(), - KeyPair.generate()); + KeyPair.generate(), + new NoOpMetricsSystem()); final BlockImporter.ImportResult result = blockImporter.importBlockchain(source, targetController); assertThat(result.count).isEqualTo(1000); @@ -83,7 +85,8 @@ public final class BlockImporterTest { false, 10, new MiningParametersTestBuilder().enabled(false).build(), - KeyPair.generate()); + KeyPair.generate(), + new NoOpMetricsSystem()); final BlockImporter.ImportResult result = blockImporter.importBlockchain(source, controller); assertThat(result.count).isEqualTo(959);