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 c74bc1433ca..7ae98894376 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 @@ -63,14 +63,16 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { private final Map pantheonPluginContextMap = new HashMap<>(); - private PantheonPluginContextImpl buildPluginContext(final PantheonNode node) { - PantheonPluginContextImpl pantheonPluginContext = new PantheonPluginContextImpl(); + private PantheonPluginContextImpl buildPluginContext( + final PantheonNode node, final CommandLine commandLine) { + final PantheonPluginContextImpl pantheonPluginContext = new PantheonPluginContextImpl(); final Path pluginsPath = node.homeDirectory().resolve("plugins"); final File pluginsDirFile = pluginsPath.toFile(); if (!pluginsDirFile.isDirectory()) { pluginsDirFile.mkdirs(); pluginsDirFile.deleteOnExit(); } + pantheonPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine)); System.setProperty("pantheon.plugins.dir", pluginsPath.toString()); pantheonPluginContext.registerPlugins(pluginsPath); return pantheonPluginContext; @@ -85,8 +87,7 @@ public void startNode(final PantheonNode node) { final CommandLine commandLine = new CommandLine(CommandSpec.create()); final PantheonPluginContextImpl pantheonPluginContext = - pantheonPluginContextMap.computeIfAbsent(node, n -> buildPluginContext(node)); - pantheonPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine)); + pantheonPluginContextMap.computeIfAbsent(node, n -> buildPluginContext(node, commandLine)); commandLine.parseArgs(node.getConfiguration().getExtraCLIOptions().toArray(new String[0])); @@ -126,7 +127,7 @@ public void startNode(final PantheonNode node) { final RunnerBuilder runnerBuilder = new RunnerBuilder(); if (node.getPermissioningConfiguration().isPresent()) { - PermissioningConfiguration permissioningConfiguration = + final PermissioningConfiguration permissioningConfiguration = node.getPermissioningConfiguration().get(); runnerBuilder.permissioningConfiguration(permissioningConfiguration); @@ -151,6 +152,7 @@ public void startNode(final PantheonNode node) { .webSocketConfiguration(node.webSocketConfiguration()) .dataDir(node.homeDirectory()) .metricsSystem(noOpMetricsSystem) + .clock(Clock.systemUTC()) .metricsConfiguration(node.metricsConfiguration()) .p2pEnabled(node.isP2pEnabled()) .graphQLConfiguration(GraphQLConfiguration.createDefault()) @@ -167,7 +169,7 @@ public void startNode(final PantheonNode node) { @Override public void stopNode(final PantheonNode node) { - PantheonPluginContextImpl pluginContext = pantheonPluginContextMap.remove(node); + final PantheonPluginContextImpl pluginContext = pantheonPluginContextMap.remove(node); if (pluginContext != null) { pluginContext.stopPlugins(); } diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/BlockHeaderValidationRulesetFactory.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/BlockHeaderValidationRulesetFactory.java index cdb7867a5bb..bb3005ff1e3 100644 --- a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/BlockHeaderValidationRulesetFactory.java +++ b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/BlockHeaderValidationRulesetFactory.java @@ -28,6 +28,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter; import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent; +import java.time.Clock; + public class BlockHeaderValidationRulesetFactory { /** @@ -38,16 +40,17 @@ public class BlockHeaderValidationRulesetFactory { * * @param secondsBetweenBlocks the minimum number of seconds which must elapse between blocks. * @param epochManager an object which determines if a given block is an epoch block. + * @param clock System clock * @return the header validator. */ public static BlockHeaderValidator cliqueBlockHeaderValidator( - final long secondsBetweenBlocks, final EpochManager epochManager) { + final long secondsBetweenBlocks, final EpochManager epochManager, final Clock clock) { return new BlockHeaderValidator.Builder() .addRule(new AncestryValidationRule()) .addRule(new GasUsageValidationRule()) .addRule(new GasLimitRangeAndDeltaValidationRule(5000, 0x7fffffffffffffffL)) - .addRule(new TimestampBoundedByFutureParameter(10)) + .addRule(new TimestampBoundedByFutureParameter(10, clock)) .addRule(new TimestampMoreRecentThanParent(secondsBetweenBlocks)) .addRule(new ConstantFieldValidationRule<>("MixHash", BlockHeader::getMixHash, Hash.ZERO)) .addRule( diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java index dfc98d684e0..d96246f1088 100644 --- a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java +++ b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java @@ -30,6 +30,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpecBuilder; import java.math.BigInteger; +import java.time.Clock; /** Defines the protocol behaviours for a blockchain using Clique. */ public class CliqueProtocolSchedule { @@ -40,7 +41,8 @@ public static ProtocolSchedule create( final GenesisConfigOptions config, final KeyPair nodeKeys, final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled) { + final boolean isRevertReasonEnabled, + final Clock clock) { final CliqueConfigOptions cliqueConfig = config.getCliqueConfigOptions(); @@ -52,28 +54,37 @@ public static ProtocolSchedule create( DEFAULT_CHAIN_ID, builder -> applyCliqueSpecificModifications( - epochManager, cliqueConfig.getBlockPeriodSeconds(), localNodeAddress, builder), + epochManager, + cliqueConfig.getBlockPeriodSeconds(), + localNodeAddress, + builder, + clock), privacyParameters, - isRevertReasonEnabled) + isRevertReasonEnabled, + clock) .createProtocolSchedule(); } public static ProtocolSchedule create( final GenesisConfigOptions config, final KeyPair nodeKeys, - final boolean isRevertReasonEnabled) { - return create(config, nodeKeys, PrivacyParameters.DEFAULT, isRevertReasonEnabled); + final boolean isRevertReasonEnabled, + final Clock clock) { + return create(config, nodeKeys, PrivacyParameters.DEFAULT, isRevertReasonEnabled, clock); } private static ProtocolSpecBuilder applyCliqueSpecificModifications( final EpochManager epochManager, final long secondsBetweenBlocks, final Address localNodeAddress, - final ProtocolSpecBuilder specBuilder) { + final ProtocolSpecBuilder specBuilder, + final Clock clock) { return specBuilder .changeConsensusContextType( - difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager), - difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager), + difficultyCalculator -> + cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager, clock), + difficultyCalculator -> + cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager, clock), MainnetBlockBodyValidator::new, MainnetBlockValidator::new, MainnetBlockImporter::new, diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java index cccaca84274..1412398e679 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java @@ -20,6 +20,7 @@ import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; +import tech.pegasys.pantheon.testutil.TestClock; import org.junit.Test; @@ -41,7 +42,7 @@ public void protocolSpecsAreCreatedAtBlockDefinedInJson() { final GenesisConfigOptions config = GenesisConfigFile.fromConfig(jsonInput).getConfigOptions(); final ProtocolSchedule protocolSchedule = - CliqueProtocolSchedule.create(config, NODE_KEYS, false); + CliqueProtocolSchedule.create(config, NODE_KEYS, false, TestClock.fixed()); final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockNumber(1); final ProtocolSpec tangerineWhistleSpec = protocolSchedule.getByBlockNumber(2); @@ -57,7 +58,7 @@ public void protocolSpecsAreCreatedAtBlockDefinedInJson() { public void parametersAlignWithMainnetWithAdjustments() { final ProtocolSpec homestead = CliqueProtocolSchedule.create( - GenesisConfigFile.DEFAULT.getConfigOptions(), NODE_KEYS, false) + GenesisConfigFile.DEFAULT.getConfigOptions(), NODE_KEYS, false, TestClock.fixed()) .getByBlockNumber(0); assertThat(homestead.getName()).isEqualTo("Frontier"); diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java index fbc7133bb75..473cb90d79e 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java @@ -76,7 +76,10 @@ public class CliqueBlockCreatorTest { public void setup() { protocolSchedule = CliqueProtocolSchedule.create( - GenesisConfigFile.DEFAULT.getConfigOptions(), proposerKeyPair, false); + GenesisConfigFile.DEFAULT.getConfigOptions(), + proposerKeyPair, + false, + TestClock.fixed()); final Address otherAddress = Util.publicKeyToAddress(otherKeyPair.getPublicKey()); validatorList.add(otherAddress); diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index 19012ab83cb..116c9fe99b1 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -90,7 +90,8 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() { new CliqueMinerExecutor( cliqueProtocolContext, Executors.newSingleThreadExecutor(), - CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair, false), + CliqueProtocolSchedule.create( + GENESIS_CONFIG_OPTIONS, proposerKeyPair, false, TestClock.fixed()), new PendingTransactions( TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS, 1, @@ -127,7 +128,8 @@ public void extraDataForNonEpochBlocksDoesNotContainValidaors() { new CliqueMinerExecutor( cliqueProtocolContext, Executors.newSingleThreadExecutor(), - CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair, false), + CliqueProtocolSchedule.create( + GENESIS_CONFIG_OPTIONS, proposerKeyPair, false, TestClock.fixed()), new PendingTransactions( TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS, 1, @@ -164,7 +166,8 @@ public void shouldUseLatestVanityData() { new CliqueMinerExecutor( cliqueProtocolContext, Executors.newSingleThreadExecutor(), - CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair, false), + CliqueProtocolSchedule.create( + GENESIS_CONFIG_OPTIONS, proposerKeyPair, false, TestClock.fixed()), new PendingTransactions( TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS, 1, diff --git a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java index a5a0d58b4da..bdeef803339 100644 --- a/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/tech/pegasys/pantheon/consensus/ibft/support/TestContextBuilder.java @@ -12,6 +12,7 @@ */ package tech.pegasys.pantheon.consensus.ibft.support; +import static com.google.common.base.Preconditions.checkNotNull; import static java.nio.charset.StandardCharsets.UTF_8; import static org.mockito.Mockito.mock; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain; @@ -159,6 +160,8 @@ public TestContextBuilder useGossip(final boolean useGossip) { } public TestContext build() { + checkNotNull(clock); + final NetworkLayout networkNodes = NetworkLayout.createNetworkLayout(validatorCount, indexOfFirstLocallyProposedBlock); @@ -263,7 +266,7 @@ private static ControllerAndState createControllerAndFinalState( genesisConfigOptions.byzantiumBlock(0); final ProtocolSchedule protocolSchedule = - IbftProtocolSchedule.create(genesisConfigOptions); + IbftProtocolSchedule.create(genesisConfigOptions, Clock.systemUTC()); ///////////////////////////////////////////////////////////////////////////////////// // From here down is BASICALLY taken from IbftPantheonController diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java index c45f8168e0a..a866c94ae95 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactory.java @@ -26,6 +26,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent; import tech.pegasys.pantheon.util.uint.UInt256; +import java.time.Clock; + public class IbftBlockHeaderValidationRulesetFactory { /** @@ -33,15 +35,16 @@ public class IbftBlockHeaderValidationRulesetFactory { * part of the BlockChain (i.e. not proposed blocks, which do not contain commit seals) * * @param secondsBetweenBlocks the minimum number of seconds which must elapse between blocks. + * @param clock System clock * @return BlockHeaderValidator configured for assessing ibft block headers */ public static BlockHeaderValidator ibftBlockHeaderValidator( - final long secondsBetweenBlocks) { + final long secondsBetweenBlocks, final Clock clock) { return new BlockHeaderValidator.Builder() .addRule(new AncestryValidationRule()) .addRule(new GasUsageValidationRule()) .addRule(new GasLimitRangeAndDeltaValidationRule(5000, 0x7fffffffffffffffL)) - .addRule(new TimestampBoundedByFutureParameter(1)) + .addRule(new TimestampBoundedByFutureParameter(1, clock)) .addRule(new TimestampMoreRecentThanParent(secondsBetweenBlocks)) .addRule( new ConstantFieldValidationRule<>( diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java index d9526928d2d..5ec3f885e88 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java @@ -26,6 +26,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpecBuilder; import java.math.BigInteger; +import java.time.Clock; /** Defines the protocol behaviours for a blockchain using IBFT. */ public class IbftProtocolSchedule { @@ -35,34 +36,37 @@ public class IbftProtocolSchedule { public static ProtocolSchedule create( final GenesisConfigOptions config, final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled) { + final boolean isRevertReasonEnabled, + final Clock clock) { final IbftConfigOptions ibftConfig = config.getIbftLegacyConfigOptions(); final long blockPeriod = ibftConfig.getBlockPeriodSeconds(); return new ProtocolScheduleBuilder<>( config, DEFAULT_CHAIN_ID, - builder -> applyIbftChanges(blockPeriod, builder), + builder -> applyIbftChanges(blockPeriod, builder, clock), privacyParameters, - isRevertReasonEnabled) + isRevertReasonEnabled, + clock) .createProtocolSchedule(); } public static ProtocolSchedule create( - final GenesisConfigOptions config, final boolean isRevertReasonEnabled) { - return create(config, PrivacyParameters.DEFAULT, isRevertReasonEnabled); + final GenesisConfigOptions config, final boolean isRevertReasonEnabled, final Clock clock) { + return create(config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, clock); } - public static ProtocolSchedule create(final GenesisConfigOptions config) { - return create(config, PrivacyParameters.DEFAULT, false); + public static ProtocolSchedule create( + final GenesisConfigOptions config, final Clock clock) { + return create(config, PrivacyParameters.DEFAULT, false, clock); } private static ProtocolSpecBuilder applyIbftChanges( - final long secondsBetweenBlocks, final ProtocolSpecBuilder builder) { + final long secondsBetweenBlocks, final ProtocolSpecBuilder builder, final Clock clock) { return builder .changeConsensusContextType( - difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), - difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), + difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks, clock), + difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks, clock), MainnetBlockBodyValidator::new, MainnetBlockValidator::new, MainnetBlockImporter::new, diff --git a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java index 80649af4344..052206a39f8 100644 --- a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java +++ b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/IbftBlockHeaderValidationRulesetFactoryTest.java @@ -26,6 +26,7 @@ import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.mainnet.BlockHeaderValidator; import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.uint.UInt256; @@ -54,7 +55,7 @@ public void ibftValidateHeaderPasses() { getPresetHeaderBuilder(2, proposerKeyPair, validators, parentHeader).buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -75,7 +76,7 @@ public void ibftValidateHeaderFailsOnExtraData() { getPresetHeaderBuilder(2, proposerKeyPair, emptyList(), parentHeader).buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -100,7 +101,7 @@ public void ibftValidateHeaderFailsOnCoinbaseData() { .buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -121,7 +122,7 @@ public void ibftValidateHeaderFailsOnNonce() { getPresetHeaderBuilder(2, proposerKeyPair, validators, parentHeader).nonce(3).buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -144,7 +145,7 @@ public void ibftValidateHeaderFailsOnTimestamp() { .buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -167,7 +168,7 @@ public void ibftValidateHeaderFailsOnMixHash() { .buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -190,7 +191,7 @@ public void ibftValidateHeaderFailsOnOmmers() { .buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -213,7 +214,7 @@ public void ibftValidateHeaderFailsOnDifficulty() { .buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -234,7 +235,7 @@ public void ibftValidateHeaderFailsOnAncestor() { getPresetHeaderBuilder(2, proposerKeyPair, validators, null).buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -258,7 +259,7 @@ public void ibftValidateHeaderFailsOnGasUsage() { .buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -281,7 +282,7 @@ public void ibftValidateHeaderFailsOnGasLimitRange() { .buildHeader(); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( diff --git a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/IbftBlockCreatorTest.java b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/IbftBlockCreatorTest.java index 3f50fb3a981..0aba2c04de9 100644 --- a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/IbftBlockCreatorTest.java +++ b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/IbftBlockCreatorTest.java @@ -75,7 +75,8 @@ public void createdBlockPassesValidationRulesAndHasAppropriateHashAndMixHash() { final ProtocolSchedule protocolSchedule = IbftProtocolSchedule.create( GenesisConfigFile.fromConfig("{\"config\": {\"spuriousDragonBlock\":0}}") - .getConfigOptions()); + .getConfigOptions(), + TestClock.fixed()); final ProtocolContext protContext = new ProtocolContext<>( blockchain, @@ -110,7 +111,7 @@ public void createdBlockPassesValidationRulesAndHasAppropriateHashAndMixHash() { final Block block = blockCreator.createBlock(Instant.now().getEpochSecond()); final BlockHeaderValidator rules = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(0); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(0, TestClock.fixed()); // NOTE: The header will not contain commit seals, so can only do light validation on header. final boolean validationResult = diff --git a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactory.java b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactory.java index 68dc7ab542f..b6e8d84ed47 100644 --- a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactory.java +++ b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactory.java @@ -26,6 +26,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent; import tech.pegasys.pantheon.util.uint.UInt256; +import java.time.Clock; + public class IbftBlockHeaderValidationRulesetFactory { /** @@ -33,11 +35,12 @@ public class IbftBlockHeaderValidationRulesetFactory { * part of the BlockChain (i.e. not proposed blocks, which do not contain commit seals) * * @param secondsBetweenBlocks the minimum number of seconds which must elapse between blocks. + * @param clock System clock * @return BlockHeaderValidator configured for assessing ibft block headers */ public static BlockHeaderValidator ibftBlockHeaderValidator( - final long secondsBetweenBlocks) { - return createValidator(secondsBetweenBlocks, true); + final long secondsBetweenBlocks, final Clock clock) { + return createValidator(secondsBetweenBlocks, true, clock); } /** @@ -45,20 +48,21 @@ public static BlockHeaderValidator ibftBlockHeaderValidator( * which need to be vetted by the validators, and do not contain commit seals). * * @param secondsBetweenBlocks the minimum number of seconds which must elapse between blocks. + * @param clock System clock * @return BlockHeaderValidator configured for assessing ibft block headers */ public static BlockHeaderValidator ibftProposedBlockValidator( - final long secondsBetweenBlocks) { - return createValidator(secondsBetweenBlocks, false); + final long secondsBetweenBlocks, final Clock clock) { + return createValidator(secondsBetweenBlocks, false, clock); } private static BlockHeaderValidator createValidator( - final long secondsBetweenBlocks, final boolean validateCommitSeals) { + final long secondsBetweenBlocks, final boolean validateCommitSeals, final Clock clock) { return new BlockHeaderValidator.Builder() .addRule(new AncestryValidationRule()) .addRule(new GasUsageValidationRule()) .addRule(new GasLimitRangeAndDeltaValidationRule(5000, 0x7fffffffffffffffL)) - .addRule(new TimestampBoundedByFutureParameter(1)) + .addRule(new TimestampBoundedByFutureParameter(1, clock)) .addRule(new TimestampMoreRecentThanParent(secondsBetweenBlocks)) .addRule( new ConstantFieldValidationRule<>( diff --git a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java index 321557b9c06..6b7eab70646 100644 --- a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java +++ b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java @@ -27,6 +27,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpecBuilder; import java.math.BigInteger; +import java.time.Clock; /** Defines the protocol behaviours for a blockchain using IBFT. */ public class IbftProtocolSchedule { @@ -36,30 +37,32 @@ public class IbftProtocolSchedule { public static ProtocolSchedule create( final GenesisConfigOptions config, final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled) { + final boolean isRevertReasonEnabled, + final Clock clock) { final IbftConfigOptions ibftConfig = config.getIbftLegacyConfigOptions(); final long blockPeriod = ibftConfig.getBlockPeriodSeconds(); return new ProtocolScheduleBuilder<>( config, DEFAULT_CHAIN_ID, - builder -> applyIbftChanges(blockPeriod, builder), + builder -> applyIbftChanges(blockPeriod, builder, clock), privacyParameters, - isRevertReasonEnabled) + isRevertReasonEnabled, + clock) .createProtocolSchedule(); } public static ProtocolSchedule create( - final GenesisConfigOptions config, final boolean isRevertReasonEnabled) { - return create(config, PrivacyParameters.DEFAULT, isRevertReasonEnabled); + final GenesisConfigOptions config, final boolean isRevertReasonEnabled, final Clock clock) { + return create(config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, clock); } private static ProtocolSpecBuilder applyIbftChanges( - final long secondsBetweenBlocks, final ProtocolSpecBuilder builder) { + final long secondsBetweenBlocks, final ProtocolSpecBuilder builder, final Clock clock) { return builder .changeConsensusContextType( - difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), - difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), + difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks, clock), + difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks, clock), MainnetBlockBodyValidator::new, MainnetBlockValidator::new, MainnetBlockImporter::new, diff --git a/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactoryTest.java b/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactoryTest.java index fd44e0b0101..bf4ef179e5a 100644 --- a/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactoryTest.java +++ b/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftBlockHeaderValidationRulesetFactoryTest.java @@ -32,6 +32,7 @@ import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.mainnet.BlockHeaderValidator; import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.uint.UInt256; @@ -67,7 +68,7 @@ public void ibftValidateHeaderPasses() { final BlockHeader blockHeader = buildBlockHeader(2, proposerKeyPair, validators, parentHeader); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( @@ -90,7 +91,7 @@ public void ibftValidateHeaderFails() { final BlockHeader blockHeader = buildBlockHeader(2, proposerKeyPair, validators, null); final BlockHeaderValidator validator = - IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5); + IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator(5, TestClock.fixed()); assertThat( validator.validateHeader( diff --git a/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java b/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java index 2163e0fe71a..7ebdf721254 100644 --- a/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java +++ b/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java @@ -43,7 +43,7 @@ import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; -import java.time.Instant; +import java.time.Clock; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -78,11 +78,13 @@ public void headerProducedPassesValidationRules() { Address.fromHexString(String.format("%020d", 4)), localAddr); + Clock testClock = TestClock.fixed(); final ProtocolSchedule protocolSchedule = IbftProtocolSchedule.create( GenesisConfigFile.fromConfig("{\"config\": {\"spuriousDragonBlock\":0}}") .getConfigOptions(), - false); + false, + testClock); final ProtocolContext protContext = new ProtocolContext<>( blockchain, @@ -102,7 +104,7 @@ public void headerProducedPassesValidationRules() { new PendingTransactions( TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS, 1, - TestClock.fixed(), + testClock, metricsSystem), protContext, protocolSchedule, @@ -111,10 +113,10 @@ public void headerProducedPassesValidationRules() { Wei.ZERO, parentHeader); - final Block block = blockCreator.createBlock(Instant.now().getEpochSecond()); + final Block block = blockCreator.createBlock(testClock.instant().getEpochSecond()); final BlockHeaderValidator rules = - IbftBlockHeaderValidationRulesetFactory.ibftProposedBlockValidator(0); + IbftBlockHeaderValidationRulesetFactory.ibftProposedBlockValidator(0, testClock); final boolean validationResult = rules.validateHeader( diff --git a/errorprone-checks/src/main/java/tech/pegasys/errorpronechecks/BannedMethod.java b/errorprone-checks/src/main/java/tech/pegasys/errorpronechecks/BannedMethod.java index 28e065c70a8..90cbff84efa 100644 --- a/errorprone-checks/src/main/java/tech/pegasys/errorpronechecks/BannedMethod.java +++ b/errorprone-checks/src/main/java/tech/pegasys/errorpronechecks/BannedMethod.java @@ -15,7 +15,6 @@ import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; import static com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; import static com.google.errorprone.matchers.Description.NO_MATCH; -import static com.google.errorprone.matchers.Matchers.allOf; import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; import java.util.Map; @@ -23,6 +22,7 @@ import com.google.auto.service.AutoService; import com.google.common.collect.ImmutableMap; import com.google.errorprone.BugPattern; +import com.google.errorprone.BugPattern.LinkType; import com.google.errorprone.VisitorState; import com.google.errorprone.bugpatterns.BugChecker; import com.google.errorprone.matchers.Description; @@ -34,12 +34,15 @@ @BugPattern( name = "BannedMethod", summary = "Some methods should not be used, make sure that doesn't happen.", - severity = WARNING) + severity = WARNING, + linkType = LinkType.NONE) public class BannedMethod extends BugChecker implements MethodInvocationTreeMatcher { private static final ImmutableMap, String> BANNED_METHOD_LIST = ImmutableMap.of( - allOf(staticMethod().onClass("com.google.common.base.Objects").withAnyName()), + staticMethod().onClass("java.lang.System").named("currentTimeMillis"), + "Do not use System.currentTimeMillis(), use a java.time.Clock passed into a constructor or as a static method parameter.", + staticMethod().onClass("com.google.common.base.Objects").withAnyName(), "Do not use com.google.common.base.Objects methods, use java.util.Objects methods instead."); @Override diff --git a/errorprone-checks/src/test/resources/tech/pegasys/errorpronechecks/BannedMethodNegativeCases.java b/errorprone-checks/src/test/resources/tech/pegasys/errorpronechecks/BannedMethodNegativeCases.java index e8e236a2d69..9c2965ea94f 100644 --- a/errorprone-checks/src/test/resources/tech/pegasys/errorpronechecks/BannedMethodNegativeCases.java +++ b/errorprone-checks/src/test/resources/tech/pegasys/errorpronechecks/BannedMethodNegativeCases.java @@ -13,6 +13,7 @@ package tech.pegasys.errorpronechecks; import java.util.Objects; +import java.time.Clock; public class BannedMethodNegativeCases { @@ -23,4 +24,9 @@ public void callsObjectsEquals() throws Exception { public void callsObjectsHashCode() throws Exception { Objects.hash("1", "1"); } + + public void callsClockMillis(final Clock clock) throws Exception { + clock.millis(); + } + } diff --git a/errorprone-checks/src/test/resources/tech/pegasys/errorpronechecks/BannedMethodPositiveCases.java b/errorprone-checks/src/test/resources/tech/pegasys/errorpronechecks/BannedMethodPositiveCases.java index 31818f8119c..b183e0f02f6 100644 --- a/errorprone-checks/src/test/resources/tech/pegasys/errorpronechecks/BannedMethodPositiveCases.java +++ b/errorprone-checks/src/test/resources/tech/pegasys/errorpronechecks/BannedMethodPositiveCases.java @@ -27,4 +27,10 @@ public void callsObjectsHashCode() throws Exception { // java.util.Objects methods instead. Objects.hashCode("1", "1"); } + + public void callsSystemCurrentTimeMillis() throws Exception { + // BUG: Diagnostic contains: Do not use System.currentTimeMillis(), use a java.time.Clock + // passed into a constructor or as a static method parameter. + System.currentTimeMillis(); + } } diff --git a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java index 346101f9cfb..c3f02961f46 100644 --- a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java @@ -93,7 +93,8 @@ private ProcessableBlockHeader createBlockWithGasLimit(final long gasLimit) { @Test public void emptyPendingTransactionsResultsInEmptyVettingResult() { final ProtocolSchedule protocolSchedule = - FixedDifficultyProtocolSchedule.create(GenesisConfigFile.development().getConfigOptions()); + FixedDifficultyProtocolSchedule.create( + GenesisConfigFile.development().getConfigOptions(), TestClock.fixed()); final TransactionProcessor mainnetTransactionProcessor = protocolSchedule.getByBlockNumber(0).getTransactionProcessor(); diff --git a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java index ad80f58bd99..15eaa78da9d 100644 --- a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java @@ -58,8 +58,10 @@ public class EthHashBlockCreatorTest { BigInteger.valueOf(42), Function.identity(), PrivacyParameters.DEFAULT, - false) + false, + TestClock.fixed()) .createProtocolSchedule()) + .clock(TestClock.fixed()) .build(); @Test diff --git a/ethereum/core/src/jmh/java/tech/pegasys/pantheon/ethereum/vm/operations/OperationBenchmarkHelper.java b/ethereum/core/src/jmh/java/tech/pegasys/pantheon/ethereum/vm/operations/OperationBenchmarkHelper.java index 8b7147ee62e..8968b5ec6bd 100644 --- a/ethereum/core/src/jmh/java/tech/pegasys/pantheon/ethereum/vm/operations/OperationBenchmarkHelper.java +++ b/ethereum/core/src/jmh/java/tech/pegasys/pantheon/ethereum/vm/operations/OperationBenchmarkHelper.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Clock; import com.google.common.io.MoreFiles; import com.google.common.io.RecursiveDeleteOption; @@ -57,7 +58,10 @@ public static OperationBenchmarkHelper create() throws IOException { new NoOpMetricsSystem()); final ExecutionContextTestFixture executionContext = - ExecutionContextTestFixture.builder().keyValueStorage(keyValueStorage).build(); + ExecutionContextTestFixture.builder() + .keyValueStorage(keyValueStorage) + .clock(Clock.systemUTC()) + .build(); final MutableBlockchain blockchain = executionContext.getBlockchain(); for (int i = 1; i < 256; i++) { diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java index d9df25023df..885964ac3f0 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java @@ -17,27 +17,32 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; +import java.time.Clock; + /** A ProtocolSchedule which behaves similarly to MainNet, but with a much reduced difficulty. */ public class FixedDifficultyProtocolSchedule { public static ProtocolSchedule create( final GenesisConfigOptions config, final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled) { + final boolean isRevertReasonEnabled, + final Clock clock) { return new ProtocolScheduleBuilder<>( config, builder -> builder.difficultyCalculator(FixedDifficultyCalculators.calculator(config)), privacyParameters, - isRevertReasonEnabled) + isRevertReasonEnabled, + clock) .createProtocolSchedule(); } public static ProtocolSchedule create( - final GenesisConfigOptions config, final boolean isRevertReasonEnabled) { - return create(config, PrivacyParameters.DEFAULT, isRevertReasonEnabled); + final GenesisConfigOptions config, final boolean isRevertReasonEnabled, final Clock clock) { + return create(config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, clock); } - public static ProtocolSchedule create(final GenesisConfigOptions config) { - return create(config, PrivacyParameters.DEFAULT, false); + public static ProtocolSchedule create( + final GenesisConfigOptions config, final Clock clock) { + return create(config, PrivacyParameters.DEFAULT, false, clock); } } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidator.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidator.java index 0b4cbb33ae7..f0fd9b5691e 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidator.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidator.java @@ -24,6 +24,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.time.Clock; + public final class MainnetBlockHeaderValidator { public static final BytesValue DAO_EXTRA_DATA = @@ -34,13 +36,13 @@ public final class MainnetBlockHeaderValidator { public static final int MINIMUM_SECONDS_SINCE_PARENT = 1; public static BlockHeaderValidator create( - final DifficultyCalculator difficultyCalculator) { - return createValidator(difficultyCalculator).build(); + final DifficultyCalculator difficultyCalculator, final Clock clock) { + return createValidator(difficultyCalculator, clock).build(); } - public static BlockHeaderValidator createDaoValidator( - final DifficultyCalculator difficultyCalculator) { - return createValidator(difficultyCalculator) + static BlockHeaderValidator createDaoValidator( + final DifficultyCalculator difficultyCalculator, final Clock clock) { + return createValidator(difficultyCalculator, clock) .addRule( new ConstantFieldValidationRule<>( "extraData", BlockHeader::getExtraData, DAO_EXTRA_DATA)) @@ -65,14 +67,14 @@ static BlockHeaderValidator createOmmerValidator( } private static BlockHeaderValidator.Builder createValidator( - final DifficultyCalculator difficultyCalculator) { + final DifficultyCalculator difficultyCalculator, final Clock clock) { return new BlockHeaderValidator.Builder() .addRule(new CalculatedDifficultyValidationRule<>(difficultyCalculator)) .addRule(new AncestryValidationRule()) .addRule(new GasLimitRangeAndDeltaValidationRule(MIN_GAS_LIMIT, MAX_GAS_LIMIT)) .addRule(new GasUsageValidationRule()) .addRule(new TimestampMoreRecentThanParent(MINIMUM_SECONDS_SINCE_PARENT)) - .addRule(new TimestampBoundedByFutureParameter(TIMESTAMP_TOLERANCE_S)) + .addRule(new TimestampBoundedByFutureParameter(TIMESTAMP_TOLERANCE_S, clock)) .addRule(new ExtraDataMaxLengthValidationRule(BlockHeader.MAX_EXTRA_DATA_BYTES)) .addRule(new ProofOfWorkValidationRule()); } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java index 181203303fd..f282092ba2c 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java @@ -19,6 +19,7 @@ import tech.pegasys.pantheon.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule; import java.math.BigInteger; +import java.time.Clock; import java.util.function.Function; /** Provides {@link ProtocolSpec} lookups for mainnet hard forks. */ @@ -26,9 +27,9 @@ public class MainnetProtocolSchedule { public static final BigInteger DEFAULT_CHAIN_ID = BigInteger.ONE; - public static ProtocolSchedule create() { + public static ProtocolSchedule create(final Clock clock) { return fromConfig( - GenesisConfigFile.mainnet().getConfigOptions(), PrivacyParameters.DEFAULT, false); + GenesisConfigFile.mainnet().getConfigOptions(), PrivacyParameters.DEFAULT, false, clock); } /** @@ -38,18 +39,25 @@ public static ProtocolSchedule create() { * starting points * @param privacyParameters the parameters set for private transactions * @param isRevertReasonEnabled whether storing the revert reason is for failed transactions + * @param clock System clock * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( final GenesisConfigOptions config, final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled) { + final boolean isRevertReasonEnabled, + final Clock clock) { if (FixedDifficultyCalculators.isFixedDifficultyInConfig(config)) { return FixedDifficultyProtocolSchedule.create( - config, privacyParameters, isRevertReasonEnabled); + config, privacyParameters, isRevertReasonEnabled, clock); } - return new ProtocolScheduleBuilder<>( - config, DEFAULT_CHAIN_ID, Function.identity(), privacyParameters, isRevertReasonEnabled) + return new ProtocolScheduleBuilder( + config, + DEFAULT_CHAIN_ID, + Function.identity(), + privacyParameters, + isRevertReasonEnabled, + clock) .createProtocolSchedule(); } @@ -59,11 +67,12 @@ public static ProtocolSchedule fromConfig( * @param config {@link GenesisConfigOptions} containing the config options for the milestone * starting points * @param isRevertReasonEnabled whether storing the revert reason is for failed transactions + * @param clock System clock * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( - final GenesisConfigOptions config, final boolean isRevertReasonEnabled) { - return fromConfig(config, PrivacyParameters.DEFAULT, isRevertReasonEnabled); + final GenesisConfigOptions config, final boolean isRevertReasonEnabled, final Clock clock) { + return fromConfig(config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, clock); } /** @@ -71,9 +80,11 @@ public static ProtocolSchedule fromConfig( * * @param config {@link GenesisConfigOptions} containing the config options for the milestone * starting points + * @param clock System clock * @return A configured mainnet protocol schedule */ - public static ProtocolSchedule fromConfig(final GenesisConfigOptions config) { - return fromConfig(config, PrivacyParameters.DEFAULT, false); + public static ProtocolSchedule fromConfig( + final GenesisConfigOptions config, final Clock clock) { + return fromConfig(config, PrivacyParameters.DEFAULT, false, clock); } } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java index e99d9bbe1fe..1c6a0c8a156 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.math.BigInteger; import java.nio.charset.StandardCharsets; +import java.time.Clock; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -72,7 +73,9 @@ public abstract class MainnetProtocolSpecs { private MainnetProtocolSpecs() {} public static ProtocolSpecBuilder frontierDefinition( - final OptionalInt configContractSizeLimit, final OptionalInt configStackSizeLimit) { + final OptionalInt configContractSizeLimit, + final OptionalInt configStackSizeLimit, + final Clock clock) { final int contractSizeLimit = configContractSizeLimit.orElse(FRONTIER_CONTRACT_SIZE_LIMIT); final int stackSizeLimit = configStackSizeLimit.orElse(DEFAULT_MAX_STACK_SIZE); return new ProtocolSpecBuilder() @@ -120,7 +123,8 @@ public static ProtocolSpecBuilder frontierDefinition( Account.DEFAULT_VERSION, new PrivateTransactionValidator(Optional.empty()))) .difficultyCalculator(MainnetDifficultyCalculators.FRONTIER) - .blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::create) + .blockHeaderValidatorBuilder( + difficultyCalculator -> MainnetBlockHeaderValidator.create(difficultyCalculator, clock)) .ommerHeaderValidatorBuilder(MainnetBlockHeaderValidator::createOmmerValidator) .blockBodyValidatorBuilder(MainnetBlockBodyValidator::new) .transactionReceiptFactory(MainnetProtocolSpecs::frontierTransactionReceiptFactory) @@ -135,9 +139,11 @@ public static ProtocolSpecBuilder frontierDefinition( } public static ProtocolSpecBuilder homesteadDefinition( - final OptionalInt configContractSizeLimit, final OptionalInt configStackSizeLimit) { + final OptionalInt configContractSizeLimit, + final OptionalInt configStackSizeLimit, + final Clock clock) { final int contractSizeLimit = configContractSizeLimit.orElse(FRONTIER_CONTRACT_SIZE_LIMIT); - return frontierDefinition(configContractSizeLimit, configStackSizeLimit) + return frontierDefinition(configContractSizeLimit, configStackSizeLimit, clock) .gasCalculator(HomesteadGasCalculator::new) .evmBuilder(MainnetEvmRegistries::homestead) .contractCreationProcessorBuilder( @@ -155,9 +161,13 @@ public static ProtocolSpecBuilder homesteadDefinition( } public static ProtocolSpecBuilder daoRecoveryInitDefinition( - final OptionalInt contractSizeLimit, final OptionalInt configStackSizeLimit) { - return homesteadDefinition(contractSizeLimit, configStackSizeLimit) - .blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::createDaoValidator) + final OptionalInt contractSizeLimit, + final OptionalInt configStackSizeLimit, + final Clock clock) { + return homesteadDefinition(contractSizeLimit, configStackSizeLimit, clock) + .blockHeaderValidatorBuilder( + difficultyCalculator -> + MainnetBlockHeaderValidator.createDaoValidator(difficultyCalculator, clock)) .blockProcessorBuilder( (transactionProcessor, transactionReceiptFactory, @@ -173,15 +183,19 @@ public static ProtocolSpecBuilder daoRecoveryInitDefinition( } public static ProtocolSpecBuilder daoRecoveryTransitionDefinition( - final OptionalInt contractSizeLimit, final OptionalInt configStackSizeLimit) { - return daoRecoveryInitDefinition(contractSizeLimit, configStackSizeLimit) + final OptionalInt contractSizeLimit, + final OptionalInt configStackSizeLimit, + final Clock clock) { + return daoRecoveryInitDefinition(contractSizeLimit, configStackSizeLimit, clock) .blockProcessorBuilder(MainnetBlockProcessor::new) .name("DaoRecoveryTransition"); } public static ProtocolSpecBuilder tangerineWhistleDefinition( - final OptionalInt contractSizeLimit, final OptionalInt configStackSizeLimit) { - return homesteadDefinition(contractSizeLimit, configStackSizeLimit) + final OptionalInt contractSizeLimit, + final OptionalInt configStackSizeLimit, + final Clock clock) { + return homesteadDefinition(contractSizeLimit, configStackSizeLimit, clock) .gasCalculator(TangerineWhistleGasCalculator::new) .name("TangerineWhistle"); } @@ -189,12 +203,13 @@ public static ProtocolSpecBuilder tangerineWhistleDefinition( public static ProtocolSpecBuilder spuriousDragonDefinition( final Optional chainId, final OptionalInt configContractSizeLimit, - final OptionalInt configStackSizeLimit) { + final OptionalInt configStackSizeLimit, + final Clock clock) { final int contractSizeLimit = configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); final int stackSizeLimit = configStackSizeLimit.orElse(DEFAULT_MAX_STACK_SIZE); - return tangerineWhistleDefinition(OptionalInt.empty(), configStackSizeLimit) + return tangerineWhistleDefinition(OptionalInt.empty(), configStackSizeLimit, clock) .gasCalculator(SpuriousDragonGasCalculator::new) .messageCallProcessorBuilder( (evm, precompileContractRegistry) -> @@ -249,8 +264,9 @@ public static ProtocolSpecBuilder byzantiumDefinition( final Optional chainId, final OptionalInt contractSizeLimit, final OptionalInt configStackSizeLimit, - final boolean enableRevertReason) { - return spuriousDragonDefinition(chainId, contractSizeLimit, configStackSizeLimit) + final boolean enableRevertReason, + final Clock clock) { + return spuriousDragonDefinition(chainId, contractSizeLimit, configStackSizeLimit, clock) .evmBuilder(MainnetEvmRegistries::byzantium) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::byzantium) .difficultyCalculator(MainnetDifficultyCalculators.BYZANTIUM) @@ -267,8 +283,10 @@ public static ProtocolSpecBuilder constantinopleDefinition( final Optional chainId, final OptionalInt contractSizeLimit, final OptionalInt configStackSizeLimit, - final boolean enableRevertReason) { - return byzantiumDefinition(chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason) + final boolean enableRevertReason, + final Clock clock) { + return byzantiumDefinition( + chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason, clock) .difficultyCalculator(MainnetDifficultyCalculators.CONSTANTINOPLE) .gasCalculator(ConstantinopleGasCalculator::new) .evmBuilder(MainnetEvmRegistries::constantinople) @@ -280,9 +298,10 @@ public static ProtocolSpecBuilder constantinopleFixDefinition( final Optional chainId, final OptionalInt contractSizeLimit, final OptionalInt configStackSizeLimit, - final boolean enableRevertReason) { + final boolean enableRevertReason, + final Clock clock) { return constantinopleDefinition( - chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason) + chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason, clock) .gasCalculator(ConstantinopleFixGasCalculator::new) .name("ConstantinopleFix"); } @@ -291,13 +310,14 @@ public static ProtocolSpecBuilder istanbulDefinition( final Optional chainId, final OptionalInt configContractSizeLimit, final OptionalInt configStackSizeLimit, - final boolean enableRevertReason) { + final boolean enableRevertReason, + final Clock clock) { checkArgument(chainId.isPresent(), "Istanbul requires the use of chainId"); final int contractSizeLimit = configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); final int stackSizeLimit = configStackSizeLimit.orElse(DEFAULT_MAX_STACK_SIZE); return constantinopleFixDefinition( - chainId, configContractSizeLimit, configStackSizeLimit, enableRevertReason) + chainId, configContractSizeLimit, configStackSizeLimit, enableRevertReason, clock) .gasCalculator(IstanbulGasCalculator::new) .evmBuilder(gasCalculator -> MainnetEvmRegistries.istanbul(gasCalculator, chainId.get())) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::istanbul) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java index c6d3ddb6119..2b71b6d5053 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionValidator; import java.math.BigInteger; +import java.time.Clock; import java.util.Optional; import java.util.OptionalLong; import java.util.function.Function; @@ -32,27 +33,37 @@ public class ProtocolScheduleBuilder { private final Optional defaultChainId; private final PrivacyParameters privacyParameters; private final boolean isRevertReasonEnabled; + private final Clock clock; public ProtocolScheduleBuilder( final GenesisConfigOptions config, final BigInteger defaultChainId, final Function, ProtocolSpecBuilder> protocolSpecAdapter, final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled) { + final boolean isRevertReasonEnabled, + final Clock clock) { this( config, Optional.of(defaultChainId), protocolSpecAdapter, privacyParameters, - isRevertReasonEnabled); + isRevertReasonEnabled, + clock); } public ProtocolScheduleBuilder( final GenesisConfigOptions config, final Function, ProtocolSpecBuilder> protocolSpecAdapter, final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled) { - this(config, Optional.empty(), protocolSpecAdapter, privacyParameters, isRevertReasonEnabled); + final boolean isRevertReasonEnabled, + final Clock clock) { + this( + config, + Optional.empty(), + protocolSpecAdapter, + privacyParameters, + isRevertReasonEnabled, + clock); } private ProtocolScheduleBuilder( @@ -60,17 +71,18 @@ private ProtocolScheduleBuilder( final Optional defaultChainId, final Function, ProtocolSpecBuilder> protocolSpecAdapter, final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled) { + final boolean isRevertReasonEnabled, + final Clock clock) { this.config = config; this.defaultChainId = defaultChainId; this.protocolSpecAdapter = protocolSpecAdapter; this.privacyParameters = privacyParameters; this.isRevertReasonEnabled = isRevertReasonEnabled; + this.clock = clock; } public ProtocolSchedule createProtocolSchedule() { - final Optional chainId = - config.getChainId().map(Optional::of).orElse(defaultChainId); + final Optional chainId = config.getChainId().or(() -> defaultChainId); final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(chainId); validateForkOrdering(); @@ -79,12 +91,12 @@ public ProtocolSchedule createProtocolSchedule() { protocolSchedule, OptionalLong.of(0), MainnetProtocolSpecs.frontierDefinition( - config.getContractSizeLimit(), config.getEvmStackSize())); + config.getContractSizeLimit(), config.getEvmStackSize(), clock)); addProtocolSpec( protocolSchedule, config.getHomesteadBlockNumber(), MainnetProtocolSpecs.homesteadDefinition( - config.getContractSizeLimit(), config.getEvmStackSize())); + config.getContractSizeLimit(), config.getEvmStackSize(), clock)); config .getDaoForkBlock() @@ -96,12 +108,12 @@ public ProtocolSchedule createProtocolSchedule() { protocolSchedule, OptionalLong.of(daoBlockNumber), MainnetProtocolSpecs.daoRecoveryInitDefinition( - config.getContractSizeLimit(), config.getEvmStackSize())); + config.getContractSizeLimit(), config.getEvmStackSize(), clock)); addProtocolSpec( protocolSchedule, OptionalLong.of(daoBlockNumber + 1), MainnetProtocolSpecs.daoRecoveryTransitionDefinition( - config.getContractSizeLimit(), config.getEvmStackSize())); + config.getContractSizeLimit(), config.getEvmStackSize(), clock)); // Return to the previous protocol spec after the dao fork has completed. protocolSchedule.putMilestone(daoBlockNumber + 10, originalProtocolSpec); @@ -111,12 +123,12 @@ public ProtocolSchedule createProtocolSchedule() { protocolSchedule, config.getTangerineWhistleBlockNumber(), MainnetProtocolSpecs.tangerineWhistleDefinition( - config.getContractSizeLimit(), config.getEvmStackSize())); + config.getContractSizeLimit(), config.getEvmStackSize(), clock)); addProtocolSpec( protocolSchedule, config.getSpuriousDragonBlockNumber(), MainnetProtocolSpecs.spuriousDragonDefinition( - chainId, config.getContractSizeLimit(), config.getEvmStackSize())); + chainId, config.getContractSizeLimit(), config.getEvmStackSize(), clock)); addProtocolSpec( protocolSchedule, config.getByzantiumBlockNumber(), @@ -124,7 +136,8 @@ public ProtocolSchedule createProtocolSchedule() { chainId, config.getContractSizeLimit(), config.getEvmStackSize(), - isRevertReasonEnabled)); + isRevertReasonEnabled, + clock)); addProtocolSpec( protocolSchedule, config.getConstantinopleBlockNumber(), @@ -132,7 +145,8 @@ public ProtocolSchedule createProtocolSchedule() { chainId, config.getContractSizeLimit(), config.getEvmStackSize(), - isRevertReasonEnabled)); + isRevertReasonEnabled, + clock)); addProtocolSpec( protocolSchedule, config.getConstantinopleFixBlockNumber(), @@ -140,7 +154,8 @@ public ProtocolSchedule createProtocolSchedule() { chainId, config.getContractSizeLimit(), config.getEvmStackSize(), - isRevertReasonEnabled)); + isRevertReasonEnabled, + clock)); addProtocolSpec( protocolSchedule, config.getIstanbulBlockNumber(), @@ -148,7 +163,8 @@ public ProtocolSchedule createProtocolSchedule() { chainId, config.getContractSizeLimit(), config.getEvmStackSize(), - isRevertReasonEnabled)); + isRevertReasonEnabled, + clock)); LOG.info("Protocol schedule created with milestones: {}", protocolSchedule.listMilestones()); return protocolSchedule; diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampBoundedByFutureParameter.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampBoundedByFutureParameter.java index 2d7a77e1333..add41a9f66e 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampBoundedByFutureParameter.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampBoundedByFutureParameter.java @@ -15,7 +15,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.mainnet.DetachedBlockHeaderValidationRule; -import java.util.concurrent.TimeUnit; +import java.time.Clock; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -28,9 +28,12 @@ public class TimestampBoundedByFutureParameter implements DetachedBlockHeaderVal private final Logger LOG = LogManager.getLogger(); private final long acceptableClockDriftSeconds; + private final Clock clock; - public TimestampBoundedByFutureParameter(final long acceptableClockDriftSeconds) { + public TimestampBoundedByFutureParameter( + final long acceptableClockDriftSeconds, final Clock clock) { this.acceptableClockDriftSeconds = acceptableClockDriftSeconds; + this.clock = clock; } @Override @@ -43,9 +46,7 @@ private boolean validateTimestamp(final long timestamp) { } private boolean validateHeaderNotAheadOfCurrentSystemTime(final long timestamp) { - final long timestampMargin = - TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS) - + acceptableClockDriftSeconds; + final long timestampMargin = clock.instant().getEpochSecond() + acceptableClockDriftSeconds; if (Long.compareUnsigned(timestamp, timestampMargin) > 0) { LOG.trace( "Invalid block header: timestamp {} is greater than the timestamp margin {}", 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 8263349f54e..a7d889355db 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 @@ -12,6 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.core; +import static com.google.common.base.Preconditions.checkNotNull; + import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.config.StubGenesisConfigOptions; import tech.pegasys.pantheon.ethereum.ProtocolContext; @@ -27,8 +29,10 @@ 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.testutil.TestClock; import java.math.BigInteger; +import java.time.Clock; import java.util.function.Function; public class ExecutionContextTestFixture { @@ -60,7 +64,7 @@ keyValueStorage, new MainnetBlockHeaderFunctions()), } public static ExecutionContextTestFixture create() { - return new Builder().build(); + return new Builder().clock(TestClock.fixed()).build(); } public static Builder builder() { @@ -95,6 +99,7 @@ public static class Builder { private KeyValueStorage keyValueStorage; private ProtocolSchedule protocolSchedule; + private Clock clock; public Builder keyValueStorage(final KeyValueStorage keyValueStorage) { this.keyValueStorage = keyValueStorage; @@ -106,7 +111,14 @@ public Builder protocolSchedule(final ProtocolSchedule protocolSchedule) { return this; } + public Builder clock(final Clock clock) { + this.clock = clock; + return this; + } + public ExecutionContextTestFixture build() { + checkNotNull(clock); + if (protocolSchedule == null) { protocolSchedule = new ProtocolScheduleBuilder<>( @@ -114,7 +126,8 @@ public ExecutionContextTestFixture build() { BigInteger.valueOf(42), Function.identity(), new PrivacyParameters(), - false) + false, + clock) .createProtocolSchedule(); } if (keyValueStorage == null) { diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/TestCodeExecutor.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/TestCodeExecutor.java index 9e1c3876a66..5dbf2ba306d 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/TestCodeExecutor.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/TestCodeExecutor.java @@ -21,6 +21,7 @@ import tech.pegasys.pantheon.ethereum.vm.MessageFrame; import tech.pegasys.pantheon.ethereum.vm.OperationTracer; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.math.BigInteger; @@ -35,7 +36,11 @@ public class TestCodeExecutor { private static final Address SENDER_ADDRESS = AddressHelpers.ofValue(244259721); public TestCodeExecutor(final ProtocolSchedule protocolSchedule) { - fixture = ExecutionContextTestFixture.builder().protocolSchedule(protocolSchedule).build(); + fixture = + ExecutionContextTestFixture.builder() + .protocolSchedule(protocolSchedule) + .clock(TestClock.fixed()) + .build(); } public MessageFrame executeCode( diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisStateTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisStateTest.java index 1669f047cb4..45d95cd10f0 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisStateTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisStateTest.java @@ -23,9 +23,12 @@ import tech.pegasys.pantheon.ethereum.storage.keyvalue.WorldStateKeyValueStorage; import tech.pegasys.pantheon.ethereum.worldstate.DefaultMutableWorldState; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.uint.UInt256; +import java.time.Clock; + import com.google.common.base.Charsets; import com.google.common.io.Resources; import org.bouncycastle.util.encoders.Hex; @@ -33,6 +36,8 @@ public final class GenesisStateTest { + final Clock testClock = new TestClock(); + /** Known RLP encoded bytes of the Olympic Genesis Block. */ private static final String OLYMPIC_RLP = "f901f8f901f3a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a09178d0f23c965d81f0834a4c72c6253ce6830f4022b1359aaebfc1ecba442d4ea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808080a0000000000000000000000000000000000000000000000000000000000000000088000000000000002ac0c0"; @@ -49,7 +54,7 @@ public void createFromJsonWithAllocs() throws Exception { final GenesisState genesisState = GenesisState.fromJson( Resources.toString(GenesisStateTest.class.getResource("genesis1.json"), Charsets.UTF_8), - MainnetProtocolSchedule.create()); + MainnetProtocolSchedule.create(testClock)); final BlockHeader header = genesisState.getBlock().getHeader(); assertThat(header.getStateRoot()) .isEqualTo( @@ -78,7 +83,7 @@ public void createFromJsonNoAllocs() throws Exception { final GenesisState genesisState = GenesisState.fromJson( Resources.toString(GenesisStateTest.class.getResource("genesis2.json"), Charsets.UTF_8), - MainnetProtocolSchedule.create()); + MainnetProtocolSchedule.create(testClock)); final BlockHeader header = genesisState.getBlock().getHeader(); assertThat(header.getStateRoot()).isEqualTo(Hash.EMPTY_TRIE_HASH); assertThat(header.getTransactionsRoot()).isEqualTo(Hash.EMPTY_TRIE_HASH); @@ -93,7 +98,7 @@ private void assertContractInvariants( final GenesisState genesisState = GenesisState.fromJson( Resources.toString(GenesisStateTest.class.getResource(sourceFile), Charsets.UTF_8), - MainnetProtocolSchedule.create()); + MainnetProtocolSchedule.create(testClock)); final BlockHeader header = genesisState.getBlock().getHeader(); assertThat(header.getHash()).isEqualTo(Hash.fromHexString(blockHash)); @@ -132,7 +137,7 @@ public void createFromJsonWithNonce() throws Exception { GenesisState.fromJson( Resources.toString( GenesisStateTest.class.getResource("genesisNonce.json"), Charsets.UTF_8), - MainnetProtocolSchedule.create()); + MainnetProtocolSchedule.create(testClock)); final BlockHeader header = genesisState.getBlock().getHeader(); assertThat(header.getHash()) .isEqualTo( @@ -146,7 +151,7 @@ public void encodeOlympicBlock() throws Exception { GenesisState.fromJson( Resources.toString( GenesisStateTest.class.getResource("genesis-olympic.json"), Charsets.UTF_8), - MainnetProtocolSchedule.create()); + MainnetProtocolSchedule.create(testClock)); final BytesValueRLPOutput tmp = new BytesValueRLPOutput(); genesisState.getBlock().writeTo(tmp); assertThat(Hex.toHexString(genesisState.getBlock().getHeader().getHash().extractArray())) diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java index df66f560735..ca406c3c6a8 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java @@ -18,6 +18,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; +import tech.pegasys.pantheon.testutil.TestClock; import org.junit.Test; @@ -27,7 +28,8 @@ public class FixedProtocolScheduleTest { public void reportedDifficultyForAllBlocksIsAFixedValue() { final ProtocolSchedule schedule = - FixedDifficultyProtocolSchedule.create(GenesisConfigFile.development().getConfigOptions()); + FixedDifficultyProtocolSchedule.create( + GenesisConfigFile.development().getConfigOptions(), TestClock.fixed()); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidatorTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidatorTest.java index c31517898c4..ec95ff1b169 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidatorTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockHeaderValidatorTest.java @@ -16,6 +16,7 @@ import static org.mockito.Mockito.mock; import tech.pegasys.pantheon.ethereum.ProtocolContext; +import tech.pegasys.pantheon.testutil.TestClock; import org.junit.Test; @@ -28,7 +29,8 @@ public final class MainnetBlockHeaderValidatorTest { @Test public void validHeaderFrontier() throws Exception { final BlockHeaderValidator headerValidator = - MainnetBlockHeaderValidator.create(MainnetDifficultyCalculators.FRONTIER); + MainnetBlockHeaderValidator.create( + MainnetDifficultyCalculators.FRONTIER, TestClock.fixed()); assertThat( headerValidator.validateHeader( ValidationTestUtils.readHeader(300006), @@ -41,7 +43,8 @@ public void validHeaderFrontier() throws Exception { @Test public void validHeaderHomestead() throws Exception { final BlockHeaderValidator headerValidator = - MainnetBlockHeaderValidator.create(MainnetDifficultyCalculators.HOMESTEAD); + MainnetBlockHeaderValidator.create( + MainnetDifficultyCalculators.HOMESTEAD, TestClock.fixed()); assertThat( headerValidator.validateHeader( ValidationTestUtils.readHeader(1200001), @@ -54,7 +57,8 @@ public void validHeaderHomestead() throws Exception { @Test public void invalidParentHash() throws Exception { final BlockHeaderValidator headerValidator = - MainnetBlockHeaderValidator.create(MainnetDifficultyCalculators.HOMESTEAD); + MainnetBlockHeaderValidator.create( + MainnetDifficultyCalculators.HOMESTEAD, TestClock.fixed()); assertThat( headerValidator.validateHeader( ValidationTestUtils.readHeader(1200001), @@ -67,7 +71,8 @@ public void invalidParentHash() throws Exception { @Test public void validHeaderByzantium() throws Exception { final BlockHeaderValidator headerValidator = - MainnetBlockHeaderValidator.create(MainnetDifficultyCalculators.BYZANTIUM); + MainnetBlockHeaderValidator.create( + MainnetDifficultyCalculators.BYZANTIUM, TestClock.fixed()); assertThat( headerValidator.validateHeader( ValidationTestUtils.readHeader(4400001), diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java index 6834be93fc4..1e7547c9e6b 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java @@ -13,6 +13,7 @@ package tech.pegasys.pantheon.ethereum.mainnet; import tech.pegasys.pantheon.config.GenesisConfigFile; +import tech.pegasys.pantheon.testutil.TestClock; import java.nio.charset.StandardCharsets; @@ -25,7 +26,7 @@ public class MainnetProtocolScheduleTest { @Test public void shouldReturnDefaultProtocolSpecsWhenCustomNumbersAreNotUsed() { - final ProtocolSchedule sched = MainnetProtocolSchedule.create(); + final ProtocolSchedule sched = MainnetProtocolSchedule.create(TestClock.fixed()); Assertions.assertThat(sched.getByBlockNumber(1L).getName()).isEqualTo("Frontier"); Assertions.assertThat(sched.getByBlockNumber(1_150_000L).getName()).isEqualTo("Homestead"); Assertions.assertThat(sched.getByBlockNumber(1_920_000L).getName()) @@ -49,7 +50,8 @@ public void shouldReturnDefaultProtocolSpecsWhenCustomNumbersAreNotUsed() { public void shouldOnlyUseFrontierWhenEmptyJsonConfigIsUsed() { final JsonObject json = new JsonObject("{}"); final ProtocolSchedule sched = - MainnetProtocolSchedule.fromConfig(GenesisConfigFile.fromConfig(json).getConfigOptions()); + MainnetProtocolSchedule.fromConfig( + GenesisConfigFile.fromConfig(json).getConfigOptions(), TestClock.fixed()); Assertions.assertThat(sched.getByBlockNumber(1L).getName()).isEqualTo("Frontier"); Assertions.assertThat(sched.getByBlockNumber(Long.MAX_VALUE).getName()).isEqualTo("Frontier"); } @@ -60,7 +62,8 @@ public void createFromConfigWithSettings() { new JsonObject( "{\"config\": {\"homesteadBlock\": 2, \"daoForkBlock\": 3, \"eip150Block\": 14, \"eip158Block\": 15, \"byzantiumBlock\": 16, \"constantinopleBlock\": 18, \"constantinopleFixBlock\": 19, \"chainId\":1234}}"); final ProtocolSchedule sched = - MainnetProtocolSchedule.fromConfig(GenesisConfigFile.fromConfig(json).getConfigOptions()); + MainnetProtocolSchedule.fromConfig( + GenesisConfigFile.fromConfig(json).getConfigOptions(), TestClock.fixed()); Assertions.assertThat(sched.getByBlockNumber(1).getName()).isEqualTo("Frontier"); Assertions.assertThat(sched.getByBlockNumber(2).getName()).isEqualTo("Homestead"); Assertions.assertThat(sched.getByBlockNumber(3).getName()).isEqualTo("DaoRecoveryInit"); @@ -84,7 +87,7 @@ public void outOfOrderConstantinoplesFail() { .isThrownBy( () -> MainnetProtocolSchedule.fromConfig( - GenesisConfigFile.fromConfig(json).getConfigOptions())); + GenesisConfigFile.fromConfig(json).getConfigOptions(), TestClock.fixed())); } @Test @@ -94,7 +97,8 @@ public void shouldCreateRopstenConfig() throws Exception { GenesisConfigFile.fromConfig( Resources.toString( this.getClass().getResource("/ropsten.json"), StandardCharsets.UTF_8)) - .getConfigOptions()); + .getConfigOptions(), + TestClock.fixed()); Assertions.assertThat(sched.getByBlockNumber(0).getName()).isEqualTo("TangerineWhistle"); Assertions.assertThat(sched.getByBlockNumber(1).getName()).isEqualTo("TangerineWhistle"); Assertions.assertThat(sched.getByBlockNumber(10).getName()).isEqualTo("SpuriousDragon"); diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRuleTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRuleTest.java index 88e853dc5e7..cc2a6661da9 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRuleTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRuleTest.java @@ -22,6 +22,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import tech.pegasys.pantheon.ethereum.mainnet.ValidationTestUtils; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.uint.UInt256; import java.io.IOException; @@ -109,7 +110,8 @@ public void failsWithMisMatchedNonce() { } private BlockHeaderFunctions mainnetBlockHashFunction() { - final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(TestClock.fixed()); return ScheduleBasedBlockHeaderFunctions.create(protocolSchedule); } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java index b6aac2e3aba..65faf00a337 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/TimestampValidationRuleTest.java @@ -16,8 +16,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; - -import java.util.concurrent.TimeUnit; +import tech.pegasys.pantheon.testutil.TestClock; import org.assertj.core.api.Assertions; import org.junit.Test; @@ -26,7 +25,8 @@ public class TimestampValidationRuleTest { @Test public void headerTimestampSufficientlyFarIntoFutureVadidatesSuccessfully() { - final TimestampBoundedByFutureParameter uut00 = new TimestampBoundedByFutureParameter(0); + final TimestampBoundedByFutureParameter uut00 = + new TimestampBoundedByFutureParameter(0, TestClock.fixed()); final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); @@ -50,7 +50,8 @@ public void headerTimestampDifferenceMustBePositive() { @Test public void headerTimestampTooCloseToParentFailsValidation() { - final TimestampBoundedByFutureParameter uut00 = new TimestampBoundedByFutureParameter(0); + final TimestampBoundedByFutureParameter uut00 = + new TimestampBoundedByFutureParameter(0, TestClock.fixed()); final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); @@ -68,7 +69,8 @@ public void headerTimestampTooCloseToParentFailsValidation() { @Test public void headerTimestampIsBehindParentFailsValidation() { - final TimestampBoundedByFutureParameter uut00 = new TimestampBoundedByFutureParameter(0); + final TimestampBoundedByFutureParameter uut00 = + new TimestampBoundedByFutureParameter(0, TestClock.fixed()); final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); @@ -89,14 +91,13 @@ public void headerNewerThanCurrentSystemFailsValidation() { final long acceptableClockDrift = 5; final TimestampBoundedByFutureParameter uut00 = - new TimestampBoundedByFutureParameter(acceptableClockDrift); + new TimestampBoundedByFutureParameter(acceptableClockDrift, TestClock.fixed()); final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); // Create Parent Header @ 'now' - headerBuilder.timestamp( - TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS)); + headerBuilder.timestamp(TestClock.fixed().instant().getEpochSecond()); final BlockHeader parent = headerBuilder.buildHeader(); // Create header for validation with a timestamp in the future (1 second too far away) @@ -112,14 +113,12 @@ public void futureHeadersAreValidIfTimestampWithinTolerance() { final long acceptableClockDrift = 5; final TimestampBoundedByFutureParameter uut00 = - new TimestampBoundedByFutureParameter(acceptableClockDrift); + new TimestampBoundedByFutureParameter(acceptableClockDrift, TestClock.fixed()); final TimestampMoreRecentThanParent uut01 = new TimestampMoreRecentThanParent(10); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); - // Create Parent Header @ 'now' - headerBuilder.timestamp( - TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS)); + headerBuilder.timestamp(TestClock.fixed().instant().getEpochSecond()); final BlockHeader parent = headerBuilder.buildHeader(); // Create header for validation with a timestamp in the future (1 second too far away) diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java index 4d2ff6c6b9b..0eb18f036da 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java @@ -19,6 +19,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; import java.math.BigInteger; +import java.time.Clock; import java.util.Map; import java.util.function.Function; @@ -67,7 +68,12 @@ public ProtocolSchedule getByName(final String name) { private static ProtocolSchedule createSchedule(final GenesisConfigOptions options) { return new ProtocolScheduleBuilder<>( - options, CHAIN_ID, Function.identity(), PrivacyParameters.DEFAULT, false) + options, + CHAIN_ID, + Function.identity(), + PrivacyParameters.DEFAULT, + false, + Clock.systemUTC()) .createProtocolSchedule(); } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java index b144eed64c4..5596917d8c4 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java @@ -31,6 +31,7 @@ import tech.pegasys.pantheon.testutil.JsonTestParameters; import java.math.BigInteger; +import java.time.Clock; import java.util.ArrayDeque; import java.util.Collection; import java.util.Optional; @@ -121,7 +122,8 @@ protected void runTest() { final EnvironmentInformation execEnv = spec.getExec(); final ProtocolSpec protocolSpec = - MainnetProtocolSpecs.frontierDefinition(OptionalInt.empty(), OptionalInt.empty()) + MainnetProtocolSpecs.frontierDefinition( + OptionalInt.empty(), OptionalInt.empty(), Clock.systemUTC()) .privacyParameters(PrivacyParameters.DEFAULT) .privateTransactionValidatorBuilder(() -> new PrivateTransactionValidator(CHAIN_ID)) .build(new MutableProtocolSchedule<>(CHAIN_ID)); diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ConstantinopleSStoreOperationGasCostTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ConstantinopleSStoreOperationGasCostTest.java index 2aa6fe735fc..9c20cb17153 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ConstantinopleSStoreOperationGasCostTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ConstantinopleSStoreOperationGasCostTest.java @@ -22,6 +22,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.vm.MessageFrame; import tech.pegasys.pantheon.ethereum.vm.MessageFrame.State; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.uint.UInt256; import org.junit.Before; @@ -35,7 +36,8 @@ public class ConstantinopleSStoreOperationGasCostTest { private static final ProtocolSchedule protocolSchedule = - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().constantinopleBlock(0)); + MainnetProtocolSchedule.fromConfig( + new StubGenesisConfigOptions().constantinopleBlock(0), TestClock.fixed()); @Parameters(name = "Code: {0}, Original: {1}") public static Object[][] scenarios() { diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeer.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeer.java index 68c9fbe5a54..f65f36512e0 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeer.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeer.java @@ -109,7 +109,7 @@ public void recordRequestTimeout(final int requestCode) { public void recordUselessResponse(final String requestType) { LOG.debug("Received useless response for {} from peer {}", requestType, this); - reputation.recordUselessResponse(System.currentTimeMillis()).ifPresent(this::disconnect); + reputation.recordUselessResponse(clock.millis()).ifPresent(this::disconnect); } public void disconnect(final DisconnectReason reason) { diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java index 9dee76e5b9a..bbf19486ea9 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java @@ -967,7 +967,8 @@ public void newBlockMinedSendsNewBlockMessageToAllPeers() { .isEqualTo(Collections.singletonList(EthProtocol.ETH63)); // assert that all messages transmitted contain the expected block & total difficulty. - final ProtocolSchedule protocolSchdeule = MainnetProtocolSchedule.create(); + final ProtocolSchedule protocolSchdeule = + MainnetProtocolSchedule.create(TestClock.fixed()); for (final NewBlockMessage msg : messageSentCaptor.getAllValues()) { assertThat(msg.block(protocolSchdeule)).isEqualTo(minedBlock); assertThat(msg.totalDifficulty(protocolSchdeule)).isEqualTo(expectedTotalDifficulty); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTestUtil.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTestUtil.java index f55c4abc354..5f25be8c5cf 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTestUtil.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTestUtil.java @@ -65,7 +65,8 @@ public static EthProtocolManager create( } public static EthProtocolManager create(final EthScheduler ethScheduler) { - final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(TestClock.fixed()); final GenesisConfigFile config = GenesisConfigFile.mainnet(); final GenesisState genesisState = GenesisState.fromConfig(config, protocolSchedule); final Blockchain blockchain = createInMemoryBlockchain(genesisState.getBlock()); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ethtaskutils/BlockchainSetupUtil.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ethtaskutils/BlockchainSetupUtil.java index e98313e6fa6..b2678068256 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ethtaskutils/BlockchainSetupUtil.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ethtaskutils/BlockchainSetupUtil.java @@ -32,6 +32,7 @@ import tech.pegasys.pantheon.ethereum.util.RawBlockIterator; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.testutil.BlockTestUtil; +import tech.pegasys.pantheon.testutil.TestClock; import java.io.IOException; import java.net.URISyntaxException; @@ -91,7 +92,8 @@ public int blockCount() { } public static BlockchainSetupUtil forTesting() { - final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(TestClock.fixed()); final TemporaryFolder temp = new TemporaryFolder(); try { temp.create(); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/BlockBodiesMessageTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/BlockBodiesMessageTest.java index 07318cdaf69..953fceb36d3 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/BlockBodiesMessageTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/BlockBodiesMessageTest.java @@ -23,6 +23,7 @@ import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPInput; import tech.pegasys.pantheon.ethereum.rlp.RLP; import tech.pegasys.pantheon.ethereum.rlp.RLPInput; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.io.IOException; @@ -66,7 +67,7 @@ public void blockBodiesRoundTrip() throws IOException { message .bodies( FixedDifficultyProtocolSchedule.create( - GenesisConfigFile.development().getConfigOptions(), false)) + GenesisConfigFile.development().getConfigOptions(), false, TestClock.fixed())) .iterator(); for (int i = 0; i < 50; ++i) { Assertions.assertThat(readBodies.next()).isEqualTo(bodies.get(i)); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/BlockHeadersMessageTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/BlockHeadersMessageTest.java index c018da22386..e5c104d20f4 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/BlockHeadersMessageTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/BlockHeadersMessageTest.java @@ -21,6 +21,7 @@ import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPInput; import tech.pegasys.pantheon.ethereum.rlp.RLP; import tech.pegasys.pantheon.ethereum.rlp.RLPInput; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.io.IOException; @@ -58,7 +59,7 @@ public void blockHeadersRoundTrip() throws IOException { final List readHeaders = message.getHeaders( FixedDifficultyProtocolSchedule.create( - GenesisConfigFile.development().getConfigOptions(), false)); + GenesisConfigFile.development().getConfigOptions(), false, TestClock.fixed())); for (int i = 0; i < 50; ++i) { Assertions.assertThat(readHeaders.get(i)).isEqualTo(headers.get(i)); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/NewBlockMessageTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/NewBlockMessageTest.java index 8a89bac9811..020d86ef859 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/NewBlockMessageTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/messages/NewBlockMessageTest.java @@ -21,13 +21,15 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.p2p.rlpx.wire.RawMessage; import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.uint.UInt256; import org.junit.Test; public class NewBlockMessageTest { - private static final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + private static final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(TestClock.fixed()); @Test public void roundTripNewBlockMessage() { diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java index 81b8f97309e..3eaff2ac0f3 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/peervalidation/DaoForkPeerValidatorTest.java @@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderValidator; import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.List; @@ -55,7 +56,7 @@ public void validatePeer_responsivePeerOnRightSideOfFork() { PeerValidator validator = new DaoForkPeerValidator( ethProtocolManager.ethContext(), - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(TestClock.fixed()), new NoOpMetricsSystem(), daoBlockNumber, 0); @@ -87,7 +88,7 @@ public void validatePeer_responsivePeerOnWrongSideOfFork() { PeerValidator validator = new DaoForkPeerValidator( ethProtocolManager.ethContext(), - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(TestClock.fixed()), new NoOpMetricsSystem(), daoBlockNumber, 0); @@ -115,7 +116,7 @@ public void validatePeer_unresponsivePeer() { PeerValidator validator = new DaoForkPeerValidator( ethProtocolManager.ethContext(), - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(TestClock.fixed()), new NoOpMetricsSystem(), daoBlockNumber, 0); @@ -144,7 +145,7 @@ public void validatePeer_requestBlockFromPeerBeingTested() { PeerValidator validator = new DaoForkPeerValidator( ethProtocolManager.ethContext(), - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(TestClock.fixed()), new NoOpMetricsSystem(), daoBlockNumber, 0); @@ -183,7 +184,7 @@ public void canBeValidated() { PeerValidator validator = new DaoForkPeerValidator( ethProtocolManager.ethContext(), - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(TestClock.fixed()), new NoOpMetricsSystem(), daoBlockNumber, buffer); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/ChainHeadTrackerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/ChainHeadTrackerTest.java index fc8c011db91..f5e0a0a9d73 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/ChainHeadTrackerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/ChainHeadTrackerTest.java @@ -27,6 +27,7 @@ import tech.pegasys.pantheon.ethereum.eth.manager.ethtaskutils.BlockchainSetupUtil; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.uint.UInt256; import org.junit.Test; @@ -45,7 +46,7 @@ public class ChainHeadTrackerTest { 0); private final ProtocolSchedule protocolSchedule = FixedDifficultyProtocolSchedule.create( - GenesisConfigFile.development().getConfigOptions(), false); + GenesisConfigFile.development().getConfigOptions(), false, TestClock.fixed()); private final TrailingPeerLimiter trailingPeerLimiter = mock(TrailingPeerLimiter.class); private final ChainHeadTracker chainHeadTracker = diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java index 424bad6938b..ecf05aba37a 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java @@ -32,6 +32,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -58,7 +59,8 @@ public void setup() { final BlockchainSetupUtil localBlockchainSetup = BlockchainSetupUtil.forTesting(); localBlockchain = localBlockchainSetup.getBlockchain(); - final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(TestClock.fixed()); final ProtocolContext protocolContext = new ProtocolContext<>(localBlockchain, localWorldState, null); ethProtocolManager = diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java index 68ef6371611..49ff1faad02 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java @@ -34,6 +34,7 @@ import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.uint.UInt256; import java.io.IOException; @@ -53,7 +54,8 @@ @RunWith(Parameterized.class) public class DetermineCommonAncestorTaskParameterizedTest { - private final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + private final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(TestClock.fixed()); private static final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java index 22a5324effb..e1efc4f6275 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java @@ -46,6 +46,7 @@ import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.ExceptionUtils; import java.util.List; @@ -58,7 +59,8 @@ public class DetermineCommonAncestorTaskTest { - private final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + private final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(TestClock.fixed()); private final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); private final int defaultHeaderRequestSize = 10; diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java index b80dfdb78fa..1ac5b4ae667 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java @@ -892,7 +892,10 @@ private void respondPartially( RespondingEthPeer.blockchainResponder(mock(Blockchain.class), remoteWorldStateArchive); final Responder partialResponder = RespondingEthPeer.partialResponder( - mock(Blockchain.class), remoteWorldStateArchive, MainnetProtocolSchedule.create(), .5f); + mock(Blockchain.class), + remoteWorldStateArchive, + MainnetProtocolSchedule.create(TestClock.fixed()), + .5f); final Responder emptyResponder = RespondingEthPeer.emptyResponder(); // Send a few partial responses diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java index 8fd3d66ea7e..919665970af 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java @@ -95,7 +95,7 @@ public TestNode( final GenesisConfigFile genesisConfigFile = GenesisConfigFile.development(); final ProtocolSchedule protocolSchedule = FixedDifficultyProtocolSchedule.create( - GenesisConfigFile.development().getConfigOptions(), false); + GenesisConfigFile.development().getConfigOptions(), false, TestClock.fixed()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, protocolSchedule); final BlockHeaderFunctions blockHeaderFunctions = @@ -130,6 +130,7 @@ public TestNode( .keyPair(this.kp) .config(networkingConfiguration) .metricsSystem(new NoOpMetricsSystem()) + .clock(TestClock.fixed()) .supportedCapabilities(capabilities) .build()) .metricsSystem(new NoOpMetricsSystem()) diff --git a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/AbstractEthGraphQLHttpServiceTest.java b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/AbstractEthGraphQLHttpServiceTest.java index 1d07b12f52b..3437c969964 100644 --- a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/AbstractEthGraphQLHttpServiceTest.java +++ b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/AbstractEthGraphQLHttpServiceTest.java @@ -44,6 +44,7 @@ import tech.pegasys.pantheon.ethereum.util.RawBlockIterator; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.testutil.BlockTestUtil; +import tech.pegasys.pantheon.testutil.TestClock; import java.net.URL; import java.nio.file.Paths; @@ -97,7 +98,7 @@ public abstract class AbstractEthGraphQLHttpServiceTest { @BeforeClass public static void setupConstants() throws Exception { - PROTOCOL_SCHEDULE = MainnetProtocolSchedule.create(); + PROTOCOL_SCHEDULE = MainnetProtocolSchedule.create(TestClock.fixed()); final URL blocksUrl = BlockTestUtil.getTestBlockchainUrl(); diff --git a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java index 41c801dc028..52508e7c69f 100644 --- a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java +++ b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java @@ -23,6 +23,7 @@ import java.net.URL; import java.nio.file.Paths; +import java.time.Clock; import java.util.ArrayList; import java.util.List; @@ -40,7 +41,7 @@ public class BlockchainImporter { public BlockchainImporter(final URL blocksUrl, final String genesisJson) throws Exception { protocolSchedule = MainnetProtocolSchedule.fromConfig( - GenesisConfigFile.fromConfig(genesisJson).getConfigOptions()); + GenesisConfigFile.fromConfig(genesisJson).getConfigOptions(), Clock.systemUTC()); blocks = new ArrayList<>(); try (final RawBlockIterator iterator = diff --git a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcTestMethodsFactory.java b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcTestMethodsFactory.java index d22bc1d15da..f3a641622c2 100644 --- a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcTestMethodsFactory.java +++ b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcTestMethodsFactory.java @@ -43,6 +43,7 @@ import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration; +import java.time.Clock; import java.util.HashSet; import java.util.Map; import java.util.Optional; @@ -102,7 +103,7 @@ public Map methods() { peerDiscovery, blockchainQueries, synchronizer, - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(Clock.systemUTC()), filterManager, transactionPool, miningCoordinator, diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractEthJsonRpcHttpServiceTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractEthJsonRpcHttpServiceTest.java index 302c80e212f..cc9bb80952a 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractEthJsonRpcHttpServiceTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractEthJsonRpcHttpServiceTest.java @@ -54,6 +54,7 @@ import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration; import tech.pegasys.pantheon.testutil.BlockTestUtil; +import tech.pegasys.pantheon.testutil.TestClock; import java.net.URL; import java.nio.file.Paths; @@ -115,7 +116,7 @@ public abstract class AbstractEthJsonRpcHttpServiceTest { @BeforeClass public static void setupConstants() throws Exception { - PROTOCOL_SCHEDULE = MainnetProtocolSchedule.create(); + PROTOCOL_SCHEDULE = MainnetProtocolSchedule.create(TestClock.fixed()); final URL blocksUrl = BlockTestUtil.getTestBlockchainUrl(); @@ -179,7 +180,7 @@ public void setupTest() throws Exception { peerDiscoveryMock, blockchainQueries, synchronizerMock, - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(TestClock.fixed()), filterManager, transactionPoolMock, miningCoordinatorMock, diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java index cd42b7f5400..7c69743e49f 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java @@ -34,6 +34,7 @@ import tech.pegasys.pantheon.ethereum.permissioning.NodeLocalConfigPermissioningController; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration; +import tech.pegasys.pantheon.testutil.TestClock; import java.io.IOException; import java.math.BigInteger; @@ -99,7 +100,8 @@ public void initServerAndClient() throws Exception { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions() .constantinopleBlock(0) - .chainId(BigInteger.valueOf(CHAIN_ID))), + .chainId(BigInteger.valueOf(CHAIN_ID)), + TestClock.fixed()), mock(FilterManager.class), mock(TransactionPool.class), mock(EthHashMiningCoordinator.class), diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java index cf43813b478..b9288d18aad 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -38,6 +38,7 @@ import tech.pegasys.pantheon.ethereum.p2p.rlpx.wire.Capability; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration; +import tech.pegasys.pantheon.testutil.TestClock; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -127,7 +128,7 @@ public static void initServerAndClient() throws Exception { peerDiscoveryMock, blockchainQueries, synchronizer, - MainnetProtocolSchedule.fromConfig(genesisConfigOptions), + MainnetProtocolSchedule.fromConfig(genesisConfigOptions, TestClock.fixed()), mock(FilterManager.class), mock(TransactionPool.class), mock(EthHashMiningCoordinator.class), diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java index 825c1027032..17520ec2512 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java @@ -43,6 +43,7 @@ import tech.pegasys.pantheon.ethereum.permissioning.NodeLocalConfigPermissioningController; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration; +import tech.pegasys.pantheon.testutil.TestClock; import java.io.IOException; import java.util.ArrayList; @@ -193,7 +194,7 @@ private JsonRpcHttpService createJsonRpcHttpServiceWithRpcApis(final JsonRpcConf mock(P2PNetwork.class), blockchainQueries, mock(Synchronizer.class), - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(TestClock.fixed()), mock(FilterManager.class), mock(TransactionPool.class), mock(EthHashMiningCoordinator.class), @@ -251,6 +252,7 @@ private P2PNetwork createP2pNetwork() { .vertx(vertx) .config(config) .metricsSystem(new NoOpMetricsSystem()) + .clock(TestClock.fixed()) .build(); p2pNetwork.start(); @@ -283,7 +285,7 @@ private JsonRpcHttpService createJsonRpcHttpService( p2pNetwork, blockchainQueries, mock(Synchronizer.class), - MainnetProtocolSchedule.create(), + MainnetProtocolSchedule.create(TestClock.fixed()), mock(FilterManager.class), mock(TransactionPool.class), mock(EthHashMiningCoordinator.class), diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java index 1ef60e6b78b..92c2c2e137e 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java @@ -49,6 +49,7 @@ import tech.pegasys.pantheon.ethereum.permissioning.NodeLocalConfigPermissioningController; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValues; import tech.pegasys.pantheon.util.uint.UInt256; @@ -126,7 +127,8 @@ public static void initServerAndClient() throws Exception { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions() .constantinopleBlock(0) - .chainId(BigInteger.valueOf(CHAIN_ID))), + .chainId(BigInteger.valueOf(CHAIN_ID)), + TestClock.fixed()), mock(FilterManager.class), mock(TransactionPool.class), mock(EthHashMiningCoordinator.class), diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgent.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgent.java index b48a5e7c45f..4036ab0e33c 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgent.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgent.java @@ -35,6 +35,7 @@ import java.net.InetSocketAddress; import java.net.SocketException; +import java.time.Clock; import java.util.List; import java.util.Optional; import java.util.OptionalInt; @@ -64,6 +65,7 @@ public abstract class PeerDiscoveryAgent { private final List peerRequirements = new CopyOnWriteArrayList<>(); private final PeerPermissions peerPermissions; private final Optional natManager; + private final Clock clock; private final MetricsSystem metricsSystem; /* The peer controller, which takes care of the state machine of peers. */ protected Optional controller = Optional.empty(); @@ -87,20 +89,23 @@ public PeerDiscoveryAgent( final DiscoveryConfiguration config, final PeerPermissions peerPermissions, final Optional natManager, - final MetricsSystem metricsSystem) { - this.metricsSystem = metricsSystem; + final MetricsSystem metricsSystem, + final Clock clock) { checkArgument(keyPair != null, "keypair cannot be null"); checkArgument(config != null, "provided configuration cannot be null"); + checkArgument(clock != null, "provided clock cannot be null"); validateConfiguration(config); + this.keyPair = keyPair; + this.config = config; + this.peerPermissions = peerPermissions; this.natManager = natManager; this.bootstrapPeers = config.getBootnodes().stream().map(DiscoveryPeer::fromEnode).collect(Collectors.toList()); - - this.config = config; - this.keyPair = keyPair; + this.metricsSystem = metricsSystem; + this.clock = clock; id = keyPair.getPublicKey().getEncodedBytes(); } @@ -188,6 +193,7 @@ private PeerDiscoveryController createController(final DiscoveryPeer localNode) .peerPermissions(peerPermissions) .peerBondedObservers(peerBondedObservers) .metricsSystem(metricsSystem) + .clock(clock) .build(); } @@ -242,7 +248,7 @@ protected void handleOutgoingPacket(final DiscoveryPeer peer, final Packet packe } return; } - peer.setLastContacted(System.currentTimeMillis()); + peer.setLastContacted(clock.millis()); }); } diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java index 693fae42c02..b147e0a0c7d 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java @@ -31,6 +31,7 @@ import java.net.BindException; import java.net.InetSocketAddress; import java.net.SocketException; +import java.time.Clock; import java.util.Optional; import java.util.OptionalInt; import java.util.concurrent.CompletableFuture; @@ -61,8 +62,9 @@ public VertxPeerDiscoveryAgent( final DiscoveryConfiguration config, final PeerPermissions peerPermissions, final Optional natManager, - final MetricsSystem metricsSystem) { - super(keyPair, config, peerPermissions, natManager, metricsSystem); + final MetricsSystem metricsSystem, + final Clock clock) { + super(keyPair, config, peerPermissions, natManager, metricsSystem, clock); checkArgument(vertx != null, "vertx instance cannot be null"); this.vertx = vertx; diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/FindNeighborsPacketData.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/FindNeighborsPacketData.java index b89593e1d0e..c18a4d65727 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/FindNeighborsPacketData.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/FindNeighborsPacketData.java @@ -18,6 +18,8 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPOutput; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.time.Clock; + public class FindNeighborsPacketData implements PacketData { private static final int TARGET_SIZE = 64; @@ -35,9 +37,9 @@ private FindNeighborsPacketData(final BytesValue target, final long expiration) this.expiration = expiration; } - public static FindNeighborsPacketData create(final BytesValue target) { + public static FindNeighborsPacketData create(final BytesValue target, final Clock clock) { return new FindNeighborsPacketData( - target, System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); + target, clock.millis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); } @Override diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/NeighborsPacketData.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/NeighborsPacketData.java index bc2d1d6e8c4..11ee7b366a0 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/NeighborsPacketData.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/NeighborsPacketData.java @@ -18,6 +18,7 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPInput; import tech.pegasys.pantheon.ethereum.rlp.RLPOutput; +import java.time.Clock; import java.util.List; public class NeighborsPacketData implements PacketData { @@ -36,9 +37,8 @@ private NeighborsPacketData(final List peers, final long expirati } @SuppressWarnings("unchecked") - public static NeighborsPacketData create(final List peers) { - return new NeighborsPacketData( - peers, System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); + public static NeighborsPacketData create(final List peers, final Clock clock) { + return new NeighborsPacketData(peers, clock.millis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); } public static NeighborsPacketData readFrom(final RLPInput in) { diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryController.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryController.java index 38f869d27ce..150e5721476 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryController.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryController.java @@ -35,6 +35,7 @@ import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.time.Clock; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -142,6 +143,8 @@ public class PeerDiscoveryController { private RecursivePeerRefreshState recursivePeerRefreshState; + private final Clock clock; + private PeerDiscoveryController( final KeyPair keypair, final DiscoveryPeer localPeer, @@ -155,7 +158,8 @@ private PeerDiscoveryController( final PeerRequirement peerRequirement, final PeerPermissions peerPermissions, final Subscribers peerBondedObservers, - final MetricsSystem metricsSystem) { + final MetricsSystem metricsSystem, + final Clock clock) { this.timerUtil = timerUtil; this.keypair = keypair; this.localPeer = localPeer; @@ -167,6 +171,7 @@ private PeerDiscoveryController( this.peerRequirement = peerRequirement; this.outboundMessageHandler = outboundMessageHandler; this.peerBondedObservers = peerBondedObservers; + this.clock = clock; this.discoveryProtocolLogger = new DiscoveryProtocolLogger(metricsSystem); this.peerPermissions = new PeerDiscoveryPermissions(localPeer, peerPermissions); @@ -357,7 +362,7 @@ private boolean addToPeerTable(final DiscoveryPeer peer) { } // Reset the last seen timestamp. - final long now = System.currentTimeMillis(); + final long now = clock.millis(); if (peer.getFirstDiscovered() == 0) { peer.setFirstDiscovered(now); } @@ -396,7 +401,7 @@ private Optional matchInteraction(final Packet packet) { } private void refreshTableIfRequired() { - final long now = System.currentTimeMillis(); + final long now = clock.millis(); if (lastRefreshTime + tableRefreshIntervalMs <= now) { LOG.debug("Peer table refresh triggered by timer expiry"); refreshTable(); @@ -425,7 +430,7 @@ private void refreshTable() { final BytesValue target = Peer.randomId(); final List initialPeers = peerTable.nearestPeers(Peer.randomId(), 16); recursivePeerRefreshState.start(initialPeers, target); - lastRefreshTime = System.currentTimeMillis(); + lastRefreshTime = clock.millis(); } /** @@ -435,13 +440,13 @@ private void refreshTable() { */ @VisibleForTesting void bond(final DiscoveryPeer peer) { - peer.setFirstDiscovered(System.currentTimeMillis()); + peer.setFirstDiscovered(clock.millis()); peer.setStatus(PeerDiscoveryStatus.BONDING); final Consumer action = interaction -> { final PingPacketData data = - PingPacketData.create(localPeer.getEndpoint(), peer.getEndpoint()); + PingPacketData.create(localPeer.getEndpoint(), peer.getEndpoint(), clock); createPacket( PacketType.PING, data, @@ -505,7 +510,7 @@ void createPacket(final PacketType type, final PacketData data, final Consumer

action = (interaction) -> { - final FindNeighborsPacketData data = FindNeighborsPacketData.create(target); + final FindNeighborsPacketData data = FindNeighborsPacketData.create(target, clock); sendPacket(peer, PacketType.FIND_NEIGHBORS, data); }; final PeerInteractionState interaction = @@ -532,7 +537,7 @@ private void dispatchInteraction(final Peer peer, final PeerInteractionState sta private void respondToPing( final PingPacketData packetData, final BytesValue pingHash, final DiscoveryPeer sender) { - final PongPacketData data = PongPacketData.create(packetData.getFrom(), pingHash); + final PongPacketData data = PongPacketData.create(packetData.getFrom(), pingHash, clock); sendPacket(sender, PacketType.PONG, data); } @@ -541,7 +546,7 @@ private void respondToFindNeighbors( // TODO: for now return 16 peers. Other implementations calculate how many // peers they can fit in a 1280-byte payload. final List peers = peerTable.nearestPeers(packetData.getTarget(), 16); - final PacketData data = NeighborsPacketData.create(peers); + final PacketData data = NeighborsPacketData.create(peers, clock); sendPacket(sender, PacketType.NEIGHBORS, data); } @@ -662,6 +667,7 @@ public static class Builder { private TimerUtil timerUtil; private AsyncExecutor workerExecutor; private MetricsSystem metricsSystem; + private Clock clock; private Builder() {} @@ -685,7 +691,8 @@ public PeerDiscoveryController build() { peerRequirement, peerPermissions, peerBondedObservers, - metricsSystem); + metricsSystem, + clock); } private void validate() { @@ -695,6 +702,7 @@ private void validate() { validateRequiredDependency(workerExecutor, "AsyncExecutor"); validateRequiredDependency(metricsSystem, "MetricsSystem"); validateRequiredDependency(peerBondedObservers, "PeerBondedObservers"); + validateRequiredDependency(clock, "Clock"); } private void validateRequiredDependency(final Object object, final String name) { @@ -777,5 +785,11 @@ public Builder metricsSystem(final MetricsSystem metricsSystem) { this.metricsSystem = metricsSystem; return this; } + + public Builder clock(final Clock clock) { + checkNotNull(clock); + this.clock = clock; + return this; + } } } diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PingPacketData.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PingPacketData.java index eee997ab8cd..e91c444fdb8 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PingPacketData.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PingPacketData.java @@ -18,6 +18,8 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPInput; import tech.pegasys.pantheon.ethereum.rlp.RLPOutput; +import java.time.Clock; + public class PingPacketData implements PacketData { /* Fixed value that represents we're using v4 of the P2P discovery protocol. */ @@ -42,9 +44,8 @@ private PingPacketData(final Endpoint from, final Endpoint to, final long expira this.expiration = expiration; } - public static PingPacketData create(final Endpoint from, final Endpoint to) { - return new PingPacketData( - from, to, System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); + public static PingPacketData create(final Endpoint from, final Endpoint to, final Clock clock) { + return new PingPacketData(from, to, clock.millis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); } public static PingPacketData readFrom(final RLPInput in) { diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PongPacketData.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PongPacketData.java index b26bd3dba89..a1576682fbf 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PongPacketData.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PongPacketData.java @@ -17,6 +17,8 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPOutput; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.time.Clock; + public class PongPacketData implements PacketData { /* Destination. */ @@ -34,9 +36,10 @@ private PongPacketData(final Endpoint to, final BytesValue pingHash, final long this.expiration = expiration; } - public static PongPacketData create(final Endpoint to, final BytesValue pingHash) { + public static PongPacketData create( + final Endpoint to, final BytesValue pingHash, final Clock clock) { return new PongPacketData( - to, pingHash, System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); + to, pingHash, clock.millis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); } public static PongPacketData readFrom(final RLPInput in) { diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/network/DefaultP2PNetwork.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/network/DefaultP2PNetwork.java index bc58d90cc57..495a2687efe 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/network/DefaultP2PNetwork.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/network/DefaultP2PNetwork.java @@ -43,6 +43,7 @@ import tech.pegasys.pantheon.nat.upnp.UpnpNatManager; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.time.Clock; import java.time.Duration; import java.util.Arrays; import java.util.Collection; @@ -409,6 +410,7 @@ public static class Builder { private Optional natManager = Optional.empty(); private MetricsSystem metricsSystem; + private Clock clock; public P2PNetwork build() { validate(); @@ -426,7 +428,7 @@ private P2PNetwork doBuild() { MutableLocalNode.create(config.getRlpx().getClientId(), 5, supportedCapabilities); final PeerPrivileges peerPrivileges = new DefaultPeerPrivileges(maintainedPeers); peerDiscoveryAgent = peerDiscoveryAgent == null ? createDiscoveryAgent() : peerDiscoveryAgent; - rlpxAgent = rlpxAgent == null ? createRlpxAgent(localNode, peerPrivileges) : rlpxAgent; + rlpxAgent = rlpxAgent == null ? createRlpxAgent(localNode, peerPrivileges, clock) : rlpxAgent; return new DefaultP2PNetwork( localNode, @@ -447,17 +449,18 @@ private void validate() { supportedCapabilities != null && supportedCapabilities.size() > 0, "Supported capabilities must be set and non-empty."); checkState(metricsSystem != null, "MetricsSystem must be set."); + checkState(clock != null, "Clock must be set."); checkState(peerDiscoveryAgent != null || vertx != null, "Vertx must be set."); } private PeerDiscoveryAgent createDiscoveryAgent() { return new VertxPeerDiscoveryAgent( - vertx, keyPair, config.getDiscovery(), peerPermissions, natManager, metricsSystem); + vertx, keyPair, config.getDiscovery(), peerPermissions, natManager, metricsSystem, clock); } private RlpxAgent createRlpxAgent( - final LocalNode localNode, final PeerPrivileges peerPrivileges) { + final LocalNode localNode, final PeerPrivileges peerPrivileges, final Clock clock) { return RlpxAgent.builder() .keyPair(keyPair) .config(config.getRlpx()) @@ -465,6 +468,7 @@ private RlpxAgent createRlpxAgent( .peerPrivileges(peerPrivileges) .localNode(localNode) .metricsSystem(metricsSystem) + .clock(clock) .build(); } @@ -521,6 +525,12 @@ public Builder metricsSystem(final MetricsSystem metricsSystem) { return this; } + public Builder clock(final Clock clock) { + checkNotNull(clock); + this.clock = clock; + return this; + } + public Builder natManager(final UpnpNatManager natManager) { this.natManager = Optional.ofNullable(natManager); return this; diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/RlpxAgent.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/RlpxAgent.java index 118a644873a..74b793edc02 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/RlpxAgent.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/RlpxAgent.java @@ -39,6 +39,7 @@ import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.time.Clock; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -67,6 +68,7 @@ public class RlpxAgent { private final PeerPrivileges peerPrivileges; private final int maxConnections; private final int maxRemotelyInitiatedConnections; + private final Clock clock; @VisibleForTesting final Map connectionsById = new ConcurrentHashMap<>(); @@ -84,7 +86,8 @@ private RlpxAgent( final PeerPrivileges peerPrivileges, final int maxConnections, final int maxRemotelyInitiatedConnections, - final MetricsSystem metricsSystem) { + final MetricsSystem metricsSystem, + final Clock clock) { this.localNode = localNode; this.connectionEvents = connectionEvents; this.connectionInitializer = connectionInitializer; @@ -93,6 +96,7 @@ private RlpxAgent( this.maxConnections = maxConnections; this.maxRemotelyInitiatedConnections = Math.min(maxConnections, maxRemotelyInitiatedConnections); + this.clock = clock; // Setup metrics connectedPeersCounter = @@ -231,7 +235,8 @@ public CompletableFuture connect(final Peer peer) { // We're initiating a new connection final CompletableFuture future = initiateOutboundConnection(peer); connectionFuture.set(future); - RlpxConnection newConnection = RlpxConnection.outboundConnection(peer, future); + RlpxConnection newConnection = + RlpxConnection.outboundConnection(peer, future, clock.millis()); newConnection.subscribeConnectionEstablished( (conn) -> { this.dispatchConnect(conn.getPeerConnection()); @@ -299,7 +304,7 @@ private void handlePermissionsUpdate( private CompletableFuture initiateOutboundConnection(final Peer peer) { LOG.trace("Initiating connection to peer: {}", peer.getEnodeURL()); if (peer instanceof DiscoveryPeer) { - ((DiscoveryPeer) peer).setLastAttemptedConnection(System.currentTimeMillis()); + ((DiscoveryPeer) peer).setLastAttemptedConnection(clock.millis()); } return connectionInitializer @@ -339,7 +344,8 @@ private void handleIncomingConnection(final PeerConnection peerConnection) { // Track this new connection, deduplicating existing connection if necessary final AtomicBoolean newConnectionAccepted = new AtomicBoolean(false); - final RlpxConnection inboundConnection = RlpxConnection.inboundConnection(peerConnection); + final RlpxConnection inboundConnection = + RlpxConnection.inboundConnection(peerConnection, clock.millis()); // Our disconnect handler runs connectionsById.compute(), so don't actually execute the // disconnect command until we've returned from our compute() calculation final AtomicReference disconnectAction = new AtomicReference<>(); @@ -503,6 +509,7 @@ public static class Builder { private ConnectionInitializer connectionInitializer; private PeerConnectionEvents connectionEvents; private MetricsSystem metricsSystem; + private Clock clock; private Builder() {} @@ -528,7 +535,8 @@ public RlpxAgent build() { peerPrivileges, config.getMaxPeers(), config.getMaxRemotelyInitiatedConnections(), - metricsSystem); + metricsSystem, + clock); } private void validate() { @@ -538,6 +546,7 @@ private void validate() { checkState(peerPrivileges != null, "PeerPrivileges must be configured"); checkState(peerPermissions != null, "PeerPermissions must be configured"); checkState(metricsSystem != null, "MetricsSystem must be configured"); + checkState(clock != null, "Clock must be configured"); } public Builder keyPair(final KeyPair keyPair) { @@ -587,5 +596,11 @@ public Builder metricsSystem(final MetricsSystem metricsSystem) { this.metricsSystem = metricsSystem; return this; } + + public Builder clock(final Clock clock) { + checkNotNull(clock); + this.clock = clock; + return this; + } } } diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/RlpxConnection.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/RlpxConnection.java index 868659f3a2c..c9492a9c7c1 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/RlpxConnection.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/RlpxConnection.java @@ -24,18 +24,19 @@ public abstract class RlpxConnection { private final long initiatedAt; protected final CompletableFuture future; - private RlpxConnection(final CompletableFuture future) { + private RlpxConnection(final CompletableFuture future, final long initiatedAt) { this.future = future; - this.initiatedAt = System.currentTimeMillis(); + this.initiatedAt = initiatedAt; } - public static RlpxConnection inboundConnection(final PeerConnection peerConnection) { - return new RemotelyInitiatedRlpxConnection(peerConnection); + public static RlpxConnection inboundConnection( + final PeerConnection peerConnection, final long initiatedAt) { + return new RemotelyInitiatedRlpxConnection(peerConnection, initiatedAt); } public static RlpxConnection outboundConnection( - final Peer peer, final CompletableFuture future) { - return new LocallyInitiatedRlpxConnection(peer, future); + final Peer peer, final CompletableFuture future, final long initiatedAt) { + return new LocallyInitiatedRlpxConnection(peer, future, initiatedAt); } public abstract Peer getPeer(); @@ -84,8 +85,9 @@ private static class RemotelyInitiatedRlpxConnection extends RlpxConnection { private final PeerConnection peerConnection; - private RemotelyInitiatedRlpxConnection(final PeerConnection peerConnection) { - super(CompletableFuture.completedFuture(peerConnection)); + private RemotelyInitiatedRlpxConnection( + final PeerConnection peerConnection, final long initiatedAt) { + super(CompletableFuture.completedFuture(peerConnection), initiatedAt); this.peerConnection = peerConnection; } @@ -147,8 +149,8 @@ private static class LocallyInitiatedRlpxConnection extends RlpxConnection { private final Peer peer; private LocallyInitiatedRlpxConnection( - final Peer peer, final CompletableFuture future) { - super(future); + final Peer peer, final CompletableFuture future, final long initiatedAt) { + super(future, initiatedAt); this.peer = peer; } diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/netty/NettyConnectionInitializer.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/netty/NettyConnectionInitializer.java index a86ff6a5251..aa3b914760d 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/netty/NettyConnectionInitializer.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/netty/NettyConnectionInitializer.java @@ -16,7 +16,6 @@ import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.p2p.config.RlpxConfiguration; -import tech.pegasys.pantheon.ethereum.p2p.discovery.DiscoveryPeer; import tech.pegasys.pantheon.ethereum.p2p.peers.EnodeURL; import tech.pegasys.pantheon.ethereum.p2p.peers.LocalNode; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; @@ -164,10 +163,6 @@ public void subscribeIncomingConnect(final ConnectCallback callback) { public CompletableFuture connect(final Peer peer) { final CompletableFuture connectionFuture = new CompletableFuture<>(); - if (peer instanceof DiscoveryPeer) { - ((DiscoveryPeer) peer).setLastAttemptedConnection(System.currentTimeMillis()); - } - final EnodeURL enode = peer.getEnodeURL(); new Bootstrap() .group(workers) 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 f3f9a8de684..c7086e4f4d5 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 @@ -32,6 +32,7 @@ import tech.pegasys.pantheon.ethereum.p2p.permissions.PeerPermissions; import tech.pegasys.pantheon.ethereum.p2p.permissions.PeerPermissions.Action; import tech.pegasys.pantheon.ethereum.p2p.permissions.PeerPermissionsBlacklist; +import tech.pegasys.pantheon.testutil.TestClock; import java.util.Collections; import java.util.List; @@ -73,7 +74,7 @@ public void neighborsPacketFromUnbondedPeerIsDropped() { // Generate an out-of-band NEIGHBORS message. final List peers = helper.createDiscoveryPeers(5); - final NeighborsPacketData data = NeighborsPacketData.create(peers); + final NeighborsPacketData data = NeighborsPacketData.create(peers, TestClock.fixed()); final Packet packet = Packet.create(PacketType.NEIGHBORS, data, otherNode.getKeyPair()); helper.sendMessageBetweenAgents(otherNode, agent, packet); @@ -112,7 +113,8 @@ public void neighborsPacketLimited() { packet = Packet.create( PacketType.FIND_NEIGHBORS, - FindNeighborsPacketData.create(otherAgents.get(0).getAdvertisedPeer().get().getId()), + FindNeighborsPacketData.create( + otherAgents.get(0).getAdvertisedPeer().get().getId(), TestClock.fixed()), testAgent.getKeyPair()); helper.sendMessageBetweenAgents(testAgent, agent, packet); @@ -204,7 +206,7 @@ public void bonding_allowIncomingBonding() { // Start an agent with no bootstrap peers. final PeerPermissions peerPermissions = mock(PeerPermissions.class); final MockPeerDiscoveryAgent agent = - helper.startDiscoveryAgent(Collections.emptyList(), peerPermissions); + helper.startDiscoveryAgent(Collections.emptyList(), peerPermissions, TestClock.fixed()); final Peer localNode = agent.getAdvertisedPeer().get(); // Setup peer and permissions @@ -231,7 +233,7 @@ public void bonding_disallowIncomingBonding() { // Start an agent with no bootstrap peers. final PeerPermissions peerPermissions = mock(PeerPermissions.class); final MockPeerDiscoveryAgent agent = - helper.startDiscoveryAgent(Collections.emptyList(), peerPermissions); + helper.startDiscoveryAgent(Collections.emptyList(), peerPermissions, TestClock.fixed()); final Peer localNode = agent.getAdvertisedPeer().get(); // Setup peer and permissions @@ -472,7 +474,8 @@ protected void bondViaIncomingPing( protected void requestNeighbors( final MockPeerDiscoveryAgent fromAgent, final MockPeerDiscoveryAgent toAgent) { - final FindNeighborsPacketData data = FindNeighborsPacketData.create(Peer.randomId()); + final FindNeighborsPacketData data = + FindNeighborsPacketData.create(Peer.randomId(), TestClock.fixed()); final Packet packet = Packet.create(PacketType.FIND_NEIGHBORS, data, fromAgent.getKeyPair()); helper.sendMessageBetweenAgents(fromAgent, toAgent, packet); } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryBondingTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryBondingTest.java index 6e458c0261f..7e9a0022c2f 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryBondingTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryBondingTest.java @@ -21,6 +21,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.Packet; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PacketType; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PongPacketData; +import tech.pegasys.pantheon.testutil.TestClock; import java.util.Collections; import java.util.List; @@ -67,7 +68,8 @@ public void neighborsPacketNotSentUnlessBonded() throws InterruptedException { // ignored because // we haven't bonded. final MockPeerDiscoveryAgent otherNode = helper.startDiscoveryAgent(); - final FindNeighborsPacketData data = FindNeighborsPacketData.create(otherNode.getId()); + final FindNeighborsPacketData data = + FindNeighborsPacketData.create(otherNode.getId(), TestClock.fixed()); final Packet packet = Packet.create(PacketType.FIND_NEIGHBORS, data, otherNode.getKeyPair()); helper.sendMessageBetweenAgents(otherNode, agent, packet); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryBootstrappingTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryBootstrappingTest.java index a549991434d..9d9f241dfdd 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryBootstrappingTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryBootstrappingTest.java @@ -23,6 +23,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PacketType; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PingPacketData; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.List; @@ -53,7 +54,7 @@ public void bootstrappingPingsSentSingleBootstrapPeer() { final PingPacketData pingData = pingPacket.getPacketData(PingPacketData.class).get(); assertThat(pingData.getExpiration()) - .isGreaterThanOrEqualTo(System.currentTimeMillis() / 1000 - 10000); + .isGreaterThanOrEqualTo(TestClock.fixed().millis() / 1000 - 10000); assertThat(pingData.getFrom()).isEqualTo(agent.getAdvertisedPeer().get().getEndpoint()); assertThat(pingData.getTo()).isEqualTo(testAgent.getAdvertisedPeer().get().getEndpoint()); } @@ -100,7 +101,7 @@ public void bootstrappingPingsSentMultipleBootstrapPeers() { // Assert on the content of the packet data. final PingPacketData ping = packet.getPacketData(PingPacketData.class).get(); assertThat(ping.getExpiration()) - .isGreaterThanOrEqualTo(System.currentTimeMillis() / 1000 - 10000); + .isGreaterThanOrEqualTo(TestClock.fixed().millis() / 1000 - 10000); assertThat(ping.getTo()).isEqualTo(bootstrapAgent.getAdvertisedPeer().get().getEndpoint()); } } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryObserversTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryObserversTest.java index cb084aefed5..b36c202e343 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryObserversTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryObserversTest.java @@ -16,6 +16,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryEvent.PeerBondedEvent; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.MockPeerDiscoveryAgent; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.ArrayList; @@ -102,7 +103,7 @@ public void peerBondedObserverTriggered() throws TimeoutException, InterruptedEx // Create a discovery agent (which we'll assert on), using the above two peers as bootstrap // peers. - final MockPeerDiscoveryAgent agent = helper.createDiscoveryAgent(peers2); + final MockPeerDiscoveryAgent agent = helper.createDiscoveryAgent(peers2, TestClock.fixed()); // A queue for storing peer bonded events. final List events = new ArrayList<>(10); agent.observePeerBondedEvents(events::add); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryPacketSedesTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryPacketSedesTest.java index 7e830443d87..b48a3c95497 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryPacketSedesTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryPacketSedesTest.java @@ -24,6 +24,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PacketType; import tech.pegasys.pantheon.ethereum.rlp.RLP; import tech.pegasys.pantheon.ethereum.rlp.RLPException; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.MutableBytesValue; @@ -43,7 +44,8 @@ public void serializeDeserializeEntirePacket() { final BytesValue target = BytesValue.wrap(r); final SECP256K1.KeyPair kp = SECP256K1.KeyPair.generate(); - final FindNeighborsPacketData packetData = FindNeighborsPacketData.create(target); + final FindNeighborsPacketData packetData = + FindNeighborsPacketData.create(target, TestClock.fixed()); final Packet packet = Packet.create(PacketType.FIND_NEIGHBORS, packetData, kp); final Buffer encoded = packet.encode(); assertNotNull(encoded); @@ -61,7 +63,8 @@ public void serializeDeserializeFindNeighborsPacketData() { new Random().nextBytes(r); final BytesValue target = BytesValue.wrap(r); - final FindNeighborsPacketData packet = FindNeighborsPacketData.create(target); + final FindNeighborsPacketData packet = + FindNeighborsPacketData.create(target, TestClock.fixed()); final BytesValue serialized = RLP.encode(packet::writeTo); assertNotNull(serialized); @@ -72,14 +75,14 @@ public void serializeDeserializeFindNeighborsPacketData() { // assertion. assertThat(deserialized.getExpiration()) .isCloseTo( - System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS, offset(1500L)); + TestClock.fixed().millis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS, offset(1500L)); } @Test public void neighborsPacketData() { final List peers = helper.createDiscoveryPeers(5); - final NeighborsPacketData packet = NeighborsPacketData.create(peers); + final NeighborsPacketData packet = NeighborsPacketData.create(peers, TestClock.fixed()); final BytesValue serialized = RLP.encode(packet::writeTo); assertNotNull(serialized); @@ -89,7 +92,7 @@ public void neighborsPacketData() { // assertion. assertThat(deserialized.getExpiration()) .isCloseTo( - System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS, offset(1500L)); + TestClock.fixed().millis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS, offset(1500L)); } @Test(expected = RLPException.class) @@ -98,7 +101,8 @@ public void deserializeDifferentPacketData() { new Random().nextBytes(r); final BytesValue target = BytesValue.wrap(r); - final FindNeighborsPacketData packet = FindNeighborsPacketData.create(target); + final FindNeighborsPacketData packet = + FindNeighborsPacketData.create(target, TestClock.fixed()); final BytesValue serialized = RLP.encode(packet::writeTo); assertNotNull(serialized); @@ -113,7 +117,7 @@ public void integrityCheckFailsUnmatchedHash() { final SECP256K1.KeyPair kp = SECP256K1.KeyPair.generate(); - final FindNeighborsPacketData data = FindNeighborsPacketData.create(target); + final FindNeighborsPacketData data = FindNeighborsPacketData.create(target, TestClock.fixed()); final Packet packet = Packet.create(PacketType.FIND_NEIGHBORS, data, kp); final BytesValue encoded = BytesValue.wrapBuffer(packet.encode()); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java index 7840ef19428..0e2a18c8761 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java @@ -24,8 +24,10 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.EnodeURL; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.p2p.permissions.PeerPermissions; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.time.Clock; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -80,7 +82,8 @@ public Packet createPingPacket( PacketType.PING, PingPacketData.create( fromAgent.getAdvertisedPeer().get().getEndpoint(), - toAgent.getAdvertisedPeer().get().getEndpoint()), + toAgent.getAdvertisedPeer().get().getEndpoint(), + TestClock.fixed()), fromAgent.getKeyPair()); } @@ -122,7 +125,19 @@ public List startDiscoveryAgents(final int count) { * @return a list of discovery agents. */ public MockPeerDiscoveryAgent startDiscoveryAgent(final List bootstrapPeers) { - final AgentBuilder agentBuilder = agentBuilder().bootstrapPeers(bootstrapPeers); + return startDiscoveryAgent(bootstrapPeers, TestClock.fixed()); + } + + /** + * Start a single discovery agent with the provided bootstrap peers. + * + * @param bootstrapPeers the list of bootstrap peers + * @param clock the clock to sample timestamps from + * @return a list of discovery agents. + */ + public MockPeerDiscoveryAgent startDiscoveryAgent( + final List bootstrapPeers, final Clock clock) { + final AgentBuilder agentBuilder = agentBuilder().bootstrapPeers(bootstrapPeers).clock(clock); return startDiscoveryAgent(agentBuilder); } @@ -133,6 +148,12 @@ public MockPeerDiscoveryAgent startDiscoveryAgent(final DiscoveryPeer... bootstr return startDiscoveryAgent(agentBuilder); } + public MockPeerDiscoveryAgent startDiscoveryAgent(final Clock clock) { + final AgentBuilder agentBuilder = agentBuilder().bootstrapPeers(List.of()).clock(clock); + + return startDiscoveryAgent(agentBuilder); + } + /** * Start a single discovery agent with the provided bootstrap peers. * @@ -141,9 +162,11 @@ public MockPeerDiscoveryAgent startDiscoveryAgent(final DiscoveryPeer... bootstr * @return a list of discovery agents. */ public MockPeerDiscoveryAgent startDiscoveryAgent( - final List bootstrapPeers, final PeerPermissions peerPermissions) { + final List bootstrapPeers, + final PeerPermissions peerPermissions, + final Clock clock) { final AgentBuilder agentBuilder = - agentBuilder().bootstrapPeers(bootstrapPeers).peerPermissions(peerPermissions); + agentBuilder().bootstrapPeers(bootstrapPeers).peerPermissions(peerPermissions).clock(clock); return startDiscoveryAgent(agentBuilder); } @@ -154,8 +177,9 @@ public MockPeerDiscoveryAgent startDiscoveryAgent(final AgentBuilder agentBuilde return agent; } - public MockPeerDiscoveryAgent createDiscoveryAgent(final List bootstrapPeers) { - final AgentBuilder agentBuilder = agentBuilder().bootstrapPeers(bootstrapPeers); + public MockPeerDiscoveryAgent createDiscoveryAgent( + final List bootstrapPeers, final Clock clock) { + final AgentBuilder agentBuilder = agentBuilder().bootstrapPeers(bootstrapPeers).clock(clock); return createDiscoveryAgent(agentBuilder); } @@ -179,6 +203,7 @@ public static class AgentBuilder { private List bootnodes = Collections.emptyList(); private boolean active = true; private PeerPermissions peerPermissions = PeerPermissions.noop(); + private Clock clock = TestClock.fixed(); private AgentBuilder( final Map agents, @@ -215,6 +240,11 @@ public AgentBuilder active(final boolean active) { return this; } + public AgentBuilder clock(final Clock clock) { + this.clock = clock; + return this; + } + public MockPeerDiscoveryAgent build() { final DiscoveryConfiguration config = new DiscoveryConfiguration(); config.setBootnodes(bootnodes); @@ -222,7 +252,7 @@ public MockPeerDiscoveryAgent build() { config.setActive(active); return new MockPeerDiscoveryAgent( - SECP256K1.KeyPair.generate(), config, peerPermissions, agents); + SECP256K1.KeyPair.generate(), config, peerPermissions, agents, clock); } } } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java index 4206fb96353..89e70e36125 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java @@ -26,6 +26,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PeerTable; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PingPacketData; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.Subscribers; import java.util.Collections; @@ -38,6 +39,7 @@ public class PeerDiscoveryTimestampsTest { private final PeerDiscoveryTestHelper helper = new PeerDiscoveryTestHelper(); + private final TestClock testClock = new TestClock(); @Test public void lastSeenAndFirstDiscoveredTimestampsUpdatedOnMessage() { @@ -60,11 +62,14 @@ public void lastSeenAndFirstDiscoveredTimestampsUpdatedOnMessage() { .tableRefreshIntervalMs(TimeUnit.HOURS.toMillis(1)) .peerBondedObservers(Subscribers.create()) .metricsSystem(new NoOpMetricsSystem()) + .clock(testClock) .build(); controller.start(); + testClock.stepMillis(1_000); final PingPacketData ping = - PingPacketData.create(peers.get(1).getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + peers.get(1).getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet packet = Packet.create(PacketType.PING, ping, keypairs.get(1)); controller.onMessage(packet, peers.get(1)); @@ -74,6 +79,7 @@ public void lastSeenAndFirstDiscoveredTimestampsUpdatedOnMessage() { assertThat(controller.streamDiscoveredPeers()).hasSize(1); + testClock.stepMillis(1_000); DiscoveryPeer p = controller.streamDiscoveredPeers().iterator().next(); assertThat(p.getLastSeen()).isGreaterThan(0); assertThat(p.getFirstDiscovered()).isGreaterThan(0); @@ -81,6 +87,7 @@ public void lastSeenAndFirstDiscoveredTimestampsUpdatedOnMessage() { lastSeen.set(p.getLastSeen()); firstDiscovered.set(p.getFirstDiscovered()); + testClock.stepMillis(1_000); controller.onMessage(packet, peers.get(1)); assertThat(controller.streamDiscoveredPeers()).hasSize(1); @@ -92,11 +99,12 @@ public void lastSeenAndFirstDiscoveredTimestampsUpdatedOnMessage() { @Test public void lastContactedTimestampUpdatedOnOutboundMessage() { - final MockPeerDiscoveryAgent agent = helper.startDiscoveryAgent(Collections.emptyList()); + final MockPeerDiscoveryAgent agent = + helper.startDiscoveryAgent(Collections.emptyList(), testClock); assertThat(agent.streamDiscoveredPeers()).hasSize(0); // Start a test peer and send a PING packet to the agent under test. - final MockPeerDiscoveryAgent testAgent = helper.startDiscoveryAgent(); + final MockPeerDiscoveryAgent testAgent = helper.startDiscoveryAgent(testClock); final Packet ping = helper.createPingPacket(testAgent, agent); helper.sendMessageBetweenAgents(testAgent, agent, ping); @@ -120,6 +128,7 @@ public void lastContactedTimestampUpdatedOnOutboundMessage() { firstDiscovered.set(fd); // Send another packet and ensure that timestamps are updated accordingly. + testClock.stepMillis(1_000); helper.sendMessageBetweenAgents(testAgent, agent, ping); peer = agent.streamDiscoveredPeers().iterator().next(); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/FindNeighborsPacketDataTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/FindNeighborsPacketDataTest.java index 9d58ca24df0..3a7831aedbe 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/FindNeighborsPacketDataTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/FindNeighborsPacketDataTest.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput; import tech.pegasys.pantheon.ethereum.rlp.RLP; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import org.junit.Test; @@ -24,10 +25,11 @@ public class FindNeighborsPacketDataTest { @Test public void serializeDeserialize() { - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final BytesValue target = Peer.randomId(); - final FindNeighborsPacketData packet = FindNeighborsPacketData.create(target); + final FindNeighborsPacketData packet = + FindNeighborsPacketData.create(target, TestClock.fixed()); final BytesValue serialized = RLP.encode(packet::writeTo); final FindNeighborsPacketData deserialized = FindNeighborsPacketData.readFrom(RLP.input(serialized)); @@ -38,7 +40,7 @@ public void serializeDeserialize() { @Test public void readFrom() { - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final BytesValue target = Peer.randomId(); BytesValueRLPOutput out = new BytesValueRLPOutput(); @@ -56,7 +58,7 @@ public void readFrom() { @Test public void readFrom_withExtraFields() { - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final BytesValue target = Peer.randomId(); BytesValueRLPOutput out = new BytesValueRLPOutput(); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPacketDataFactory.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPacketDataFactory.java index 230b9ff88c1..85655130248 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPacketDataFactory.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPacketDataFactory.java @@ -18,6 +18,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.DiscoveryPeer; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.Bytes32; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -30,7 +31,8 @@ public static Packet mockNeighborsPacket( final DiscoveryPeer from, final DiscoveryPeer... neighbors) { final Packet packet = mock(Packet.class); - final NeighborsPacketData packetData = NeighborsPacketData.create(Arrays.asList(neighbors)); + final NeighborsPacketData packetData = + NeighborsPacketData.create(Arrays.asList(neighbors), TestClock.fixed()); when(packet.getPacketData(any())).thenReturn(Optional.of(packetData)); final BytesValue id = from.getId(); @@ -44,7 +46,8 @@ public static Packet mockNeighborsPacket( public static Packet mockPongPacket(final DiscoveryPeer from, final BytesValue pingHash) { final Packet packet = mock(Packet.class); - final PongPacketData pongPacketData = PongPacketData.create(from.getEndpoint(), pingHash); + final PongPacketData pongPacketData = + PongPacketData.create(from.getEndpoint(), pingHash, TestClock.fixed()); when(packet.getPacketData(any())).thenReturn(Optional.of(pongPacketData)); final BytesValue id = from.getId(); when(packet.getNodeId()).thenReturn(id); @@ -60,7 +63,8 @@ public static Packet mockFindNeighborsPacket(final Peer from) { BytesValue.fromHexString( "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40"); - final FindNeighborsPacketData packetData = FindNeighborsPacketData.create(target); + final FindNeighborsPacketData packetData = + FindNeighborsPacketData.create(target, TestClock.fixed()); when(packet.getPacketData(any())).thenReturn(Optional.of(packetData)); final BytesValue id = from.getId(); when(packet.getNodeId()).thenReturn(id); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java index 09f9be1312c..8452a8bc982 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java @@ -22,6 +22,7 @@ import tech.pegasys.pantheon.util.bytes.BytesValue; import java.net.InetSocketAddress; +import java.time.Clock; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Deque; @@ -39,8 +40,9 @@ public MockPeerDiscoveryAgent( final KeyPair keyPair, final DiscoveryConfiguration config, final PeerPermissions peerPermissions, - final Map agentNetwork) { - super(keyPair, config, peerPermissions, Optional.empty(), new NoOpMetricsSystem()); + final Map agentNetwork, + final Clock clock) { + super(keyPair, config, peerPermissions, Optional.empty(), new NoOpMetricsSystem(), clock); this.agentNetwork = agentNetwork; } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/NeighborsPacketDataTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/NeighborsPacketDataTest.java index 996055131b8..cd8d4665c7d 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/NeighborsPacketDataTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/NeighborsPacketDataTest.java @@ -18,6 +18,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.DiscoveryPeer; import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput; import tech.pegasys.pantheon.ethereum.rlp.RLP; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.Arrays; @@ -29,11 +30,11 @@ public class NeighborsPacketDataTest { @Test public void serializeDeserialize() { - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final List peers = Arrays.asList(DiscoveryPeer.fromEnode(enode()), DiscoveryPeer.fromEnode(enode())); - final NeighborsPacketData packet = NeighborsPacketData.create(peers); + final NeighborsPacketData packet = NeighborsPacketData.create(peers, TestClock.fixed()); final BytesValue serialized = RLP.encode(packet::writeTo); final NeighborsPacketData deserialized = NeighborsPacketData.readFrom(RLP.input(serialized)); @@ -43,7 +44,7 @@ public void serializeDeserialize() { @Test public void readFrom() { - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final List peers = Arrays.asList(DiscoveryPeer.fromEnode(enode()), DiscoveryPeer.fromEnode(enode())); @@ -61,7 +62,7 @@ public void readFrom() { @Test public void readFrom_extraFields() { - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final List peers = Arrays.asList(DiscoveryPeer.fromEnode(enode()), DiscoveryPeer.fromEnode(enode())); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java index 59e06536993..7b3cfc30d90 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java @@ -41,6 +41,7 @@ import tech.pegasys.pantheon.ethereum.p2p.permissions.PeerPermissions.Action; import tech.pegasys.pantheon.ethereum.p2p.permissions.PeerPermissionsBlacklist; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.bytes.Bytes32; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -113,7 +114,8 @@ public void bootstrapPeersRetriesSent() { // Mock the creation of the PING packet, so that we can control the hash, // which gets validated when receiving the PONG. final PingPacketData mockPing = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet mockPacket = Packet.create(PacketType.PING, mockPing, keyPairs.get(0)); mockPingPacketCreation(mockPacket); @@ -183,7 +185,8 @@ public void bootstrapPeersRetriesStoppedUponResponse() { // Mock the creation of the PING packet, so that we can control the hash, // which gets validated when receiving the PONG. final PingPacketData mockPing = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet mockPacket = Packet.create(PacketType.PING, mockPing, keyPairs.get(0)); mockPingPacketCreation(mockPacket); @@ -201,7 +204,7 @@ public void bootstrapPeersRetriesStoppedUponResponse() { // Simulate a PONG message from peer 0. final PongPacketData packetData = - PongPacketData.create(localPeer.getEndpoint(), mockPacket.getHash()); + PongPacketData.create(localPeer.getEndpoint(), mockPacket.getHash(), TestClock.fixed()); final Packet packet = Packet.create(PacketType.PONG, packetData, keyPairs.get(0)); controller.onMessage(packet, peers.get(0)); @@ -237,7 +240,8 @@ public void shouldStopRetryingInteractionWhenLimitIsReached() { // Mock the creation of the PING packet, so that we can control the hash, // which gets validated when receiving the PONG. final PingPacketData mockPing = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet mockPacket = Packet.create(PacketType.PING, mockPing, keyPairs.get(0)); mockPingPacketCreation(mockPacket); @@ -272,7 +276,8 @@ public void bootstrapPeersPongReceived_HashMatched() { // Mock the creation of the PING packet, so that we can control the hash, which gets validated // when receiving the PONG. final PingPacketData mockPing = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet mockPacket = Packet.create(PacketType.PING, mockPing, keyPairs.get(0)); mockPingPacketCreation(mockPacket); @@ -287,7 +292,7 @@ public void bootstrapPeersPongReceived_HashMatched() { // Simulate PONG messages from all peers for (int i = 0; i < 3; i++) { final PongPacketData packetData = - PongPacketData.create(localPeer.getEndpoint(), mockPacket.getHash()); + PongPacketData.create(localPeer.getEndpoint(), mockPacket.getHash(), TestClock.fixed()); final Packet packet0 = Packet.create(PacketType.PONG, packetData, keyPairs.get(i)); controller.onMessage(packet0, peers.get(i)); } @@ -332,7 +337,8 @@ public void bootstrapPeersPongReceived_HashUnmatched() { // when // processing the PONG. final PingPacketData mockPing = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet mockPacket = Packet.create(PacketType.PING, mockPing, keyPairs.get(0)); mockPingPacketCreation(mockPacket); @@ -346,7 +352,8 @@ public void bootstrapPeersPongReceived_HashUnmatched() { // Send a PONG packet from peer 1, with an incorrect hash. final PongPacketData packetData = - PongPacketData.create(localPeer.getEndpoint(), BytesValue.fromHexString("1212")); + PongPacketData.create( + localPeer.getEndpoint(), BytesValue.fromHexString("1212"), TestClock.fixed()); final Packet packet = Packet.create(PacketType.PONG, packetData, keyPairs.get(1)); controller.onMessage(packet, peers.get(1)); @@ -381,7 +388,8 @@ public void findNeighborsSentAfterBondingFinished() { // when // processing the PONG. final PingPacketData mockPing = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet mockPacket = Packet.create(PacketType.PING, mockPing, keyPairs.get(0)); mockPingPacketCreation(mockPacket); controller.setRetryDelayFunction((prev) -> 999999999L); @@ -423,7 +431,8 @@ private ControllerBuilder getControllerBuilder() { private void respondWithPong( final DiscoveryPeer discoveryPeer, final KeyPair keyPair, final BytesValue hash) { - final PongPacketData packetData0 = PongPacketData.create(localPeer.getEndpoint(), hash); + final PongPacketData packetData0 = + PongPacketData.create(localPeer.getEndpoint(), hash, TestClock.fixed()); final Packet pongPacket0 = Packet.create(PacketType.PONG, packetData0, keyPair); controller.onMessage(pongPacket0, discoveryPeer); } @@ -445,7 +454,8 @@ public void peerSeenTwice() throws InterruptedException { // Mock the creation of the PING packet, so that we can control the hash, which gets validated // when processing the PONG. final PingPacketData pingPacketData = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet pingPacket = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPingPacketCreation(pingPacket); @@ -471,7 +481,7 @@ public void peerSeenTwice() throws InterruptedException { .hasSize(1); final PongPacketData pongPacketData = - PongPacketData.create(localPeer.getEndpoint(), pingPacket.getHash()); + PongPacketData.create(localPeer.getEndpoint(), pingPacket.getHash(), TestClock.fixed()); final Packet pongPacket = Packet.create(PacketType.PONG, pongPacketData, keyPairs.get(1)); controller.onMessage(pongPacket, peers.get(1)); @@ -481,7 +491,7 @@ public void peerSeenTwice() throws InterruptedException { // Simulate a NEIGHBORS message from peer[0] listing peer[2]. final NeighborsPacketData neighbors0 = - NeighborsPacketData.create(Collections.singletonList(peers.get(2))); + NeighborsPacketData.create(Collections.singletonList(peers.get(2)), TestClock.fixed()); final Packet neighborsPacket0 = Packet.create(PacketType.NEIGHBORS, neighbors0, keyPairs.get(0)); controller.onMessage(neighborsPacket0, peers.get(0)); @@ -495,7 +505,7 @@ public void peerSeenTwice() throws InterruptedException { // Simulate bonding and neighbors packet from the second bootstrap peer, with peer[2] reported // in the peer list. final NeighborsPacketData neighbors1 = - NeighborsPacketData.create(Collections.singletonList(peers.get(2))); + NeighborsPacketData.create(Collections.singletonList(peers.get(2)), TestClock.fixed()); final Packet neighborsPacket1 = Packet.create(PacketType.NEIGHBORS, neighbors1, keyPairs.get(1)); controller.onMessage(neighborsPacket1, peers.get(1)); @@ -505,7 +515,7 @@ public void peerSeenTwice() throws InterruptedException { // Send a PONG packet from peer[2], to transition it to the BONDED state. final PongPacketData packetData2 = - PongPacketData.create(localPeer.getEndpoint(), pingPacket.getHash()); + PongPacketData.create(localPeer.getEndpoint(), pingPacket.getHash(), TestClock.fixed()); final Packet pongPacket2 = Packet.create(PacketType.PONG, packetData2, keyPairs.get(2)); controller.onMessage(pongPacket2, peers.get(2)); @@ -605,7 +615,8 @@ public void shouldNotAddNewPeerWhenReceivedPongFromBlacklistedPeer() { // Setup ping to be sent to discoPeer List keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); - PingPacketData pingPacketData = PingPacketData.create(localEndpoint, discoPeer.getEndpoint()); + PingPacketData pingPacketData = + PingPacketData.create(localEndpoint, discoPeer.getEndpoint(), TestClock.fixed()); final Packet discoPeerPing = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, discoPeer, discoPeerPing); @@ -622,13 +633,15 @@ public void shouldNotAddNewPeerWhenReceivedPongFromBlacklistedPeer() { // Setup ping to be sent to otherPeer after neighbors packet is received keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); - pingPacketData = PingPacketData.create(localEndpoint, otherPeer.getEndpoint()); + pingPacketData = + PingPacketData.create(localEndpoint, otherPeer.getEndpoint(), TestClock.fixed()); final Packet pingPacket = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, otherPeer, pingPacket); // Setup ping to be sent to otherPeer2 after neighbors packet is received keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); - pingPacketData = PingPacketData.create(localEndpoint, otherPeer2.getEndpoint()); + pingPacketData = + PingPacketData.create(localEndpoint, otherPeer2.getEndpoint(), TestClock.fixed()); final Packet pingPacket2 = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, otherPeer2, pingPacket2); @@ -683,7 +696,8 @@ public void shouldNotBondWithBlacklistedPeer() { // Setup ping to be sent to discoPeer List keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); - PingPacketData pingPacketData = PingPacketData.create(localEndpoint, discoPeer.getEndpoint()); + PingPacketData pingPacketData = + PingPacketData.create(localEndpoint, discoPeer.getEndpoint(), TestClock.fixed()); final Packet discoPeerPing = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, discoPeer, discoPeerPing); @@ -699,13 +713,15 @@ public void shouldNotBondWithBlacklistedPeer() { // Setup ping to be sent to otherPeer after neighbors packet is received keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); - pingPacketData = PingPacketData.create(localEndpoint, otherPeer.getEndpoint()); + pingPacketData = + PingPacketData.create(localEndpoint, otherPeer.getEndpoint(), TestClock.fixed()); final Packet pingPacket = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, otherPeer, pingPacket); // Setup ping to be sent to otherPeer2 after neighbors packet is received keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); - pingPacketData = PingPacketData.create(localEndpoint, otherPeer2.getEndpoint()); + pingPacketData = + PingPacketData.create(localEndpoint, otherPeer2.getEndpoint(), TestClock.fixed()); final Packet pingPacket2 = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, otherPeer2, pingPacket2); @@ -738,7 +754,7 @@ public void shouldRespondToNeighborsRequestFromKnownPeer() { // Setup ping to be sent to discoPeer final List keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); final PingPacketData pingPacketData = - PingPacketData.create(localEndpoint, discoPeer.getEndpoint()); + PingPacketData.create(localEndpoint, discoPeer.getEndpoint(), TestClock.fixed()); final Packet discoPeerPing = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, discoPeer, discoPeerPing); @@ -778,7 +794,7 @@ public void shouldNotRespondToNeighborsRequestFromUnknownPeer() { // Setup ping to be sent to discoPeer final List keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); final PingPacketData pingPacketData = - PingPacketData.create(localEndpoint, discoPeer.getEndpoint()); + PingPacketData.create(localEndpoint, discoPeer.getEndpoint(), TestClock.fixed()); final Packet discoPeerPing = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, discoPeer, discoPeerPing); @@ -819,7 +835,7 @@ public void shouldNotRespondToNeighborsRequestFromBlacklistedPeer() { // Setup ping to be sent to discoPeer final List keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); final PingPacketData pingPacketData = - PingPacketData.create(localEndpoint, discoPeer.getEndpoint()); + PingPacketData.create(localEndpoint, discoPeer.getEndpoint(), TestClock.fixed()); final Packet discoPeerPing = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPacketCreation(PacketType.PING, discoPeer, discoPeerPing); @@ -848,7 +864,8 @@ public void shouldAddNewPeerWhenReceivedPongAndPeerTableBucketIsNotFull() { // Mock the creation of the PING packet to control hash for PONG. final List keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); final PingPacketData pingPacketData = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet pingPacket = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); final OutboundMessageHandler outboundMessageHandler = mock(OutboundMessageHandler.class); @@ -887,7 +904,8 @@ public void shouldAddNewPeerWhenReceivedPongAndPeerTableBucketIsFull() { // Mock the creation of PING packets to control hash PONG packets. final List keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); final PingPacketData pingPacketData = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet pingPacket = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); mockPingPacketCreation(pingPacket); @@ -946,7 +964,8 @@ public void shouldNotAddPeerInNeighborsPacketWithoutBonding() { // Mock the creation of the PING packet to control hash for PONG. final List keyPairs = PeerDiscoveryTestHelper.generateKeyPairs(1); final PingPacketData pingPacketData = - PingPacketData.create(localPeer.getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + localPeer.getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet pingPacket = Packet.create(PacketType.PING, pingPacketData, keyPairs.get(0)); final OutboundMessageHandler outboundMessageHandler = mock(OutboundMessageHandler.class); @@ -1177,7 +1196,7 @@ private static Packet mockPingPacket(final DiscoveryPeer from, final DiscoveryPe final Packet packet = mock(Packet.class); final PingPacketData pingPacketData = - PingPacketData.create(from.getEndpoint(), to.getEndpoint()); + PingPacketData.create(from.getEndpoint(), to.getEndpoint(), TestClock.fixed()); when(packet.getPacketData(any())).thenReturn(Optional.of(pingPacketData)); final BytesValue id = from.getId(); when(packet.getNodeId()).thenReturn(id); @@ -1309,6 +1328,7 @@ PeerDiscoveryController build() { .peerPermissions(peerPermissions) .peerBondedObservers(peerBondedObservers) .metricsSystem(new NoOpMetricsSystem()) + .clock(TestClock.fixed()) .build()); } } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java index 7a9d7f79e4b..b78f207c82f 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryStatus; import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryTestHelper; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -62,12 +63,14 @@ public void tableRefreshSingleNode() { .tableRefreshIntervalMs(0) .peerBondedObservers(Subscribers.create()) .metricsSystem(new NoOpMetricsSystem()) + .clock(TestClock.fixed()) .build()); controller.start(); // Send a PING, so as to add a Peer in the controller. final PingPacketData ping = - PingPacketData.create(peers.get(1).getEndpoint(), peers.get(0).getEndpoint()); + PingPacketData.create( + peers.get(1).getEndpoint(), peers.get(0).getEndpoint(), TestClock.fixed()); final Packet pingPacket = Packet.create(PacketType.PING, ping, keypairs.get(1)); controller.onMessage(pingPacket, peers.get(1)); @@ -76,7 +79,7 @@ public void tableRefreshSingleNode() { // Simulate a PONG message from peer 0. final PongPacketData pongPacketData = - PongPacketData.create(localPeer.getEndpoint(), pingPacket.getHash()); + PongPacketData.create(localPeer.getEndpoint(), pingPacket.getHash(), TestClock.fixed()); final Packet pongPacket = Packet.create(PacketType.PONG, pongPacketData, keypairs.get(0)); final ArgumentCaptor captor = ArgumentCaptor.forClass(Packet.class); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PingPacketDataTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PingPacketDataTest.java index 4672717b072..28f937d12ab 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PingPacketDataTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PingPacketDataTest.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.Endpoint; import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput; import tech.pegasys.pantheon.ethereum.rlp.RLP; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.OptionalInt; @@ -27,11 +28,11 @@ public class PingPacketDataTest { @Test public void serializeDeserialize() { - final long currentTime = System.currentTimeMillis(); + final long currentTime = TestClock.fixed().millis(); final Endpoint from = new Endpoint("127.0.0.1", 30303, OptionalInt.of(30303)); final Endpoint to = new Endpoint("127.0.0.2", 30303, OptionalInt.empty()); - final PingPacketData packet = PingPacketData.create(from, to); + final PingPacketData packet = PingPacketData.create(from, to, TestClock.fixed()); final BytesValue serialized = RLP.encode(packet::writeTo); final PingPacketData deserialized = PingPacketData.readFrom(RLP.input(serialized)); @@ -45,7 +46,7 @@ public void readFrom() { final int version = 4; final Endpoint from = new Endpoint("127.0.0.1", 30303, OptionalInt.of(30303)); final Endpoint to = new Endpoint("127.0.0.2", 30303, OptionalInt.empty()); - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final BytesValueRLPOutput out = new BytesValueRLPOutput(); out.startList(); @@ -68,7 +69,7 @@ public void readFrom_withExtraFields() { final int version = 4; final Endpoint from = new Endpoint("127.0.0.1", 30303, OptionalInt.of(30303)); final Endpoint to = new Endpoint("127.0.0.2", 30303, OptionalInt.empty()); - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final BytesValueRLPOutput out = new BytesValueRLPOutput(); out.startList(); @@ -93,7 +94,7 @@ public void readFrom_unknownVersion() { final int version = 99; final Endpoint from = new Endpoint("127.0.0.1", 30303, OptionalInt.of(30303)); final Endpoint to = new Endpoint("127.0.0.2", 30303, OptionalInt.empty()); - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final BytesValueRLPOutput out = new BytesValueRLPOutput(); out.startList(); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PongPacketDataTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PongPacketDataTest.java index 172db39c6b7..6b5d5095632 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PongPacketDataTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PongPacketDataTest.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.Endpoint; import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput; import tech.pegasys.pantheon.ethereum.rlp.RLP; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.Bytes32; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -28,11 +29,11 @@ public class PongPacketDataTest { @Test public void serializeDeserialize() { - final long currentTime = System.currentTimeMillis(); + final long currentTime = TestClock.fixed().millis(); final Endpoint to = new Endpoint("127.0.0.2", 30303, OptionalInt.empty()); final Bytes32 hash = Bytes32.fromHexStringLenient("0x1234"); - final PongPacketData packet = PongPacketData.create(to, hash); + final PongPacketData packet = PongPacketData.create(to, hash, TestClock.fixed()); final BytesValue serialized = RLP.encode(packet::writeTo); final PongPacketData deserialized = PongPacketData.readFrom(RLP.input(serialized)); @@ -43,7 +44,7 @@ public void serializeDeserialize() { @Test public void readFrom() { - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final Endpoint to = new Endpoint("127.0.0.2", 30303, OptionalInt.empty()); final Bytes32 hash = Bytes32.fromHexStringLenient("0x1234"); @@ -63,7 +64,7 @@ public void readFrom() { @Test public void readFrom_withExtraFields() { - final long time = System.currentTimeMillis(); + final long time = TestClock.fixed().millis(); final Endpoint to = new Endpoint("127.0.0.2", 30303, OptionalInt.empty()); final Bytes32 hash = Bytes32.fromHexStringLenient("0x1234"); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/DefaultP2PNetworkTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/DefaultP2PNetworkTest.java index d4ccace2604..51972270dce 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/DefaultP2PNetworkTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/DefaultP2PNetworkTest.java @@ -44,6 +44,7 @@ import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.nat.upnp.UpnpNatManager; import tech.pegasys.pantheon.nat.upnp.UpnpNatManager.Protocol; +import tech.pegasys.pantheon.testutil.TestClock; import java.util.ArrayList; import java.util.List; @@ -215,7 +216,7 @@ public void start_withNatManager() { when(natManager.queryExternalIPAddress()) .thenReturn(CompletableFuture.completedFuture(externalIp)); - final P2PNetwork network = builder().natManager(natManager).build(); + final P2PNetwork network = builder().natManager(natManager).clock(TestClock.fixed()).build(); network.start(); verify(natManager) @@ -231,7 +232,7 @@ public void handlePeerBondedEvent_forListeningPeer() { final DefaultP2PNetwork network = network(); network.start(); final DiscoveryPeer peer = DiscoveryPeer.fromEnode(enode()); - final PeerBondedEvent peerBondedEvent = new PeerBondedEvent(peer, System.currentTimeMillis()); + final PeerBondedEvent peerBondedEvent = new PeerBondedEvent(peer, TestClock.fixed().millis()); discoverySubscriberCaptor.getValue().onPeerBonded(peerBondedEvent); verify(rlpxAgent, times(1)).connect(peer); @@ -244,7 +245,7 @@ public void handlePeerBondedEvent_forPeerWithNoTcpPort() { final DiscoveryPeer peer = DiscoveryPeer.fromIdAndEndpoint( Peer.randomId(), new Endpoint("127.0.0.1", 999, OptionalInt.empty())); - final PeerBondedEvent peerBondedEvent = new PeerBondedEvent(peer, System.currentTimeMillis()); + final PeerBondedEvent peerBondedEvent = new PeerBondedEvent(peer, TestClock.fixed().millis()); discoverySubscriberCaptor.getValue().onPeerBonded(peerBondedEvent); verify(rlpxAgent, times(1)).connect(peer); @@ -305,7 +306,7 @@ public void attemptPeerConnections_sortsPeersByLastContacted() { } private DefaultP2PNetwork network() { - return (DefaultP2PNetwork) builder().build(); + return (DefaultP2PNetwork) builder().clock(TestClock.fixed()).build(); } private DefaultP2PNetwork.Builder builder() { diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/NetworkingServiceLifecycleTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/NetworkingServiceLifecycleTest.java index 194aa97ab16..17aad220d0b 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/NetworkingServiceLifecycleTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/NetworkingServiceLifecycleTest.java @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.EnodeURL; import tech.pegasys.pantheon.ethereum.p2p.rlpx.wire.Capability; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import java.io.IOException; import java.util.Arrays; @@ -157,6 +158,7 @@ private DefaultP2PNetwork.Builder builder() { .keyPair(keyPair) .config(config) .metricsSystem(new NoOpMetricsSystem()) + .clock(TestClock.fixed()) .supportedCapabilities(Arrays.asList(Capability.create("eth", 63))); } } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/P2PNetworkTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/P2PNetworkTest.java index 6af15bc8063..205b70a44e6 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/P2PNetworkTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/network/P2PNetworkTest.java @@ -36,6 +36,7 @@ import tech.pegasys.pantheon.ethereum.p2p.rlpx.wire.SubProtocol; import tech.pegasys.pantheon.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.net.InetAddress; @@ -326,6 +327,7 @@ private DefaultP2PNetwork.Builder builder() { .config(config) .keyPair(KeyPair.generate()) .metricsSystem(new NoOpMetricsSystem()) + .clock(TestClock.fixed()) .supportedCapabilities(Arrays.asList(Capability.create("eth", 63))); } } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/RlpxAgentTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/RlpxAgentTest.java index 6dd972d23a5..778fa6fe41d 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/RlpxAgentTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/RlpxAgentTest.java @@ -49,6 +49,7 @@ import tech.pegasys.pantheon.ethereum.p2p.rlpx.wire.messages.PingMessage; import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.Arrays; @@ -971,6 +972,7 @@ private RlpxAgent agent() { .peerPrivileges(peerPrivileges) .localNode(localNode) .metricsSystem(metrics) + .clock(TestClock.fixed()) .connectionInitializer(connectionInitializer) .connectionEvents(peerConnectionEvents) .build(); diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/RlpxConnectionTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/RlpxConnectionTest.java index dceff248ea7..4f76186a60c 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/RlpxConnectionTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/rlpx/connections/RlpxConnectionTest.java @@ -21,6 +21,7 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.p2p.rlpx.connections.RlpxConnection.ConnectionNotEstablishedException; import tech.pegasys.pantheon.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; +import tech.pegasys.pantheon.testutil.TestClock; import java.util.concurrent.CompletableFuture; @@ -32,7 +33,8 @@ public class RlpxConnectionTest { public void getPeer_pendingOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); assertThat(conn.getPeer()).isEqualTo(peer); } @@ -41,7 +43,8 @@ public void getPeer_pendingOutboundConnection() { public void getPeer_establishedOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); future.complete(peerConnection(peer)); assertThat(conn.getPeer()).isEqualTo(peer); @@ -51,7 +54,8 @@ public void getPeer_establishedOutboundConnection() { public void getPeer_inboundConnection() { final Peer peer = createPeer(); final PeerConnection peerConnection = peerConnection(peer); - final RlpxConnection conn = RlpxConnection.inboundConnection(peerConnection); + final RlpxConnection conn = + RlpxConnection.inboundConnection(peerConnection, TestClock.fixed().millis()); assertThat(conn.getPeer()).isEqualTo(peer); } @@ -60,7 +64,8 @@ public void getPeer_inboundConnection() { public void disconnect_pendingOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); final DisconnectReason reason = DisconnectReason.REQUESTED; conn.disconnect(reason); @@ -79,7 +84,8 @@ public void disconnect_pendingOutboundConnection() { public void disconnect_activeOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); final PeerConnection peerConnection = peerConnection(peer); future.complete(peerConnection); @@ -95,7 +101,8 @@ public void disconnect_activeOutboundConnection() { public void disconnect_failedOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); future.completeExceptionally(new IllegalStateException("whoops")); assertThat(conn.isFailedOrDisconnected()).isTrue(); @@ -108,7 +115,8 @@ public void disconnect_failedOutboundConnection() { public void disconnect_inboundConnection() { final Peer peer = createPeer(); final PeerConnection peerConnection = peerConnection(peer); - final RlpxConnection conn = RlpxConnection.inboundConnection(peerConnection); + final RlpxConnection conn = + RlpxConnection.inboundConnection(peerConnection, TestClock.fixed().millis()); assertThat(conn.isFailedOrDisconnected()).isFalse(); final DisconnectReason reason = DisconnectReason.REQUESTED; @@ -123,7 +131,8 @@ public void disconnect_inboundConnection() { public void getPeerConnection_pendingOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); assertThatThrownBy(conn::getPeerConnection) .isInstanceOf(ConnectionNotEstablishedException.class); @@ -133,7 +142,8 @@ public void getPeerConnection_pendingOutboundConnection() { public void getPeerConnection_activeOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); final PeerConnection peerConnection = peerConnection(peer); future.complete(peerConnection); @@ -144,7 +154,8 @@ public void getPeerConnection_activeOutboundConnection() { public void getPeerConnection_failedOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); future.completeExceptionally(new IllegalStateException("whoops")); assertThatThrownBy(conn::getPeerConnection) @@ -155,7 +166,8 @@ public void getPeerConnection_failedOutboundConnection() { public void getPeerConnection_disconnectedOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); final PeerConnection peerConnection = peerConnection(peer); future.complete(peerConnection); conn.disconnect(DisconnectReason.REQUESTED); @@ -167,7 +179,8 @@ public void getPeerConnection_disconnectedOutboundConnection() { public void getPeerConnection_activeInboundConnection() { final Peer peer = createPeer(); final PeerConnection peerConnection = peerConnection(peer); - final RlpxConnection conn = RlpxConnection.inboundConnection(peerConnection); + final RlpxConnection conn = + RlpxConnection.inboundConnection(peerConnection, TestClock.fixed().millis()); assertThat(conn.getPeerConnection()).isEqualTo(peerConnection); } @@ -176,7 +189,8 @@ public void getPeerConnection_activeInboundConnection() { public void getPeerConnection_disconnectedInboundConnection() { final Peer peer = createPeer(); final PeerConnection peerConnection = peerConnection(peer); - final RlpxConnection conn = RlpxConnection.inboundConnection(peerConnection); + final RlpxConnection conn = + RlpxConnection.inboundConnection(peerConnection, TestClock.fixed().millis()); conn.disconnect(DisconnectReason.REQUESTED); assertThat(conn.getPeerConnection()).isEqualTo(peerConnection); @@ -186,7 +200,8 @@ public void getPeerConnection_disconnectedInboundConnection() { public void checkState_pendingOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); assertThat(conn.initiatedRemotely()).isFalse(); assertThat(conn.isActive()).isFalse(); @@ -198,7 +213,8 @@ public void checkState_pendingOutboundConnection() { public void checkState_activeOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); final PeerConnection peerConnection = peerConnection(peer); future.complete(peerConnection); @@ -212,7 +228,8 @@ public void checkState_activeOutboundConnection() { public void checkState_failedOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); future.completeExceptionally(new IllegalStateException("whoops")); assertThat(conn.initiatedRemotely()).isFalse(); @@ -225,7 +242,8 @@ public void checkState_failedOutboundConnection() { public void checkState_disconnectedOutboundConnection() { final Peer peer = createPeer(); final CompletableFuture future = new CompletableFuture<>(); - final RlpxConnection conn = RlpxConnection.outboundConnection(peer, future); + final RlpxConnection conn = + RlpxConnection.outboundConnection(peer, future, TestClock.fixed().millis()); final PeerConnection peerConnection = peerConnection(peer); future.complete(peerConnection); conn.disconnect(DisconnectReason.UNKNOWN); @@ -240,7 +258,8 @@ public void checkState_disconnectedOutboundConnection() { public void checkState_activeInboundConnection() { final Peer peer = createPeer(); final PeerConnection peerConnection = peerConnection(peer); - final RlpxConnection conn = RlpxConnection.inboundConnection(peerConnection); + final RlpxConnection conn = + RlpxConnection.inboundConnection(peerConnection, TestClock.fixed().millis()); assertThat(conn.initiatedRemotely()).isTrue(); assertThat(conn.isActive()).isTrue(); @@ -252,7 +271,8 @@ public void checkState_activeInboundConnection() { public void checkState_disconnectedInboundConnection() { final Peer peer = createPeer(); final PeerConnection peerConnection = peerConnection(peer); - final RlpxConnection conn = RlpxConnection.inboundConnection(peerConnection); + final RlpxConnection conn = + RlpxConnection.inboundConnection(peerConnection, TestClock.fixed().millis()); conn.disconnect(DisconnectReason.UNKNOWN); assertThat(conn.initiatedRemotely()).isTrue(); diff --git a/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java b/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java index cb2a1c81a97..7386df05228 100644 --- a/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java @@ -35,6 +35,7 @@ import tech.pegasys.pantheon.metrics.PantheonMetricCategory; import java.io.IOException; +import java.time.Clock; import com.google.common.io.Resources; import org.junit.Test; @@ -51,7 +52,8 @@ public class NodeSmartContractPermissioningControllerTest { private NodeSmartContractPermissioningController setupController( final String resourceName, final String contractAddressString) throws IOException { - final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(Clock.systemUTC()); final String emptyContractFile = Resources.toString(this.getClass().getResource(resourceName), UTF_8); diff --git a/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java b/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java index 7d83df8375b..4d19af447ef 100644 --- a/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.math.BigInteger; +import java.time.Clock; import com.google.common.io.Resources; import org.junit.Test; @@ -55,7 +56,8 @@ public class TransactionSmartContractPermissioningControllerTest { private TransactionSmartContractPermissioningController setupController( final String resourceName, final String contractAddressString) throws IOException { - final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.create(); + final ProtocolSchedule protocolSchedule = + MainnetProtocolSchedule.create(Clock.systemUTC()); final String emptyContractFile = Resources.toString(this.getClass().getResource(resourceName), UTF_8); diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/Pantheon.java b/pantheon/src/main/java/tech/pegasys/pantheon/Pantheon.java index ce8f09bb563..129dcd0aad0 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/Pantheon.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/Pantheon.java @@ -20,6 +20,8 @@ import tech.pegasys.pantheon.util.BlockExporter; import tech.pegasys.pantheon.util.BlockImporter; +import java.time.Clock; + import org.apache.logging.log4j.Logger; import picocli.CommandLine.RunLast; @@ -40,6 +42,7 @@ public static void main(final String... args) { new RunnerBuilder(), new PantheonController.Builder(), new PantheonPluginContextImpl(), + Clock.systemUTC(), System.getenv()); pantheonCommand.parse( diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java index 1349654ed7d..2c394b42397 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java @@ -12,6 +12,8 @@ */ package tech.pegasys.pantheon; +import static com.google.common.base.Preconditions.checkNotNull; + import tech.pegasys.pantheon.cli.config.EthNetworkConfig; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; @@ -85,6 +87,7 @@ import java.io.IOException; import java.nio.file.Path; +import java.time.Clock; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -95,7 +98,6 @@ import java.util.stream.Collectors; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; import graphql.GraphQL; import io.vertx.core.Vertx; @@ -124,6 +126,7 @@ public class RunnerBuilder { private MetricsSystem metricsSystem; private Optional permissioningConfiguration = Optional.empty(); private Collection staticNodes = Collections.emptyList(); + private Clock clock; public RunnerBuilder vertx(final Vertx vertx) { this.vertx = vertx; @@ -234,9 +237,14 @@ public RunnerBuilder staticNodes(final Collection staticNodes) { return this; } - public Runner build() { + public RunnerBuilder clock(final Clock clock) { + this.clock = clock; + return this; + } - Preconditions.checkNotNull(pantheonController); + public Runner build() { + checkNotNull(pantheonController); + checkNotNull(clock); final DiscoveryConfiguration discoveryConfiguration; if (discovery) { @@ -313,6 +321,7 @@ public Runner build() { .config(networkingConfiguration) .peerPermissions(peerPermissions) .metricsSystem(metricsSystem) + .clock(clock) .supportedCapabilities(caps) .natManager(natManager) .build(); 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 76005dbdca3..51c1d9be70e 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -622,6 +622,7 @@ void setBannedNodeIds(final List values) { private Optional permissioningConfiguration; private Collection staticNodes; private PantheonController pantheonController; + private Clock clock; private final Supplier metricsSystem = Suppliers.memoize(() -> PrometheusMetricsSystem.init(metricsConfiguration())); @@ -633,6 +634,7 @@ public PantheonCommand( final RunnerBuilder runnerBuilder, final PantheonController.Builder controllerBuilderFactory, final PantheonPluginContextImpl pantheonPluginContext, + final Clock clock, final Map environment) { this.logger = logger; this.blockImporter = blockImporter; @@ -640,6 +642,7 @@ public PantheonCommand( this.runnerBuilder = runnerBuilder; this.controllerBuilderFactory = controllerBuilderFactory; this.pantheonPluginContext = pantheonPluginContext; + this.clock = clock; this.environment = environment; } @@ -883,7 +886,7 @@ public PantheonController buildController() { .nodePrivateKeyFile(nodePrivateKeyFile()) .metricsSystem(metricsSystem.get()) .privacyParameters(privacyParameters()) - .clock(Clock.systemUTC()) + .clock(clock) .isRevertReasonEnabled(isRevertReasonEnabled) .build(); } catch (final InvalidConfigurationException e) { @@ -1199,6 +1202,7 @@ private void synchronize( .metricsSystem(metricsSystem) .metricsConfiguration(metricsConfiguration) .staticNodes(staticNodes) + .clock(clock) .build(); addShutdownHook(runner); diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonControllerBuilder.java index 269b5e8427f..49f7beee545 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonControllerBuilder.java @@ -121,7 +121,11 @@ protected MiningCoordinator createMiningCoordinator( @Override protected ProtocolSchedule createProtocolSchedule() { return CliqueProtocolSchedule.create( - genesisConfig.getConfigOptions(), nodeKeys, privacyParameters, isRevertReasonEnabled); + genesisConfig.getConfigOptions(), + nodeKeys, + privacyParameters, + isRevertReasonEnabled, + clock); } @Override diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonControllerBuilder.java index 2112e811061..fa88a252c97 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonControllerBuilder.java @@ -64,7 +64,7 @@ protected MiningCoordinator createMiningCoordinator( @Override protected ProtocolSchedule createProtocolSchedule() { return IbftProtocolSchedule.create( - genesisConfig.getConfigOptions(), privacyParameters, isRevertReasonEnabled); + genesisConfig.getConfigOptions(), privacyParameters, isRevertReasonEnabled, clock); } @Override diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonControllerBuilder.java index e985947e521..9a261260cac 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonControllerBuilder.java @@ -211,7 +211,7 @@ protected MiningCoordinator createMiningCoordinator( @Override protected ProtocolSchedule createProtocolSchedule() { return IbftProtocolSchedule.create( - genesisConfig.getConfigOptions(), privacyParameters, isRevertReasonEnabled); + genesisConfig.getConfigOptions(), privacyParameters, isRevertReasonEnabled, clock); } @Override diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonControllerBuilder.java index a77f17d5d5f..e6c09d1ac2d 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonControllerBuilder.java @@ -86,6 +86,6 @@ protected Void createConsensusContext( @Override protected ProtocolSchedule createProtocolSchedule() { return MainnetProtocolSchedule.fromConfig( - genesisConfig.getConfigOptions(), privacyParameters, isRevertReasonEnabled); + genesisConfig.getConfigOptions(), privacyParameters, isRevertReasonEnabled, clock); } } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java index 8e45bd6f63b..8d59aa3bc98 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java @@ -178,6 +178,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception { .graphQLConfiguration(aheadGraphQLConfiguration) .webSocketConfiguration(aheadWebSocketConfiguration) .metricsConfiguration(aheadMetricsConfiguration) + .clock(TestClock.fixed()) .dataDir(dbAhead) .build(); try { 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 a823c88a471..1b051349d74 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java @@ -45,6 +45,7 @@ import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration; import tech.pegasys.pantheon.services.PantheonPluginContextImpl; +import tech.pegasys.pantheon.testutil.TestClock; import tech.pegasys.pantheon.util.BlockExporter; import tech.pegasys.pantheon.util.BlockImporter; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -55,6 +56,7 @@ import java.io.InputStream; import java.io.PrintStream; import java.nio.file.Path; +import java.time.Clock; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -85,6 +87,7 @@ public abstract class CommandTestAbstract { protected final ByteArrayOutputStream commandErrorOutput = new ByteArrayOutputStream(); private final PrintStream errPrintStream = new PrintStream(commandErrorOutput); + private final Clock testClock = new TestClock(); private final HashMap environment = new HashMap<>(); @Mock protected RunnerBuilder mockRunnerBuilder; @@ -178,6 +181,7 @@ public void initMocks() throws Exception { when(mockRunnerBuilder.metricsSystem(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.metricsConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.staticNodes(any())).thenReturn(mockRunnerBuilder); + when(mockRunnerBuilder.clock(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.build()).thenReturn(mockRunner); } @@ -224,6 +228,7 @@ private TestPantheonCommand parseCommand( mockControllerBuilderFactory, keyLoader, mockPantheonPluginContext, + testClock, environment); // parse using Ansi.OFF to be able to assert on non formatted output results @@ -253,6 +258,7 @@ protected KeyLoader getKeyLoader() { final PantheonController.Builder controllerBuilderFactory, final KeyLoader keyLoader, final PantheonPluginContextImpl pantheonPluginContext, + final Clock clock, final Map environment) { super( mockLogger, @@ -261,6 +267,7 @@ protected KeyLoader getKeyLoader() { mockRunnerBuilder, controllerBuilderFactory, pantheonPluginContext, + clock, environment); this.keyLoader = keyLoader; } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/cli/operator/OperatorSubCommandTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/cli/operator/OperatorSubCommandTest.java index 39f539e30bb..47b60c5541f 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/operator/OperatorSubCommandTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/operator/OperatorSubCommandTest.java @@ -13,7 +13,6 @@ package tech.pegasys.pantheon.cli.operator; import static java.lang.String.format; -import static java.lang.System.currentTimeMillis; import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.file.Files.createTempDirectory; import static java.util.Arrays.asList; @@ -28,6 +27,7 @@ import static tech.pegasys.pantheon.cli.subcommands.operator.OperatorSubCommand.GENERATE_BLOCKCHAIN_CONFIG_SUBCOMMAND_NAME; import tech.pegasys.pantheon.cli.CommandTestAbstract; +import tech.pegasys.pantheon.testutil.TestClock; import java.io.File; import java.io.IOException; @@ -70,7 +70,7 @@ public class OperatorSubCommandTest extends CommandTestAbstract { @Before public void init() throws IOException { - tmpOutputDirectoryPath = createTempDirectory(format("output-%d", currentTimeMillis())); + tmpOutputDirectoryPath = createTempDirectory(format("output-%d", TestClock.fixed().millis())); } @Test diff --git a/testutil/src/main/java/tech/pegasys/pantheon/testutil/TestClock.java b/testutil/src/main/java/tech/pegasys/pantheon/testutil/TestClock.java index 1ff18a8c823..291308047d4 100644 --- a/testutil/src/main/java/tech/pegasys/pantheon/testutil/TestClock.java +++ b/testutil/src/main/java/tech/pegasys/pantheon/testutil/TestClock.java @@ -17,14 +17,20 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.temporal.TemporalUnit; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; public class TestClock extends Clock { + + private static final Supplier fixedNow = + Suppliers.memoize(() -> Clock.fixed(Instant.now(), ZoneOffset.UTC)); + private Instant now = fixedNow.get().instant(); + public static Clock fixed() { - return Clock.fixed(Instant.ofEpochSecond(10_000_000), ZoneId.systemDefault()); + return fixedNow.get(); } - private Instant now = Instant.ofEpochSecond(24982948294L); - @Override public ZoneId getZone() { return ZoneOffset.UTC;