diff --git a/CHANGELOG.md b/CHANGELOG.md index 42947fbfffc..872d24eceff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,29 +1,17 @@ # Changelog -## 23.1.0 -Besu 23.1.0 is a recommended update for Mainnet users. Thank you all for your patience as we crafted this quarterly release. - -This is a rather large release with some breaking changes, so please be sure to read these notes carefully before you upgrade any Besu instances. We are including a move to Java 17 LTS. To build and run Besu, please make sure you have Java 17 on the host machine. Additionally, there are a host of spec compliance changes that change existing formats, so please check the specific RPC updates. Lastly, this release formalizes a deprecation notice for GoQuorum privacy modes and IBFT1.0 in Besu. These will be removed in the 23.4 series, unless otherwise stated. - -From the improvements and fixes side, we have a host of execution performance improvements and fixes for defects with bonsai storage. We have also included an error detection and auto-heal capability for nodes that encounter state issues. This should keep nodes online and validating that may have previously required a resync. - -One final note. 23.1.0 is not a Shanghai ready release. If you intend to test Besu on the long-lived testnets like Zhejiang, please follow the instructions here. We will have more to share on our official Shanghai releases soon. +## 23.1.0-RC2 ### Breaking Changes +- Add a new CLI option to limit the number of requests in a single RPC batch request. Default=1 [#4965](https://github.com/hyperledger/besu/pull/4965) - Change JsonRpc http service to return the error -32602 (Invalid params) with a 200 http status code - Besu requires minimum Java 17 and up to build and run [#3320](https://github.com/hyperledger/besu/issues/3320) -- PKCS11 with nss module (PKCS11 based HSM can be used in DevP2P TLS and QBFT PKI) does not work with RSA keys -in Java 17. SoftHSM is tested manually and working. (Other PKCS11 HSM are not tested). The relevant unit and acceptance +- PKCS11 with nss module (PKCS11 based HSM can be used in DevP2P TLS and QBFT PKI) does not work with RSA keys +in Java 17. SoftHSM is tested manually and working. (Other PKCS11 HSM are not tested). The relevant unit and acceptance tests are updated to use EC private keys instead of RSA keys. - Change eth_feeHistory parameter `blockCount` to accept hexadecimal string (was accepting plain integer) [#5047](https://github.com/hyperledger/besu/pull/5047) -- Default configurations for the deprecated Ropsten, Kiln, Shandong, and Astor networks have been removed from the CLI network list. These networks can currently be accessed but will require a user-provided genesis configuration. [#4869](https://github.com/hyperledger/besu/pull/4869) -- GoQuorum-compatible privacy is deprecated and will be removed in 23.4 -- IBFT 1.0 is deprecated and will be removed in 23.4 -- Optimize SSTORE Operation execution time (memoize current and original value) [#4836](https://github.com/hyperledger/besu/pull/4836) ### Additions and Improvements -- Default rpc batch request to 1000 [#5104](https://github.com/hyperledger/besu/pull/5104) -- Add a new CLI option to limit the number of requests in a single RPC batch request. [#4965](https://github.com/hyperledger/besu/pull/4965) - Support for new DATAHASH opcode as part of EIP-4844 [#4823](https://github.com/hyperledger/besu/issues/4823) - Send only hash announcement for blob transaction type [#4940](https://github.com/hyperledger/besu/pull/4940) - Add `excess_data_gas` field to block header [#4958](https://github.com/hyperledger/besu/pull/4958) @@ -32,28 +20,18 @@ tests are updated to use EC private keys instead of RSA keys. - Improve get account performance by using the world state updater cache [#4897](https://github.com/hyperledger/besu/pull/4897) - Add new KZG precompile and option to override the trusted setup being used [#4822](https://github.com/hyperledger/besu/issues/4822) - Add implementation for eth_createAccessList RPC method [#4942](https://github.com/hyperledger/besu/pull/4942) +- Add implementation for engine_exchangeCapabilities [#4997](https://github.com/hyperledger/besu/pull/4997) +- Add implementation for engine_getPayloadBodiesByRangeV1 and engine_getPayloadBodiesByHashV1 [#4980](https://github.com/hyperledger/besu/pull/4980) - Updated reference tests to v11.3 [#4996](https://github.com/hyperledger/besu/pull/4996) - Add DebugGetRawBlock and DebugGetRawHeader RPC methods [#5011](https://github.com/hyperledger/besu/pull/5011) - Besu requires minimum Java 17 and up to build and run [#3320](https://github.com/hyperledger/besu/issues/3320) - Add worldstate auto-heal mechanism [#5059](https://github.com/hyperledger/besu/pull/5059) - Support for EIP-4895 - Withdrawals for Shanghai fork -- Improve SLOAD and SSTORE performance by caching empty slots [#4874](https://github.com/hyperledger/besu/pull/4874) -- RPC methods that lookup block by hash will now return an error response if no block found [#4582](https://github.com/hyperledger/besu/pull/4582) -- Added support for `safe` and `finalized` strings for the RPC methods using defaultBlock parameter [#4902](https://github.com/hyperledger/besu/pull/4902) -- Added post-execution state logging option to EVM Tool [#4709](https://github.com/hyperledger/besu/pull/4709) -- Add access list to Transaction Call Object [#4802](https://github.com/hyperledger/besu/issues/4801) -- Add timestamp fork support, including shanghaiTime and cancunTime forks [#4743](https://github.com/hyperledger/besu/pull/4743) -- Optimization: Memoize transaction size and hash at the same time [#4812](https://github.com/hyperledger/besu/pull/4812) -- Add chain data pruning feature with three experimental CLI options: `--Xchain-pruning-enabled`, `--Xchain-pruning-blocks-retained` and `--Xchain-pruning-frequency` [#4686](https://github.com -/hyperledger/besu/pull/4686) - - Note that chain pruning is hidden and disabled by default. Once you choose to enable chain pruning, a new column family will be added to the db and you cannot roll back to a previous versi -on of Besu. +- If a PoS block creation repetition takes less than a configurable duration, then waits before next repetition [#5048](https://github.com/hyperledger/besu/pull/5048) ### Bug Fixes - Mitigation fix for stale bonsai code storage leading to log rolling issues on contract recreates [#4906](https://github.com/hyperledger/besu/pull/4906) - Ensure latest cached layered worldstate is subscribed to storage, fix problem with RPC calls using 'latest' [#5076](https://github.com/hyperledger/besu/pull/5076) -- Fix for segmentation faults on worldstate truncation, snap-sync starts [#4786](https://github.com/hyperledger/besu/pull/4786) -- Fix for worldstate mismatch on failed forkchoiceUpdate [#4862](https://github.com/hyperledger/besu/pull/4862) ## 23.1.0-RC1 diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 49fe22131a2..58cd31ffc4b 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1891,6 +1891,13 @@ private void validateMiningParams() { throw new ParameterException( this.commandLine, "--Xpos-block-creation-max-time must be positive and ≤ 12000"); } + + if (unstableMiningOptions.getPosBlockCreationRepetitionMinDuration() <= 0 + || unstableMiningOptions.getPosBlockCreationRepetitionMinDuration() > 2000) { + throw new ParameterException( + this.commandLine, + "--Xpos-block-creation-repetition-min-duration must be positive and ≤ 2000"); + } } /** @@ -2271,6 +2278,8 @@ public BesuControllerBuilder getControllerBuilder() { .powJobTimeToLive(unstableMiningOptions.getPowJobTimeToLive()) .maxOmmerDepth(unstableMiningOptions.getMaxOmmersDepth()) .posBlockCreationMaxTime(unstableMiningOptions.getPosBlockCreationMaxTime()) + .posBlockCreationRepetitionMinDuration( + unstableMiningOptions.getPosBlockCreationRepetitionMinDuration()) .build()) .transactionPoolConfiguration(buildTransactionPoolConfiguration()) .nodeKey(new NodeKey(securityModule())) @@ -3510,7 +3519,7 @@ private void validatePostMergeCheckpointBlockRequirements() { if (synchronizerConfiguration.isCheckpointPostMergeEnabled()) { if (!checkpointConfigOptions.isValid()) { throw new InvalidConfigurationException( - "Near head checkpoint sync requires a checkpoint block configured in the genesis file"); + "PoS checkpoint sync requires a checkpoint block configured in the genesis file"); } terminalTotalDifficulty.ifPresentOrElse( ttd -> { @@ -3519,18 +3528,18 @@ private void validatePostMergeCheckpointBlockRequirements() { .equals(UInt256.ZERO) && ttd.equals(UInt256.ZERO)) { throw new InvalidConfigurationException( - "Post Merge checkpoint sync can't be used with TTD = 0 and checkpoint totalDifficulty = 0"); + "PoS checkpoint sync can't be used with TTD = 0 and checkpoint totalDifficulty = 0"); } if (UInt256.fromHexString( genesisOptions.getCheckpointOptions().getTotalDifficulty().get()) - .lessOrEqualThan(ttd)) { + .lessThan(ttd)) { throw new InvalidConfigurationException( - "Near head checkpoint sync requires a block with total difficulty greater than the TTD"); + "PoS checkpoint sync requires a block with total difficulty greater or equal than the TTD"); } }, () -> { throw new InvalidConfigurationException( - "Near head checkpoint sync requires TTD in the genesis file"); + "PoS checkpoint sync requires TTD in the genesis file"); }); } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java index 926174de166..232554722e2 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java @@ -16,6 +16,7 @@ import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_MAX_OMMERS_DEPTH; import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; +import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POW_JOB_TTL; import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_LIMIT; import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_TTL; @@ -67,6 +68,15 @@ public class MiningOptions { "Specifies the maximum time, in milliseconds, a PoS block creation jobs is allowed to run. Must be positive and ≤ 12000 (default: ${DEFAULT-VALUE} milliseconds)") private final Long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; + @CommandLine.Option( + hidden = true, + names = {"--Xpos-block-creation-repetition-min-duration"}, + description = + "If a PoS block creation repetition takes less than this duration, in milliseconds," + + " then it waits before next repetition. Must be positive and ≤ 2000 (default: ${DEFAULT-VALUE} milliseconds)") + private final Long posBlockCreationRepetitionMinDuration = + DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; + /** * Create mining options. * @@ -129,4 +139,13 @@ public int getMaxOmmersDepth() { public Long getPosBlockCreationMaxTime() { return posBlockCreationMaxTime; } + + /** + * Gets pos block creation repetition min duration. + * + * @return the pos block creation repetition min duration. + */ + public Long getPosBlockCreationRepetitionMinDuration() { + return posBlockCreationRepetitionMinDuration; + } } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 6ac5ed7037e..db700e21260 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -75,6 +75,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration; import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; @@ -548,9 +549,12 @@ public BesuController build() { } } final int maxMessageSize = ethereumWireProtocolConfiguration.getMaxMessageSize(); + final Supplier currentProtocolSpecSupplier = + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()); final EthPeers ethPeers = new EthPeers( getSupportedProtocol(), + currentProtocolSpecSupplier, clock, metricsSystem, maxPeers, diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java index cf68059763c..ad382d795fc 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.controller; +import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.MergeProtocolSchedule; import org.hyperledger.besu.consensus.merge.PostMergeContext; @@ -186,19 +187,24 @@ protected MergeContext createConsensusContext( final WorldStateArchive worldStateArchive, final ProtocolSchedule protocolSchedule) { - OptionalLong terminalBlockNumber = configOptionsSupplier.get().getTerminalBlockNumber(); - Optional terminalBlockHash = configOptionsSupplier.get().getTerminalBlockHash(); + final GenesisConfigOptions genesisConfigOptions = configOptionsSupplier.get(); + final OptionalLong terminalBlockNumber = genesisConfigOptions.getTerminalBlockNumber(); + final Optional terminalBlockHash = genesisConfigOptions.getTerminalBlockHash(); + final boolean isPostMergeAtGenesis = + genesisConfigOptions.getTerminalTotalDifficulty().isPresent() + && genesisConfigOptions.getTerminalTotalDifficulty().get().isZero() + && blockchain.getGenesisBlockHeader().getDifficulty().isZero(); final MergeContext mergeContext = PostMergeContext.get() .setSyncState(syncState.get()) .setTerminalTotalDifficulty( - configOptionsSupplier - .get() + genesisConfigOptions .getTerminalTotalDifficulty() .map(Difficulty::of) .orElse(Difficulty.ZERO)) - .setCheckpointPostMergeSync(syncConfig.isCheckpointPostMergeEnabled()); + .setCheckpointPostMergeSync(syncConfig.isCheckpointPostMergeEnabled()) + .setPostMergeAtGenesis(isPostMergeAtGenesis); blockchain .getFinalized() diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java index 32518e2410c..2938088a40d 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java @@ -24,14 +24,13 @@ import org.hyperledger.besu.cli.config.NetworkName; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.consensus.merge.TransitionProtocolSchedule; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.forkid.ForkId; import org.hyperledger.besu.ethereum.forkid.ForkIdManager; -import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.evm.internal.EvmConfiguration; import java.util.Collection; import java.util.List; @@ -73,8 +72,9 @@ public static Collection parameters() { NetworkName.SEPOLIA, List.of( new ForkId(Bytes.ofUnsignedInt(0xfe3366e7L), 1735371L), - new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L), - new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L)) + new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 1677557088L), + new ForkId(Bytes.ofUnsignedInt(0xf7f9bc08L), 0L), + new ForkId(Bytes.ofUnsignedInt(0xf7f9bc08L), 0L)) }, new Object[] { NetworkName.RINKEBY, @@ -168,8 +168,7 @@ public void testForkId() { final GenesisConfigFile genesisConfigFile = GenesisConfigFile.fromConfig(EthNetworkConfig.jsonConfig(chainName)); final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions(); - final ProtocolSchedule schedule = - MainnetProtocolSchedule.fromConfig(configOptions, EvmConfiguration.DEFAULT); + final ProtocolSchedule schedule = TransitionProtocolSchedule.fromConfig(configOptions); final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, schedule); final Blockchain mockBlockchain = mock(Blockchain.class); final BlockHeader mockBlockHeader = mock(BlockHeader.class); @@ -179,6 +178,7 @@ public void testForkId() { final AtomicLong blockNumber = new AtomicLong(); when(mockBlockchain.getChainHeadHeader()).thenReturn(mockBlockHeader); when(mockBlockHeader.getNumber()).thenAnswer(o -> blockNumber.get()); + when(mockBlockHeader.getTimestamp()).thenAnswer(o -> blockNumber.get()); final ForkIdManager forkIdManager = new ForkIdManager( @@ -187,7 +187,7 @@ public void testForkId() { genesisConfigFile.getForkTimestamps(), false); - final var actualForkIds = + final List actualForkIds = Streams.concat(schedule.streamMilestoneBlocks(), Stream.of(Long.MAX_VALUE)) .map( block -> { diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index f1ea5aabe22..99c376ceaa2 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -5518,7 +5518,7 @@ public void checkpointPostMergeShouldFailWhenGenesisHasNoTTD() throws IOExceptio assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) - .contains("Near head checkpoint sync requires TTD in the genesis file"); + .contains("PoS checkpoint sync requires TTD in the genesis file"); } @Test @@ -5529,7 +5529,7 @@ public void checkpointPostMergeShouldFailWhenGenesisUsesCheckpointFromPreMerge() assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( - "Near head checkpoint sync requires a block with total difficulty greater than the TTD"); + "PoS checkpoint sync requires a block with total difficulty greater or equal than the TTD"); } @Test @@ -5559,6 +5559,25 @@ public void checkpointPostMergeWithPostMergeBlockSucceeds() throws IOException { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void checkpointPostMergeWithPostMergeBlockTDEqualsTTDSucceeds() throws IOException { + final String configText = + Resources.toString( + Resources.getResource("valid_pos_checkpoint_pos_TD_equals_TTD.json"), + StandardCharsets.UTF_8); + final Path genesisFile = createFakeGenesisFile(new JsonObject(configText)); + + parseCommand( + "--genesis-file", + genesisFile.toString(), + "--sync-mode", + "X_CHECKPOINT", + "--Xcheckpoint-post-merge-enabled"); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void checkpointMergeAtGenesisWithGenesisBlockDifficultyZeroFails() throws IOException { final String configText = @@ -5577,6 +5596,6 @@ public void checkpointMergeAtGenesisWithGenesisBlockDifficultyZeroFails() throws assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( - "Post Merge checkpoint sync can't be used with TTD = 0 and checkpoint totalDifficulty = 0"); + "PoS checkpoint sync can't be used with TTD = 0 and checkpoint totalDifficulty = 0"); } } diff --git a/besu/src/test/resources/valid_pos_checkpoint_pos_TD_equals_TTD.json b/besu/src/test/resources/valid_pos_checkpoint_pos_TD_equals_TTD.json new file mode 100644 index 00000000000..eb7c419fed9 --- /dev/null +++ b/besu/src/test/resources/valid_pos_checkpoint_pos_TD_equals_TTD.json @@ -0,0 +1,56 @@ +{ + "config": { + "chainId": 1337, + "homesteadBlock": 0, + "daoForkBlock": 0, + "eip150Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "terminalTotalDifficulty": 10, + "ethash": { + }, + "discovery": { + "dns": "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net", + "bootnodes": [ + "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", + "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", + "enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303", + "enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303", + "enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303", + "enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303", + "enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", + "enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", + "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", + "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", + "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", + "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", + "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", + "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303" + ] + }, + "checkpoint": { + "hash": "0x186642d6084eb7799cb01c7eb69c1a7f3b2c32cd141e62d309f30081a1ea3c91", + "number": 3, + "totalDifficulty": "0x0a" + } + }, + "nonce": "0x42", + "timestamp": "0x0", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x1388", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "000d836201318ec6899a67540690382780743280": { + "balance": "0xad78ebc5ac6200000" + } + } +} diff --git a/build.gradle b/build.gradle index ae516109e8b..713d7ab4b9c 100644 --- a/build.gradle +++ b/build.gradle @@ -715,10 +715,7 @@ task dockerUpload { additionalTags.add('develop') } - def isInterimBuild = (dockerBuildVersion ==~ /.*-SNAPSHOT/) || (dockerBuildVersion ==~ /.*-alpha/) - || (dockerBuildVersion ==~ /.*-beta/) || (dockerBuildVersion ==~ /.*-RC.*/) - - if (!isInterimBuild) { + if (!isInterimBuild(dockerBuildVersion)) { additionalTags.add(dockerBuildVersion.split(/\./)[0..1].join('.')) } @@ -778,7 +775,7 @@ task manifestDocker { tags.add("${dockerImageName}:develop") } - if (!(dockerBuildVersion ==~ /.*-SNAPSHOT/)) { + if (!isInterimBuild(dockerBuildVersion)) { tags.add("${dockerImageName}:" + dockerBuildVersion.split(/\./)[0..1].join('.')) } @@ -929,6 +926,12 @@ def getCheckedOutGitCommitHash(length = 8) { } } +// Takes the version and if it contains SNAPSHOT, alpha, beta or RC in version then return true indicating an interim build +def isInterimBuild(dockerBuildVersion) { + return (dockerBuildVersion ==~ /.*-SNAPSHOT/) || (dockerBuildVersion ==~ /.*-alpha/) + || (dockerBuildVersion ==~ /.*-beta/) || (dockerBuildVersion ==~ /.*-RC.*/) +} + tasks.register("verifyDistributions") { dependsOn distTar dependsOn distZip diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java index 94d5330ac19..2f66ab343bd 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java @@ -596,10 +596,6 @@ public List getForkBlockNumbers() { getArrowGlacierBlockNumber(), getGrayGlacierBlockNumber(), getMergeNetSplitBlockNumber(), - getShanghaiTime(), - getCancunTime(), - getFutureEipsTime(), - getExperimentalEipsTime(), getEcip1015BlockNumber(), getDieHardBlockNumber(), getGothamBlockNumber(), @@ -623,7 +619,9 @@ public List getForkBlockNumbers() { @Override public List getForkBlockTimestamps() { - Stream forkBlockTimestamps = Stream.of(getShanghaiTime(), getCancunTime()); + Stream forkBlockTimestamps = + Stream.of( + getShanghaiTime(), getCancunTime(), getFutureEipsTime(), getExperimentalEipsTime()); // when adding forks add an entry to ${REPO_ROOT}/config/src/test/resources/all_forks.json return forkBlockTimestamps diff --git a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java index 468a78a83bb..381602f901a 100644 --- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -622,22 +622,22 @@ public StubGenesisConfigOptions cancunTime(final long timestamp) { /** * Future EIPs Time block. * - * @param blockNumber the block number + * @param timestamp the block timestamp * @return the stub genesis config options */ - public StubGenesisConfigOptions futureEipsTime(final long blockNumber) { - futureEipsTime = OptionalLong.of(blockNumber); + public StubGenesisConfigOptions futureEipsTime(final long timestamp) { + futureEipsTime = OptionalLong.of(timestamp); return this; } /** * Experimental EIPs Time block. * - * @param blockNumber the block number + * @param timestamp the block timestamp * @return the stub genesis config options */ - public StubGenesisConfigOptions experimentalEipsTime(final long blockNumber) { - experimentalEipsTime = OptionalLong.of(blockNumber); + public StubGenesisConfigOptions experimentalEipsTime(final long timestamp) { + experimentalEipsTime = OptionalLong.of(timestamp); return this; } diff --git a/config/src/main/resources/sepolia.json b/config/src/main/resources/sepolia.json index b1751b86e9d..7bf96fb7f42 100644 --- a/config/src/main/resources/sepolia.json +++ b/config/src/main/resources/sepolia.json @@ -13,6 +13,7 @@ "londonBlock":0, "mergeNetSplitBlock": 1735371, "terminalTotalDifficulty": 17000000000000000, + "shanghaiTime": 1677557088, "ethash":{}, "discovery": { "dns": "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.sepolia.ethdisco.net", diff --git a/consensus/ibftlegacy/src/test/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManagerTest.java b/consensus/ibftlegacy/src/test/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManagerTest.java index c8d9e16bcf4..aba56818181 100644 --- a/consensus/ibftlegacy/src/test/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManagerTest.java +++ b/consensus/ibftlegacy/src/test/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManagerTest.java @@ -111,6 +111,7 @@ public void respondToEth65GetHeadersUsingIstanbul99() EthPeers peers = new EthPeers( Istanbul99Protocol.NAME, + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), new NoOpMetricsSystem(), 25, diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java index 6e87f855bb2..d23fff04414 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java @@ -192,4 +192,11 @@ default boolean isChainPruningEnabled() { * @return the boolean */ boolean isCheckpointPostMergeSync(); + + /** + * Is configured for a post-merge from genesis. + * + * @return the boolean + */ + boolean isPostMergeAtGenesis(); } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java index 12ac368c310..6ab2de612e9 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java @@ -70,6 +70,7 @@ public class PostMergeContext implements MergeContext { private final AtomicReference> terminalPoWBlock = new AtomicReference<>(Optional.empty()); private boolean isCheckpointPostMergeSync; + private boolean isPostMergeAtGenesis; // TODO: cleanup - isChainPruningEnabled will not be required after // https://github.com/hyperledger/besu/pull/4703 is merged. @@ -329,4 +330,20 @@ public PostMergeContext setCheckpointPostMergeSync(final boolean isCheckpointPos public boolean isCheckpointPostMergeSync() { return this.isCheckpointPostMergeSync; } + + @Override + public boolean isPostMergeAtGenesis() { + return this.isPostMergeAtGenesis; + } + + /** + * Sets whether it is post merge at genesis + * + * @param isPostMergeAtGenesis the is post merge at genesis state + * @return the post merge context + */ + public PostMergeContext setPostMergeAtGenesis(final boolean isPostMergeAtGenesis) { + this.isPostMergeAtGenesis = isPostMergeAtGenesis; + return this; + } } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java index c408186af88..69183cb0c53 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java @@ -154,4 +154,9 @@ public Optional retrieveBlockById(final PayloadIdentifier pay public boolean isCheckpointPostMergeSync() { return false; } + + @Override + public boolean isPostMergeAtGenesis() { + return postMergeContext.isPostMergeAtGenesis(); + } } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index 2859fc590e6..5a2ab0a567a 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -16,11 +16,14 @@ import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; +import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.mainnet.HeaderBasedProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; @@ -60,6 +63,29 @@ public TransitionProtocolSchedule( new TransitionUtils<>(preMergeProtocolSchedule, postMergeProtocolSchedule, mergeContext); } + /** + * Create a Proof-of-Stake protocol schedule from a config object + * + * @param genesisConfigOptions {@link GenesisConfigOptions} containing the config options for the + * milestone starting points + * @return an initialised TransitionProtocolSchedule using post-merge defaults + */ + public static TransitionProtocolSchedule fromConfig( + final GenesisConfigOptions genesisConfigOptions) { + ProtocolSchedule preMergeProtocolSchedule = + MainnetProtocolSchedule.fromConfig(genesisConfigOptions); + ProtocolSchedule postMergeProtocolSchedule = + MergeProtocolSchedule.create(genesisConfigOptions, false); + TimestampSchedule timestampSchedule = + MergeProtocolSchedule.createTimestamp( + genesisConfigOptions, PrivacyParameters.DEFAULT, false); + return new TransitionProtocolSchedule( + preMergeProtocolSchedule, + postMergeProtocolSchedule, + PostMergeContext.get(), + timestampSchedule); + } + /** * Gets pre merge schedule. * @@ -162,8 +188,10 @@ public ProtocolSpec getByBlockNumber(final long number) { */ @Override public Stream streamMilestoneBlocks() { - return transitionUtils.dispatchFunctionAccordingToMergeState( - ProtocolSchedule::streamMilestoneBlocks); + Stream milestoneBlockNumbers = + transitionUtils.dispatchFunctionAccordingToMergeState( + ProtocolSchedule::streamMilestoneBlocks); + return Stream.concat(milestoneBlockNumbers, timestampSchedule.streamMilestoneBlocks()); } /** diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionUtils.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionUtils.java index 5f75f0012f2..c36e30b3000 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionUtils.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionUtils.java @@ -116,6 +116,13 @@ public static boolean isTerminalProofOfWorkBlock( // if we cannot find difficulty or are merge-at-genesis .orElse(Difficulty.ZERO); + final MergeContext consensusContext = context.getConsensusContext(MergeContext.class); + + // Genesis is configured for post-merge we will never have a terminal pow block + if (consensusContext.isPostMergeAtGenesis()) { + return false; + } + if (currentChainTotalDifficulty.isZero()) { warnLambda( LOG, @@ -123,8 +130,7 @@ public static boolean isTerminalProofOfWorkBlock( header::toLogString, header::getParentHash); } - Difficulty configuredTotalTerminalDifficulty = - context.getConsensusContext(MergeContext.class).getTerminalTotalDifficulty(); + Difficulty configuredTotalTerminalDifficulty = consensusContext.getTerminalTotalDifficulty(); if (currentChainTotalDifficulty .add(headerDifficulty) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index ac1e25b0254..56030131ea1 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -344,10 +344,20 @@ private void tryToBuildBetterBlock( private Void retryBlockCreationUntilUseful( final PayloadIdentifier payloadIdentifier, final Supplier blockCreator) { + long lastStartAt; + while (!isBlockCreationCancelled(payloadIdentifier)) { try { - recoverableBlockCreation(payloadIdentifier, blockCreator, System.currentTimeMillis()); - } catch (final CancellationException ce) { + lastStartAt = System.currentTimeMillis(); + recoverableBlockCreation(payloadIdentifier, blockCreator, lastStartAt); + final long lastDuration = System.currentTimeMillis() - lastStartAt; + final long waitBeforeRepetition = + miningParameters.getPosBlockCreationRepetitionMinDuration() - lastDuration; + if (waitBeforeRepetition > 0) { + LOG.debug("Waiting {}ms before repeating block creation", waitBeforeRepetition); + Thread.sleep(waitBeforeRepetition); + } + } catch (final CancellationException | InterruptedException ce) { debugLambda( LOG, "Block creation for payload id {} has been cancelled, reason {}", diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java index 4f7a5a16e62..12d8afd673e 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java @@ -75,6 +75,7 @@ import org.hyperledger.besu.testutil.TestClock; import java.time.ZoneId; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -114,6 +115,8 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper { private static final KeyPair KEYS1 = new KeyPair(PRIVATE_KEY1, SIGNATURE_ALGORITHM.get().createPublicKey(PRIVATE_KEY1)); private static final Optional> EMPTY_WITHDRAWALS = Optional.empty(); + + private static final long REPETITION_MIN_DURATION = 100; @Mock MergeContext mergeContext; @Mock BackwardSyncContext backwardSyncContext; @@ -121,7 +124,11 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper { private final Address coinbase = genesisAllocations(getPosGenesisConfigFile()).findFirst().get(); @Spy - MiningParameters miningParameters = new MiningParameters.Builder().coinbase(coinbase).build(); + MiningParameters miningParameters = + new MiningParameters.Builder() + .coinbase(coinbase) + .posBlockCreationRepetitionMinDuration(REPETITION_MIN_DURATION) + .build(); private MergeCoordinator coordinator; private ProtocolContext protocolContext; @@ -353,6 +360,51 @@ public void shouldContinueBuildingBlocksUntilFinalizeIsCalled() } } + @Test + public void blockCreationRepetitionShouldTakeNotLessThanRepetitionMinDuration() + throws InterruptedException, ExecutionException { + final AtomicLong retries = new AtomicLong(0); + final AtomicLong lastPutAt = new AtomicLong(); + final List repetitionDurations = new ArrayList<>(); + + doAnswer( + invocation -> { + final long r = retries.getAndIncrement(); + if (r == 0) { + // ignore first one, that is the empty block + } else if (r < 5) { + if (lastPutAt.get() > 0) { + // each repetition should take >= REPETITION_MIN_DURATION + repetitionDurations.add(System.currentTimeMillis() - lastPutAt.get()); + } + lastPutAt.set(System.currentTimeMillis()); + } else { + // finalize after 5 repetitions + coordinator.finalizeProposalById( + invocation.getArgument(0, PayloadIdentifier.class)); + } + return null; + }) + .when(mergeContext) + .putPayloadById(any(), any()); + + var payloadId = + coordinator.preparePayload( + genesisState.getBlock().getHeader(), + System.currentTimeMillis() / 1000, + Bytes32.ZERO, + suggestedFeeRecipient, + Optional.empty()); + + blockCreationTask.get(); + + verify(mergeContext, times(retries.intValue())).putPayloadById(eq(payloadId), any()); + + // check with a tolerance + assertThat(repetitionDurations) + .allSatisfy(d -> assertThat(d).isGreaterThanOrEqualTo(REPETITION_MIN_DURATION - 10)); + } + @Test public void shouldRetryBlockCreationOnRecoverableError() throws InterruptedException, ExecutionException { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index cb20677899b..25e1786b1d9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -56,6 +56,8 @@ public enum RpcMethod { ENGINE_FORKCHOICE_UPDATED_V1("engine_forkchoiceUpdatedV1"), ENGINE_FORKCHOICE_UPDATED_V2("engine_forkchoiceUpdatedV2"), ENGINE_EXCHANGE_TRANSITION_CONFIGURATION("engine_exchangeTransitionConfigurationV1"), + ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1("engine_getPayloadBodiesByHashV1"), + ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1("engine_getPayloadBodiesByRangeV1"), ENGINE_EXCHANGE_CAPABILITIES("engine_exchangeCapabilities"), GOQUORUM_ETH_GET_QUORUM_PAYLOAD("eth_getQuorumPayload"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java index 14a01f11f8b..265857af1fa 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java @@ -121,6 +121,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) // TODO: post-merge cleanup, this should be unnecessary after merge if (requireTerminalPoWBlockValidation() && !mergeContext.get().isCheckpointPostMergeSync() + && !mergeContext.get().isPostMergeAtGenesis() && !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead) && !mergeContext.get().isChainPruningEnabled()) { logForkchoiceUpdatedCall(INVALID, forkChoice); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index de4b2a12f6c..e4800bf3620 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -213,6 +213,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) // TODO: post-merge cleanup if (requireTerminalPoWBlockValidation() && !mergeContext.get().isCheckpointPostMergeSync() + && !mergeContext.get().isPostMergeAtGenesis() && !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader) && !mergeContext.get().isChainPruningEnabled()) { mergeCoordinator.addBadBlock(block, Optional.empty()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1.java new file mode 100644 index 00000000000..4c1f451403f --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1.java @@ -0,0 +1,85 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; +import org.hyperledger.besu.ethereum.chain.Blockchain; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import io.vertx.core.Vertx; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EngineGetPayloadBodiesByHashV1 extends ExecutionEngineJsonRpcMethod { + + private static final int MAX_REQUEST_BLOCKS = 1024; + private static final Logger LOG = LoggerFactory.getLogger(EngineGetPayloadBodiesByHashV1.class); + private final BlockResultFactory blockResultFactory; + + public EngineGetPayloadBodiesByHashV1( + final Vertx vertx, + final ProtocolContext protocolContext, + final BlockResultFactory blockResultFactory, + final EngineCallListener engineCallListener) { + super(vertx, protocolContext, engineCallListener); + this.blockResultFactory = blockResultFactory; + } + + @Override + public String getName() { + return RpcMethod.ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1.getMethodName(); + } + + @Override + public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { + engineCallListener.executionEngineCalled(); + + final Object reqId = request.getRequest().getId(); + + final Hash[] blockHashes = request.getRequiredParameter(0, Hash[].class); + + traceLambda(LOG, "{} parameters: blockHashes {}", () -> getName(), () -> blockHashes); + + if (blockHashes.length > getMaxRequestBlocks()) { + return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE); + } + + final Blockchain blockchain = protocolContext.getBlockchain(); + + final EngineGetPayloadBodiesResultV1 engineGetPayloadBodiesResultV1 = + blockResultFactory.payloadBodiesCompleteV1( + Arrays.stream(blockHashes).map(blockchain::getBlockBody).collect(Collectors.toList())); + + return new JsonRpcSuccessResponse(reqId, engineGetPayloadBodiesResultV1); + } + + protected int getMaxRequestBlocks() { + return MAX_REQUEST_BLOCKS; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1.java new file mode 100644 index 00000000000..a9d1a120a83 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1.java @@ -0,0 +1,113 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; + +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; +import org.hyperledger.besu.ethereum.chain.Blockchain; + +import java.util.stream.Collectors; +import java.util.stream.LongStream; + +import io.vertx.core.Vertx; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EngineGetPayloadBodiesByRangeV1 extends ExecutionEngineJsonRpcMethod { + private static final Logger LOG = LoggerFactory.getLogger(EngineGetPayloadBodiesByRangeV1.class); + private static final int MAX_REQUEST_BLOCKS = 1024; + private final BlockResultFactory blockResultFactory; + + public EngineGetPayloadBodiesByRangeV1( + final Vertx vertx, + final ProtocolContext protocolContext, + final BlockResultFactory blockResultFactory, + final EngineCallListener engineCallListener) { + super(vertx, protocolContext, engineCallListener); + this.blockResultFactory = blockResultFactory; + } + + @Override + public String getName() { + return RpcMethod.ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1.getMethodName(); + } + + @Override + public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { + engineCallListener.executionEngineCalled(); + + final long startBlockNumber = + request.getRequiredParameter(0, UnsignedLongParameter.class).getValue(); + final long count = request.getRequiredParameter(1, UnsignedLongParameter.class).getValue(); + final Object reqId = request.getRequest().getId(); + + traceLambda( + LOG, + "{} parameters: start block number {} count {}", + () -> getName(), + () -> startBlockNumber, + () -> count); + + if (startBlockNumber < 1 || count < 1) { + return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_PARAMS); + } + + if (count > getMaxRequestBlocks()) { + return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE); + } + + final Blockchain blockchain = protocolContext.getBlockchain(); + final long chainHeadBlockNumber = blockchain.getChainHeadBlockNumber(); + + // request startBlockNumber is beyond head of chain + if (chainHeadBlockNumber < startBlockNumber) { + // Empty List of payloadBodies + return new JsonRpcSuccessResponse(reqId, new EngineGetPayloadBodiesResultV1()); + } + + final long upperBound = startBlockNumber + count; + + // if we've received request from blocks beyond the head we exclude those from the query + final long endExclusiveBlockNumber = + chainHeadBlockNumber < upperBound ? chainHeadBlockNumber + 1 : upperBound; + + EngineGetPayloadBodiesResultV1 engineGetPayloadBodiesResultV1 = + blockResultFactory.payloadBodiesCompleteV1( + LongStream.range(startBlockNumber, endExclusiveBlockNumber) + .mapToObj( + blockNumber -> + blockchain + .getBlockHashByNumber(blockNumber) + .flatMap(blockchain::getBlockBody)) + .collect(Collectors.toList())); + + return new JsonRpcSuccessResponse(reqId, engineGetPayloadBodiesResultV1); + } + + protected int getMaxRequestBlocks() { + return MAX_REQUEST_BLOCKS; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java index 7321375db57..8349f93afd6 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java @@ -83,7 +83,7 @@ public enum JsonRpcError { INVALID_TERMINAL_BLOCK(-32002, "Terminal block doesn't satisfy terminal block conditions"), INVALID_FORKCHOICE_STATE(-38002, "Invalid forkchoice state"), INVALID_PAYLOAD_ATTRIBUTES(-38003, "Invalid payload attributes"), - + INVALID_RANGE_REQUEST_TOO_LARGE(-38004, "Too large request"), // Miner failures COINBASE_NOT_SET(-32010, "Coinbase not set. Unable to start mining without a coinbase"), NO_HASHES_PER_SECOND(-32011, "No hashes being generated by the current node"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java index 1ad670d5ce1..2685f888a37 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java @@ -16,9 +16,11 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1.PayloadBody; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockValueCalculator; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; @@ -26,6 +28,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; @@ -115,6 +118,15 @@ public EngineGetPayloadResultV2 payloadTransactionCompleteV2( Quantity.create(blockValue)); } + public EngineGetPayloadBodiesResultV1 payloadBodiesCompleteV1( + final List> blockBodies) { + final List payloadBodies = + blockBodies.stream() + .map(maybeBody -> maybeBody.map(PayloadBody::new).orElse(null)) + .collect(Collectors.toList()); + return new EngineGetPayloadBodiesResultV1(payloadBodies); + } + public BlockResult transactionHash(final BlockWithMetadata blockWithMetadata) { return transactionHash(blockWithMetadata, false); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java new file mode 100644 index 00000000000..4358230ee09 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java @@ -0,0 +1,79 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; + +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonValue; +import org.apache.tuweni.bytes.Bytes; + +@JsonPropertyOrder({"payloadBodies"}) +public class EngineGetPayloadBodiesResultV1 { + + private final List payloadBodies; + + public EngineGetPayloadBodiesResultV1() { + this.payloadBodies = Collections.emptyList(); + } + + public EngineGetPayloadBodiesResultV1(final List payloadBody) { + this.payloadBodies = payloadBody; + } + + @JsonValue + public List getPayloadBodies() { + return payloadBodies; + } + + public static class PayloadBody { + private final List transactions; + private final List withdrawals; + + public PayloadBody(final BlockBody blockBody) { + this.transactions = + blockBody.getTransactions().stream() + .map(TransactionEncoder::encodeOpaqueBytes) + .map(Bytes::toHexString) + .collect(Collectors.toList()); + this.withdrawals = + blockBody + .getWithdrawals() + .map( + ws -> + ws.stream() + .map(WithdrawalParameter::fromWithdrawal) + .collect(Collectors.toList())) + .orElse(null); + } + + @JsonGetter(value = "transactions") + public List getTransactions() { + return transactions; + } + + @JsonGetter(value = "withdrawals") + public List getWithdrawals() { + return withdrawals; + } + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java index 0de76d5b620..ccf50334784 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java @@ -22,6 +22,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineExchangeTransitionConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV2; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByHashV1; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByRangeV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV2; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayloadV1; @@ -114,6 +116,10 @@ protected Map create() { engineQosTimer), new EngineExchangeTransitionConfiguration( consensusEngineServer, protocolContext, engineQosTimer), + new EngineGetPayloadBodiesByHashV1( + consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer), + new EngineGetPayloadBodiesByRangeV1( + consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer), new EngineExchangeCapabilities(consensusEngineServer, protocolContext, engineQosTimer)); } else { return mapOf( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java index 55bde158abf..615bf3edefe 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java @@ -113,7 +113,8 @@ public class EthGetTransactionReceiptTest { null, Optional.of(PoWHasher.ETHASH_LIGHT), null, - Optional.empty()); + Optional.empty(), + true); private final ProtocolSpec statusTransactionTypeSpec = new ProtocolSpec( "status", @@ -140,7 +141,8 @@ public class EthGetTransactionReceiptTest { null, Optional.of(PoWHasher.ETHASH_LIGHT), null, - Optional.empty()); + Optional.empty(), + true); @SuppressWarnings("unchecked") private final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java new file mode 100644 index 00000000000..03493d7f05e --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java @@ -0,0 +1,267 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.GWei; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.core.Withdrawal; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import io.vertx.core.Vertx; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt64; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class EngineGetPayloadBodiesByHashV1Test { + private EngineGetPayloadBodiesByHashV1 method; + private static final Vertx vertx = Vertx.vertx(); + private static final BlockResultFactory blockResultFactory = new BlockResultFactory(); + @Mock private ProtocolContext protocolContext; + @Mock private EngineCallListener engineCallListener; + @Mock private MutableBlockchain blockchain; + + @Before + public void before() { + when(protocolContext.getBlockchain()).thenReturn(blockchain); + this.method = + spy( + new EngineGetPayloadBodiesByHashV1( + vertx, protocolContext, blockResultFactory, engineCallListener)); + } + + @Test + public void shouldReturnExpectedMethodName() { + assertThat(method.getName()).isEqualTo("engine_getPayloadBodiesByHashV1"); + } + + @Test + public void shouldReturnEmptyPayloadBodiesWithEmptyHash() { + final var resp = resp(new Hash[] {}); + final EngineGetPayloadBodiesResultV1 result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().isEmpty()).isTrue(); + } + + @Test + public void shouldReturnPayloadForKnownHashes() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final Hash blockHash3 = Hash.wrap(Bytes32.random()); + final BlockBody blockBody1 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + final BlockBody blockBody2 = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + final BlockBody blockBody3 = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(blockBody1)); + when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(blockBody2)); + when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(blockBody3)); + + final var resp = resp(new Hash[] {blockHash1, blockHash2, blockHash3}); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(2); + assertThat(result.getPayloadBodies().get(2).getTransactions().size()).isEqualTo(3); + } + + @Test + public void shouldReturnNullForUnknownHashes() { + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final Hash blockHash3 = Hash.wrap(Bytes32.random()); + final var resp = resp(new Hash[] {blockHash1, blockHash2, blockHash3}); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0)).isNull(); + assertThat(result.getPayloadBodies().get(1)).isNull(); + assertThat(result.getPayloadBodies().get(2)).isNull(); + } + + @Test + public void shouldReturnNullForUnknownHashAndPayloadForKnownHash() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final Hash blockHash3 = Hash.wrap(Bytes32.random()); + final BlockBody blockBody1 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + final BlockBody blockBody3 = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(blockBody1)); + when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(blockBody3)); + + final var resp = resp(new Hash[] {blockHash1, blockHash2, blockHash3}); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1)).isNull(); + assertThat(result.getPayloadBodies().get(2).getTransactions().size()).isEqualTo(3); + } + + @Test + public void shouldReturnWithdrawalNullWhenBlockIsPreShanghai() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final BlockBody preShanghaiBlockBody = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + + final BlockBody preShanghaiBlockBody2 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.empty()); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody)); + when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(preShanghaiBlockBody2)); + + final var resp = resp(new Hash[] {blockHash1, blockHash2}); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(2); + assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0).getWithdrawals()).isNull(); + assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1).getWithdrawals()).isNull(); + } + + @Test + public void shouldReturnWithdrawalsWhenBlockIsPostShanghai() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final Withdrawal withdrawal = + new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x1"), GWei.ONE); + final Withdrawal withdrawal2 = + new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x2"), GWei.ONE); + + final BlockBody shanghaiBlockBody = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.of(List.of(withdrawal))); + + final BlockBody shanghaiBlockBody2 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.of(List.of(withdrawal2))); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); + when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); + + final var resp = resp(new Hash[] {blockHash1, blockHash2}); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(2); + assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0).getWithdrawals().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1).getWithdrawals().size()).isEqualTo(1); + } + + @Test + public void shouldReturnErrorWhenRequestExceedsPermittedNumberOfBlocks() { + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final Hash[] hashes = new Hash[] {blockHash1, blockHash2}; + + doReturn(1).when(method).getMaxRequestBlocks(); + + final JsonRpcResponse resp = resp(hashes); + final var result = fromErrorResp(resp); + assertThat(result.getCode()).isEqualTo(INVALID_RANGE_REQUEST_TOO_LARGE.getCode()); + } + + private JsonRpcResponse resp(final Hash[] hashes) { + return method.response( + new JsonRpcRequestContext( + new JsonRpcRequest( + "2.0", + RpcMethod.ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1.getMethodName(), + new Object[] {hashes}))); + } + + private EngineGetPayloadBodiesResultV1 fromSuccessResp(final JsonRpcResponse resp) { + assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.SUCCESS); + return Optional.of(resp) + .map(JsonRpcSuccessResponse.class::cast) + .map(JsonRpcSuccessResponse::getResult) + .map(EngineGetPayloadBodiesResultV1.class::cast) + .get(); + } + + private JsonRpcError fromErrorResp(final JsonRpcResponse resp) { + assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); + return Optional.of(resp) + .map(JsonRpcErrorResponse.class::cast) + .map(JsonRpcErrorResponse::getError) + .get(); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java new file mode 100644 index 00000000000..5711d05d27f --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java @@ -0,0 +1,352 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_PARAMS; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.GWei; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.core.Withdrawal; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import io.vertx.core.Vertx; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt64; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class EngineGetPayloadBodiesByRangeV1Test { + private EngineGetPayloadBodiesByRangeV1 method; + private static final Vertx vertx = Vertx.vertx(); + private static final BlockResultFactory blockResultFactory = new BlockResultFactory(); + @Mock private ProtocolContext protocolContext; + @Mock private EngineCallListener engineCallListener; + @Mock private MutableBlockchain blockchain; + + @Before + public void before() { + when(protocolContext.getBlockchain()).thenReturn(blockchain); + this.method = + spy( + new EngineGetPayloadBodiesByRangeV1( + vertx, protocolContext, blockResultFactory, engineCallListener)); + } + + @Test + public void shouldReturnExpectedMethodName() { + assertThat(method.getName()).isEqualTo("engine_getPayloadBodiesByRangeV1"); + } + + @Test + public void shouldReturnPayloadForKnownNumber() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final Hash blockHash3 = Hash.wrap(Bytes32.random()); + final BlockBody blockBody1 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + final BlockBody blockBody2 = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + final BlockBody blockBody3 = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(blockBody1)); + when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(blockBody2)); + when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(blockBody3)); + when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); + when(blockchain.getBlockHashByNumber(124)).thenReturn(Optional.of(blockHash2)); + when(blockchain.getBlockHashByNumber(125)).thenReturn(Optional.of(blockHash3)); + + final var resp = resp("0x7b", "0x3"); + final EngineGetPayloadBodiesResultV1 result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(2); + assertThat(result.getPayloadBodies().get(2).getTransactions().size()).isEqualTo(3); + } + + @Test + public void shouldReturnNullForUnknownNumber() { + when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); + final var resp = resp("0x7b", "0x3"); + final EngineGetPayloadBodiesResultV1 result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0)).isNull(); + assertThat(result.getPayloadBodies().get(1)).isNull(); + assertThat(result.getPayloadBodies().get(2)).isNull(); + } + + @Test + public void shouldReturnNullForUnknownNumberAndPayloadForKnownNumber() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash3 = Hash.wrap(Bytes32.random()); + final BlockBody blockBody1 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + final BlockBody blockBody3 = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(blockBody1)); + when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(blockBody3)); + when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); + when(blockchain.getBlockHashByNumber(125)).thenReturn(Optional.of(blockHash3)); + + final var resp = resp("0x7b", "0x3"); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1)).isNull(); + assertThat(result.getPayloadBodies().get(2).getTransactions().size()).isEqualTo(3); + } + + @Test + public void shouldReturnNullForWithdrawalsWhenBlockIsPreShanghai() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + + final BlockBody preShanghaiBlockBody = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList()); + + final BlockBody preShanghaiBlockBody2 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.empty()); + when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody)); + when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(preShanghaiBlockBody2)); + when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); + when(blockchain.getBlockHashByNumber(124)).thenReturn(Optional.of(blockHash2)); + + final var resp = resp("0x7b", "0x2"); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(2); + assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0).getWithdrawals()).isNull(); + assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1).getWithdrawals()).isNull(); + ; + } + + @Test + public void shouldReturnWithdrawalsWhenBlockIsPostShanghai() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final Withdrawal withdrawal = + new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x1"), GWei.ONE); + final Withdrawal withdrawal2 = + new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x2"), GWei.ONE); + + final BlockBody shanghaiBlockBody = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.of(List.of(withdrawal))); + + final BlockBody shanghaiBlockBody2 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.of(List.of(withdrawal2))); + when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); + when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); + when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); + when(blockchain.getBlockHashByNumber(124)).thenReturn(Optional.of(blockHash2)); + + final var resp = resp("0x7b", "0x2"); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(2); + assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(3); + assertThat(result.getPayloadBodies().get(0).getWithdrawals().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(1); + assertThat(result.getPayloadBodies().get(1).getWithdrawals().size()).isEqualTo(1); + } + + @Test + public void shouldNotContainTrailingNullForBlocksPastTheCurrentHead() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Withdrawal withdrawal = + new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x1"), GWei.ONE); + + final BlockBody shanghaiBlockBody = + new BlockBody( + List.of( + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair()), + new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.of(List.of(withdrawal))); + when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(123)); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); + when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); + + final var resp = resp("0x7b", "0x3"); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(1); + } + + @Test + public void shouldReturnUpUntilHeadWhenStartBlockPlusCountEqualsHeadNumber() { + final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); + final Hash blockHash1 = Hash.wrap(Bytes32.random()); + final Hash blockHash2 = Hash.wrap(Bytes32.random()); + final Hash blockHash3 = Hash.wrap(Bytes32.random()); + final Withdrawal withdrawal = + new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x1"), GWei.ONE); + + final BlockBody shanghaiBlockBody = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.of(List.of(withdrawal))); + final BlockBody shanghaiBlockBody2 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.of(List.of(withdrawal))); + final BlockBody shanghaiBlockBody3 = + new BlockBody( + List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), + Collections.emptyList(), + Optional.of(List.of(withdrawal))); + when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(125)); + when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); + when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); + when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(shanghaiBlockBody3)); + when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); + when(blockchain.getBlockHashByNumber(124)).thenReturn(Optional.of(blockHash2)); + when(blockchain.getBlockHashByNumber(125)).thenReturn(Optional.of(blockHash3)); + + final var resp = resp("0x7b", "0x3"); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies().size()).isEqualTo(3); + } + + @Test + public void ShouldReturnEmptyPayloadForRequestsPastCurrentHead() { + + when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(123)); + final JsonRpcResponse resp = resp("0x7d", "0x3"); + final var result = fromSuccessResp(resp); + assertThat(result.getPayloadBodies()).isEqualTo(Collections.EMPTY_LIST); + } + + @Test + public void shouldReturnErrorWhenRequestExceedsPermittedNumberOfBlocks() { + doReturn(3).when(method).getMaxRequestBlocks(); + final JsonRpcResponse resp = resp("0x539", "0x4"); + final var result = fromErrorResp(resp); + assertThat(result.getCode()).isEqualTo(INVALID_RANGE_REQUEST_TOO_LARGE.getCode()); + } + + @Test + public void shouldReturnInvalidParamsIfStartIsZero() { + final JsonRpcResponse resp = resp("0x0", "0x539"); + final var result = fromErrorResp(resp); + assertThat(result.getCode()).isEqualTo(INVALID_PARAMS.getCode()); + } + + @Test + public void shouldReturnInvalidParamsIfCountIsZero() { + final JsonRpcResponse resp = resp("0x539", "0x0"); + final var result = fromErrorResp(resp); + assertThat(result.getCode()).isEqualTo(INVALID_PARAMS.getCode()); + } + + private JsonRpcResponse resp(final String startBlockNumber, final String range) { + return method.response( + new JsonRpcRequestContext( + new JsonRpcRequest( + "2.0", + RpcMethod.ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1.getMethodName(), + new Object[] {startBlockNumber, range}))); + } + + private EngineGetPayloadBodiesResultV1 fromSuccessResp(final JsonRpcResponse resp) { + assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.SUCCESS); + return Optional.of(resp) + .map(JsonRpcSuccessResponse.class::cast) + .map(JsonRpcSuccessResponse::getResult) + .map(EngineGetPayloadBodiesResultV1.class::cast) + .get(); + } + + private JsonRpcError fromErrorResp(final JsonRpcResponse resp) { + assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); + return Optional.of(resp) + .map(JsonRpcErrorResponse.class::cast) + .map(JsonRpcErrorResponse::getError) + .get(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/Blockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/Blockchain.java index 0bd09a8e36f..17a9a57743c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/Blockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/Blockchain.java @@ -94,6 +94,11 @@ default Block getGenesisBlock() { .orElseThrow(() -> new IllegalStateException("Missing genesis block.")); } + default BlockHeader getGenesisBlockHeader() { + return getBlockHeader(BlockHeader.GENESIS_BLOCK_NUMBER) + .orElseThrow(() -> new IllegalStateException("Missing genesis block header.")); + } + default Optional getBlockByHash(final Hash blockHash) { return getBlockHeader(blockHash) .flatMap(header -> getBlockBody(blockHash).map(body -> new Block(header, body))); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java index e5dba01bf59..e90efaba5b9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java @@ -36,6 +36,9 @@ public class MiningParameters { public static final long DEFAULT_POS_BLOCK_CREATION_MAX_TIME = Duration.ofSeconds(12).toMillis(); + public static final long DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION = + Duration.ofMillis(500).toMillis(); + private final Optional
coinbase; private final Optional targetGasLimit; private final Wei minTransactionGasPrice; @@ -52,6 +55,7 @@ public class MiningParameters { private final long powJobTimeToLive; private final int maxOmmerDepth; private final long posBlockCreationMaxTime; + private final long posBlockCreationRepetitionMinDuration; private MiningParameters( final Address coinbase, @@ -69,7 +73,8 @@ private MiningParameters( final long remoteSealersTimeToLive, final long powJobTimeToLive, final int maxOmmerDepth, - final long posBlockCreationMaxTime) { + final long posBlockCreationMaxTime, + final long posBlockCreationRepetitionMinDuration) { this.coinbase = Optional.ofNullable(coinbase); this.targetGasLimit = Optional.ofNullable(targetGasLimit).map(AtomicLong::new); this.minTransactionGasPrice = minTransactionGasPrice; @@ -86,6 +91,7 @@ private MiningParameters( this.powJobTimeToLive = powJobTimeToLive; this.maxOmmerDepth = maxOmmerDepth; this.posBlockCreationMaxTime = posBlockCreationMaxTime; + this.posBlockCreationRepetitionMinDuration = posBlockCreationRepetitionMinDuration; } public Optional
getCoinbase() { @@ -152,6 +158,10 @@ public long getPosBlockCreationMaxTime() { return posBlockCreationMaxTime; } + public long getPosBlockCreationRepetitionMinDuration() { + return posBlockCreationRepetitionMinDuration; + } + @Override public boolean equals(final Object o) { if (this == o) return true; @@ -170,7 +180,8 @@ public boolean equals(final Object o) { && remoteSealersTimeToLive == that.remoteSealersTimeToLive && remoteSealersLimit == that.remoteSealersLimit && powJobTimeToLive == that.powJobTimeToLive - && posBlockCreationMaxTime == that.posBlockCreationMaxTime; + && posBlockCreationMaxTime == that.posBlockCreationMaxTime + && posBlockCreationRepetitionMinDuration == that.posBlockCreationRepetitionMinDuration; } @Override @@ -189,7 +200,8 @@ public int hashCode() { remoteSealersLimit, remoteSealersTimeToLive, powJobTimeToLive, - posBlockCreationMaxTime); + posBlockCreationMaxTime, + posBlockCreationRepetitionMinDuration); } @Override @@ -227,6 +239,8 @@ public String toString() { + powJobTimeToLive + ", posBlockCreationMaxTime=" + posBlockCreationMaxTime + + ", posBlockCreationRepetitionMinDuration=" + + posBlockCreationRepetitionMinDuration + '}'; } @@ -249,6 +263,9 @@ public static class Builder { private int maxOmmerDepth = DEFAULT_MAX_OMMERS_DEPTH; private long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; + private long posBlockCreationRepetitionMinDuration = + DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; + public Builder() { // zero arg } @@ -273,6 +290,8 @@ public Builder(final MiningParameters existing) { this.powJobTimeToLive = existing.getPowJobTimeToLive(); this.maxOmmerDepth = existing.getMaxOmmerDepth(); this.posBlockCreationMaxTime = existing.getPosBlockCreationMaxTime(); + this.posBlockCreationRepetitionMinDuration = + existing.getPosBlockCreationRepetitionMinDuration(); } public Builder coinbase(final Address address) { @@ -355,6 +374,12 @@ public Builder posBlockCreationMaxTime(final long posBlockCreationMaxTime) { return this; } + public Builder posBlockCreationRepetitionMinDuration( + final long posBlockCreationRepetitionMinDuration) { + this.posBlockCreationRepetitionMinDuration = posBlockCreationRepetitionMinDuration; + return this; + } + public MiningParameters build() { return new MiningParameters( coinbase, @@ -372,7 +397,8 @@ public MiningParameters build() { remoteSealersTimeToLive, powJobTimeToLive, maxOmmerDepth, - posBlockCreationMaxTime); + posBlockCreationMaxTime, + posBlockCreationRepetitionMinDuration); } } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultTimestampSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultTimestampSchedule.java index 15677eb5537..307339abd77 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultTimestampSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultTimestampSchedule.java @@ -26,6 +26,7 @@ import java.util.Optional; import java.util.TreeSet; import java.util.stream.Collectors; +import java.util.stream.Stream; public class DefaultTimestampSchedule implements TimestampSchedule { private final NavigableSet protocolSpecs = @@ -46,6 +47,11 @@ public Optional getByTimestamp(final long timestamp) { return Optional.empty(); } + @Override + public Stream streamMilestoneBlocks() { + return protocolSpecs.stream().map(TimedProtocolSpec::getTimestamp).sorted(); + } + @Override public Optional getChainId() { return chainId; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/HeaderBasedProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/HeaderBasedProtocolSchedule.java index 697abfc0b7c..05f72726fe1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/HeaderBasedProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/HeaderBasedProtocolSchedule.java @@ -21,6 +21,7 @@ import java.math.BigInteger; import java.util.Optional; +import java.util.stream.Stream; public interface HeaderBasedProtocolSchedule { @@ -31,4 +32,6 @@ public interface HeaderBasedProtocolSchedule { void putMilestone(final long blockOrTimestamp, final ProtocolSpec protocolSpec); String listMilestones(); + + Stream streamMilestoneBlocks(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 874b73afb17..068713d5e2b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -638,7 +638,8 @@ static ProtocolSpecBuilder parisDefinition( .difficultyCalculator(MainnetDifficultyCalculators.PROOF_OF_STAKE_DIFFICULTY) .blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::mergeBlockHeaderValidator) .blockReward(Wei.ZERO) - .name("ParisFork"); + .name("ParisFork") + .isPoS(true); } static ProtocolSpecBuilder shanghaiDefinition( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java index 7cef6b7696f..30686f84eec 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java @@ -16,15 +16,11 @@ import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; -import java.util.stream.Stream; - public interface ProtocolSchedule extends HeaderBasedProtocolSchedule, PrivacySupportingProtocolSchedule { ProtocolSpec getByBlockNumber(long number); - Stream streamMilestoneBlocks(); - @Override default ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { return getByBlockNumber(blockHeader.getNumber()); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java index 3022181b49d..6777f5e7f66 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java @@ -80,6 +80,7 @@ public class ProtocolSpec { private final Optional withdrawalsProcessor; + private final boolean isPoS; /** * Creates a new protocol specification instance. * @@ -108,6 +109,7 @@ public class ProtocolSpec { * @param powHasher the proof-of-work hasher * @param withdrawalsValidator the withdrawals validator to use * @param withdrawalsProcessor the Withdrawals processor to use + * @param isPoS indicates whether the current spec is PoS */ public ProtocolSpec( final String name, @@ -134,7 +136,8 @@ public ProtocolSpec( final BadBlockManager badBlockManager, final Optional powHasher, final WithdrawalsValidator withdrawalsValidator, - final Optional withdrawalsProcessor) { + final Optional withdrawalsProcessor, + final boolean isPoS) { this.name = name; this.evm = evm; this.transactionValidator = transactionValidator; @@ -160,6 +163,7 @@ public ProtocolSpec( this.powHasher = powHasher; this.withdrawalsValidator = withdrawalsValidator; this.withdrawalsProcessor = withdrawalsProcessor; + this.isPoS = isPoS; } /** @@ -367,4 +371,13 @@ public WithdrawalsValidator getWithdrawalsValidator() { public Optional getWithdrawalsProcessor() { return withdrawalsProcessor; } + + /** + * Returns true if the network is running Proof of Stake + * + * @return true if the network is running Proof of Stake + */ + public boolean isPoS() { + return isPoS; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java index 043155dc932..0882196aadb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java @@ -79,6 +79,7 @@ public class ProtocolSpecBuilder { private FeeMarket feeMarket = FeeMarket.legacy(); private BadBlockManager badBlockManager; private PoWHasher powHasher = PoWHasher.ETHASH_LIGHT; + private boolean isPoS = false; public ProtocolSpecBuilder gasCalculator(final Supplier gasCalculatorBuilder) { this.gasCalculatorBuilder = gasCalculatorBuilder; @@ -257,6 +258,11 @@ public ProtocolSpecBuilder withdrawalsProcessor(final WithdrawalsProcessor withd return this; } + public ProtocolSpecBuilder isPoS(final boolean isPoS) { + this.isPoS = isPoS; + return this; + } + public ProtocolSpec build(final HeaderBasedProtocolSchedule protocolSchedule) { checkNotNull(gasCalculatorBuilder, "Missing gasCalculator"); checkNotNull(gasLimitCalculator, "Missing gasLimitCalculator"); @@ -363,7 +369,8 @@ public ProtocolSpec build(final HeaderBasedProtocolSchedule protocolSchedule) { badBlockManager, Optional.ofNullable(powHasher), withdrawalsValidator, - Optional.ofNullable(withdrawalsProcessor)); + Optional.ofNullable(withdrawalsProcessor), + isPoS); } private PrivateTransactionProcessor createPrivateTransactionProcessor( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java index ac49d588053..ba9837e01dd 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java @@ -313,11 +313,20 @@ public static Collection data() { empty() }, { - "Sepolia // Future", + "Sepolia // Shanghai", Network.SEPOLIA, 1735371L, 0L, - ForkIdTestUtil.wantForkId("0xb96cbd13", 0L), + ForkIdTestUtil.wantForkId("0xb96cbd13", 1677557088L), + Optional.of(ForkIds.SEPOLIA), + empty() + }, + { + "Sepolia // Future", + Network.SEPOLIA, + 1735372L, + 1677557088L, + ForkIdTestUtil.wantForkId("0xf7f9bc08", 0L), Optional.of(ForkIds.SEPOLIA), empty() }, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTestUtil.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTestUtil.java index f0da68e5bec..62503177b08 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTestUtil.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTestUtil.java @@ -73,8 +73,11 @@ public static class Forks { Arrays.asList( 1920000L, 1150000L, 2463000L, 2675000L, 2675000L, 4370000L, 7280000L, 7280000L, 9069000L, 9200000L, 12244000L, 12965000L, 13773000L, 15050000L); - public static final List SEPOLIA = + public static final List SEPOLIA_BLOCKNUMBERS = Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1735371L); + + public static final List SEPOLIA_TIMESTAMPS = Arrays.asList(1677557088L); + public static final List RINKEBY = Arrays.asList(1L, 2L, 3L, 3L, 1035301L, 3660663L, 4321234L, 5435345L); public static final List GOERLI = Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1561651L); @@ -106,7 +109,8 @@ public static class ForkIds { public static final List SEPOLIA = Arrays.asList( new ForkId(Bytes.fromHexString("0xfe3366e7"), 1735371L), - new ForkId(Bytes.fromHexString("0xb96cbd13"), 0L)); + new ForkId(Bytes.fromHexString("0xb96cbd13"), 1677557088L), + new ForkId(Bytes.fromHexString("0xf7f9bc08"), 0L)); // First Shanghai block (timestamp) public static final List RINKEBY = Arrays.asList( new ForkId(Bytes.fromHexString("0x3b8e0691"), 1L), @@ -145,7 +149,8 @@ public static class ForkIds { public static class Network { public static final Network MAINNET = network(GenesisHash.MAINNET, Forks.MAINNET, emptyList()); - public static final Network SEPOLIA = network(GenesisHash.SEPOLIA, Forks.SEPOLIA, emptyList()); + public static final Network SEPOLIA = + network(GenesisHash.SEPOLIA, Forks.SEPOLIA_BLOCKNUMBERS, Forks.SEPOLIA_TIMESTAMPS); public static final Network RINKEBY = network(GenesisHash.RINKEBY, Forks.RINKEBY, emptyList()); public static final Network GOERLI = network(GenesisHash.GOERLI, Forks.GOERLI, emptyList()); public static final Network PRIVATE = network(GenesisHash.PRIVATE, Forks.PRIVATE, emptyList()); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TimestampScheduleBuilderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TimestampScheduleBuilderTest.java index 035f3ae6fc4..ab220f3ecbd 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TimestampScheduleBuilderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TimestampScheduleBuilderTest.java @@ -138,4 +138,15 @@ public void getByBlockHeader_whenSpecNotFoundReturnsNull() { assertThat(schedule.getByBlockHeader(BLOCK_HEADER)).isNull(); } + + @Test + public void streamMilestoneBlocksReturnTimestampsInOrder() { + config.shanghaiTime(FIRST_TIMESTAMP_FORK); + config.cancunTime(2L); + config.experimentalEipsTime(5L); + config.futureEipsTime(3L); + final TimestampSchedule schedule = builder.createTimestampSchedule(); + + assertThat(schedule.streamMilestoneBlocks()).containsExactly(FIRST_TIMESTAMP_FORK, 2L, 3L, 5L); + } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java index 5ae869830ec..44016a2985e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeer.DisconnectCallback; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage; import org.hyperledger.besu.metrics.BesuMetricCategory; @@ -36,6 +37,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -67,26 +69,37 @@ public class EthPeers { private final Subscribers connectCallbacks = Subscribers.create(); private final Subscribers disconnectCallbacks = Subscribers.create(); private final Collection pendingRequests = new CopyOnWriteArrayList<>(); + private final Supplier currentProtocolSpecSupplier; private Comparator bestPeerComparator; public EthPeers( final String protocolName, + final Supplier currentProtocolSpecSupplier, final Clock clock, final MetricsSystem metricsSystem, final int maxPeers, final int maxMessageSize) { - this(protocolName, clock, metricsSystem, maxPeers, maxMessageSize, Collections.emptyList()); + this( + protocolName, + currentProtocolSpecSupplier, + clock, + metricsSystem, + maxPeers, + maxMessageSize, + Collections.emptyList()); } public EthPeers( final String protocolName, + final Supplier currentProtocolSpecSupplier, final Clock clock, final MetricsSystem metricsSystem, final int maxPeers, final int maxMessageSize, final List permissioningProviders) { this.protocolName = protocolName; + this.currentProtocolSpecSupplier = currentProtocolSpecSupplier; this.clock = clock; this.permissioningProviders = permissioningProviders; this.maxPeers = maxPeers; @@ -148,8 +161,16 @@ public EthPeer peer(final PeerConnection peerConnection) { public PendingPeerRequest executePeerRequest( final PeerRequest request, final long minimumBlockNumber, final Optional peer) { + final long actualMinBlockNumber; + if (minimumBlockNumber > 0 && currentProtocolSpecSupplier.get().isPoS()) { + // if on PoS do not enforce a min block number, since the estimated chain height of the remote + // peer is not updated anymore. + actualMinBlockNumber = 0; + } else { + actualMinBlockNumber = minimumBlockNumber; + } final PendingPeerRequest pendingPeerRequest = - new PendingPeerRequest(this, request, minimumBlockNumber, peer); + new PendingPeerRequest(this, request, actualMinBlockNumber, peer); synchronized (this) { if (!pendingPeerRequest.attemptExecution()) { pendingRequests.add(pendingPeerRequest); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java index 6dd87ae3b7a..b66a8a3b8de 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java @@ -85,10 +85,6 @@ protected final void executeTask() { }); } - public PendingPeerRequest sendRequestToPeer(final PeerRequest request) { - return sendRequestToPeer(request, 0L); - } - public PendingPeerRequest sendRequestToPeer( final PeerRequest request, final long minimumBlockNumber) { return ethContext.getEthPeers().executePeerRequest(request, minimumBlockNumber, assignedPeer); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTask.java index 6dc20710667..c352fbc3009 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTask.java @@ -103,7 +103,7 @@ private CompletableFuture>> downloadHeader() { hash.map( value -> GetHeadersFromPeerByHashTask.forSingleHash( - protocolSchedule, ethContext, value, metricsSystem)) + protocolSchedule, ethContext, value, blockNumber, metricsSystem)) .orElseGet( () -> GetHeadersFromPeerByNumberTask.forSingleNumber( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTask.java index 82e7902b579..58a8786d0ac 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTask.java @@ -83,12 +83,14 @@ public static GetBodiesFromPeerTask forHeaders( protected PendingPeerRequest sendRequest() { final List blockHashes = headers.stream().map(BlockHeader::getHash).collect(Collectors.toList()); + final long minimumRequiredBlockNumber = headers.get(headers.size() - 1).getNumber(); return sendRequestToPeer( peer -> { LOG.debug("Requesting {} bodies from peer {}.", blockHashes.size(), peer); return peer.getBodies(blockHashes); - }); + }, + minimumRequiredBlockNumber); } @Override diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTask.java index 1f8d76865d2..521d7fd398c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTask.java @@ -32,17 +32,20 @@ public class GetHeadersFromPeerByHashTask extends AbstractGetHeadersFromPeerTask private static final Logger LOG = LoggerFactory.getLogger(GetHeadersFromPeerByHashTask.class); private final Hash referenceHash; + private final long minimumRequiredBlockNumber; @VisibleForTesting GetHeadersFromPeerByHashTask( final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash referenceHash, + final long minimumRequiredBlockNumber, final int count, final int skip, final boolean reverse, final MetricsSystem metricsSystem) { super(protocolSchedule, ethContext, count, skip, reverse, metricsSystem); + this.minimumRequiredBlockNumber = minimumRequiredBlockNumber; checkNotNull(referenceHash); this.referenceHash = referenceHash; } @@ -51,40 +54,65 @@ public static AbstractGetHeadersFromPeerTask startingAtHash( final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash firstHash, + final long firstBlockNumber, final int segmentLength, final MetricsSystem metricsSystem) { return new GetHeadersFromPeerByHashTask( - protocolSchedule, ethContext, firstHash, segmentLength, 0, false, metricsSystem); + protocolSchedule, + ethContext, + firstHash, + firstBlockNumber, + segmentLength, + 0, + false, + metricsSystem); } public static AbstractGetHeadersFromPeerTask startingAtHash( final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash firstHash, + final long firstBlockNumber, final int segmentLength, final int skip, final MetricsSystem metricsSystem) { return new GetHeadersFromPeerByHashTask( - protocolSchedule, ethContext, firstHash, segmentLength, skip, false, metricsSystem); + protocolSchedule, + ethContext, + firstHash, + firstBlockNumber, + segmentLength, + skip, + false, + metricsSystem); } public static AbstractGetHeadersFromPeerTask endingAtHash( final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash lastHash, + final long lastBlockNumber, final int segmentLength, final MetricsSystem metricsSystem) { return new GetHeadersFromPeerByHashTask( - protocolSchedule, ethContext, lastHash, segmentLength, 0, true, metricsSystem); + protocolSchedule, + ethContext, + lastHash, + lastBlockNumber, + segmentLength, + 0, + true, + metricsSystem); } public static AbstractGetHeadersFromPeerTask forSingleHash( final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash hash, + final long minimumRequiredBlockNumber, final MetricsSystem metricsSystem) { return new GetHeadersFromPeerByHashTask( - protocolSchedule, ethContext, hash, 1, 0, false, metricsSystem); + protocolSchedule, ethContext, hash, minimumRequiredBlockNumber, 1, 0, false, metricsSystem); } @Override @@ -97,7 +125,8 @@ protected PendingPeerRequest sendRequest() { referenceHash.slice(0, 6), peer); return peer.getHeadersByHash(referenceHash, count, skip, reverse); - }); + }, + minimumRequiredBlockNumber); } @Override diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTask.java index 1a1cd8db23b..3ad01aa34a9 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTask.java @@ -80,7 +80,8 @@ protected PendingPeerRequest sendRequest() { LOG.debug( "Requesting {} headers (blockNumber {}) from peer {}.", count, blockNumber, peer); return peer.getHeadersByNumber(blockNumber, count, skip, reverse); - }); + }, + blockNumber); } @Override diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java index 2d1119c4aca..e467bfba119 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java @@ -39,6 +39,7 @@ public class RetryingGetHeadersEndingAtFromPeerByHashTask private final Hash referenceHash; private final ProtocolSchedule protocolSchedule; + private final long minimumRequiredBlockNumber; private final int count; @VisibleForTesting @@ -46,11 +47,13 @@ public class RetryingGetHeadersEndingAtFromPeerByHashTask final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash referenceHash, + final long minimumRequiredBlockNumber, final int count, final MetricsSystem metricsSystem, final int maxRetries) { super(ethContext, metricsSystem, List::isEmpty, maxRetries); this.protocolSchedule = protocolSchedule; + this.minimumRequiredBlockNumber = minimumRequiredBlockNumber; this.count = count; checkNotNull(referenceHash); this.referenceHash = referenceHash; @@ -60,11 +63,18 @@ public static RetryingGetHeadersEndingAtFromPeerByHashTask endingAtHash( final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash referenceHash, + final long minimumRequiredBlockNumber, final int count, final MetricsSystem metricsSystem, final int maxRetries) { return new RetryingGetHeadersEndingAtFromPeerByHashTask( - protocolSchedule, ethContext, referenceHash, count, metricsSystem, maxRetries); + protocolSchedule, + ethContext, + referenceHash, + minimumRequiredBlockNumber, + count, + metricsSystem, + maxRetries); } @Override @@ -72,7 +82,12 @@ protected CompletableFuture> executeTaskOnCurrentPeer( final EthPeer currentPeer) { final AbstractGetHeadersFromPeerTask task = GetHeadersFromPeerByHashTask.endingAtHash( - protocolSchedule, getEthContext(), referenceHash, count, getMetricsSystem()); + protocolSchedule, + getEthContext(), + referenceHash, + minimumRequiredBlockNumber, + count, + getMetricsSystem()); task.assignPeer(currentPeer); return executeSubTask(task::run) .thenApply( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java index 547a0abc555..d3d893482a8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java @@ -73,6 +73,7 @@ public void onPeerConnected(final EthPeer peer) { protocolSchedule, ethContext, Hash.wrap(peer.chainState().getBestBlock().getHash()), + 0, metricsSystem) .assignPeer(peer) .run() diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStep.java index 8ec836bde0d..6e404305823 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStep.java @@ -96,6 +96,7 @@ private CompletableFuture> downloadHeaders(final SyncTargetRan protocolSchedule, ethContext, range.getStart().getHash(), + range.getStart().getNumber(), headerRequestSize, metricsSystem) .assignPeer(range.getSyncTarget()) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStep.java index d00f979b773..dd68b5b0f4b 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStep.java @@ -76,6 +76,7 @@ protected CompletableFuture> requestHeaders(final Hash hash) { context.getProtocolSchedule(), context.getEthContext(), hash, + 0, batchSize, context.getMetricsSystem(), context.getEthContext().getEthPeers().peerCount()); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java index f3bc4860f5f..6a799e0fa00 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java @@ -171,7 +171,11 @@ public ChainDownloader createChainDownloader(final FastSyncState currentState) { private CompletableFuture downloadPivotBlockHeader(final Hash hash) { LOG.debug("Downloading pivot block header by hash {}", hash); return RetryingGetHeaderFromPeerByHashTask.byHash( - protocolSchedule, ethContext, hash, metricsSystem) + protocolSchedule, + ethContext, + hash, + pivotBlockSelector.getMinRequiredBlockNumber(), + metricsSystem) .getHeader() .whenComplete( (blockHeader, throwable) -> { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromSafeBlock.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromSafeBlock.java index e107437a9d2..5389ca22288 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromSafeBlock.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromSafeBlock.java @@ -137,7 +137,7 @@ public long getBestChainHeight() { private CompletableFuture downloadBlockHeader(final Hash hash) { return RetryingGetHeaderFromPeerByHashTask.byHash( - protocolSchedule, ethContext, hash, metricsSystem) + protocolSchedule, ethContext, hash, 0, metricsSystem) .getHeader() .whenComplete( (blockHeader, throwable) -> { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersFetcher.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersFetcher.java index a2723a10d46..68e7d193b99 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersFetcher.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersFetcher.java @@ -106,6 +106,7 @@ private CompletableFuture> requestHeaders( protocolSchedule, ethContext, referenceHeader.getHash(), + referenceHeader.getNumber(), // + 1 because lastHeader will be returned as well. headerCount + 1, skip, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java index 8e6cac0b485..474257c3cd2 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java @@ -166,7 +166,12 @@ private CompletableFuture>> downloadHeaders( // Ask for count + 1 because we'll retrieve the previous header as well final AbstractGetHeadersFromPeerTask headersTask = GetHeadersFromPeerByHashTask.endingAtHash( - protocolSchedule, ethContext, referenceHash, count + 1, metricsSystem); + protocolSchedule, + ethContext, + referenceHash, + referenceHeaderForNextRequest.getNumber(), + count + 1, + metricsSystem); assignedPeer.ifPresent(headersTask::assignPeer); return headersTask.run(); }); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java index 18f9d0951d3..c36599e6354 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java @@ -40,16 +40,19 @@ public class RetryingGetHeaderFromPeerByHashTask LoggerFactory.getLogger(RetryingGetHeaderFromPeerByHashTask.class); private final Hash referenceHash; private final ProtocolSchedule protocolSchedule; + private final long minimumRequiredBlockNumber; @VisibleForTesting RetryingGetHeaderFromPeerByHashTask( final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash referenceHash, + final long minimumRequiredBlockNumber, final MetricsSystem metricsSystem, final int maxRetries) { super(ethContext, metricsSystem, List::isEmpty, maxRetries); this.protocolSchedule = protocolSchedule; + this.minimumRequiredBlockNumber = minimumRequiredBlockNumber; checkNotNull(referenceHash); this.referenceHash = referenceHash; } @@ -58,11 +61,13 @@ public static RetryingGetHeaderFromPeerByHashTask byHash( final ProtocolSchedule protocolSchedule, final EthContext ethContext, final Hash referenceHash, + final long minimumRequiredBlockNumber, final MetricsSystem metricsSystem) { return new RetryingGetHeaderFromPeerByHashTask( protocolSchedule, ethContext, referenceHash, + minimumRequiredBlockNumber, metricsSystem, ethContext.getEthPeers().peerCount()); } @@ -71,7 +76,11 @@ public static RetryingGetHeaderFromPeerByHashTask byHash( protected CompletableFuture> executeTaskOnCurrentPeer(final EthPeer peer) { final AbstractGetHeadersFromPeerTask task = GetHeadersFromPeerByHashTask.forSingleHash( - protocolSchedule, getEthContext(), referenceHash, getMetricsSystem()); + protocolSchedule, + getEthContext(), + referenceHash, + minimumRequiredBlockNumber, + getMetricsSystem()); task.assignPeer(peer); return executeSubTask(task::run) .thenApply( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 1c781339bbd..803871d69d2 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -131,6 +131,7 @@ public static void setup() { public void handleMalformedRequestIdMessage() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -149,6 +150,7 @@ public void handleMalformedRequestIdMessage() { public void disconnectOnUnsolicitedMessage() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -166,6 +168,7 @@ public void disconnectOnUnsolicitedMessage() { public void disconnectOnFailureToSendStatusMessage() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -184,6 +187,7 @@ public void disconnectOnFailureToSendStatusMessage() { public void disconnectOnWrongChainId() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -214,6 +218,7 @@ public void disconnectNewPoWPeers() { final MergePeerFilter mergePeerFilter = new MergePeerFilter(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, protocolContext.getWorldStateArchive(), transactionPool, @@ -262,6 +267,7 @@ public void disconnectNewPoWPeers() { public void doNotDisconnectOnLargeMessageWithinLimits() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -281,6 +287,7 @@ public void doNotDisconnectOnLargeMessageWithinLimits() { public void disconnectOnWrongGenesisHash() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -310,6 +317,7 @@ public void disconnectOnWrongGenesisHash() { public void doNotDisconnectOnValidMessage() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -331,6 +339,7 @@ public void respondToGetHeaders() throws ExecutionException, InterruptedExceptio final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -370,6 +379,7 @@ public void respondToGetHeadersWithinLimits() throws ExecutionException, Interru EthProtocolConfiguration.builder().maxGetBlockHeaders(limit).build(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -406,6 +416,7 @@ public void respondToGetHeadersReversed() throws ExecutionException, Interrupted final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -442,6 +453,7 @@ public void respondToGetHeadersWithSkip() throws ExecutionException, Interrupted final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -481,6 +493,7 @@ public void respondToGetHeadersReversedWithSkip() final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -541,6 +554,7 @@ public void respondToGetHeadersPartial() throws ExecutionException, InterruptedE final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -578,6 +592,7 @@ public void respondToGetHeadersEmpty() throws ExecutionException, InterruptedExc final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -612,6 +627,7 @@ public void respondToGetBodies() throws ExecutionException, InterruptedException final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -664,6 +680,7 @@ public void respondToGetBodiesWithinLimits() throws ExecutionException, Interrup EthProtocolConfiguration.builder().maxGetBlockBodies(limit).build(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -712,6 +729,7 @@ public void respondToGetBodiesPartial() throws ExecutionException, InterruptedEx final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -754,6 +772,7 @@ public void respondToGetReceipts() throws ExecutionException, InterruptedExcepti final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -804,6 +823,7 @@ public void respondToGetReceiptsWithinLimits() throws ExecutionException, Interr EthProtocolConfiguration.builder().maxGetReceipts(limit).build(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -851,6 +871,7 @@ public void respondToGetReceiptsPartial() throws ExecutionException, Interrupted final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -895,6 +916,7 @@ public void respondToGetNodeData() throws Exception { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -942,6 +964,7 @@ public void respondToGetNodeData() throws Exception { public void newBlockMinedSendsNewBlockMessageToAllPeers() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -1012,6 +1035,7 @@ public void shouldSuccessfullyRespondToGetHeadersRequestLessThanZero() final CompletableFuture done = new CompletableFuture<>(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), @@ -1077,6 +1101,7 @@ public void transactionMessagesGoToTheCorrectExecutor() { try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, ethScheduler, protocolContext.getWorldStateArchive(), @@ -1110,6 +1135,7 @@ public void forkIdForChainHeadMayBeNull() { final EthScheduler ethScheduler = mock(EthScheduler.class); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, ethScheduler, protocolContext.getWorldStateArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java index 447910b4bb9..b3b4b850645 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java @@ -48,12 +48,14 @@ public class EthProtocolManagerTestUtil { public static EthProtocolManager create( + final ProtocolSchedule protocolSchedule, final Blockchain blockchain, final TimeoutPolicy timeoutPolicy, final WorldStateArchive worldStateArchive, final TransactionPool transactionPool, final EthProtocolConfiguration ethereumWireProtocolConfiguration) { return create( + protocolSchedule, blockchain, new DeterministicEthScheduler(timeoutPolicy), worldStateArchive, @@ -62,6 +64,7 @@ public static EthProtocolManager create( } public static EthProtocolManager create( + final ProtocolSchedule protocolSchedule, final Blockchain blockchain, final WorldStateArchive worldStateArchive, final TransactionPool transactionPool, @@ -71,6 +74,7 @@ public static EthProtocolManager create( EthPeers peers = new EthPeers( EthProtocol.NAME, + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), new NoOpMetricsSystem(), 25, @@ -145,15 +149,20 @@ public static EthProtocolManager create( } public static EthProtocolManager create(final Blockchain blockchain) { - return create(blockchain, new DeterministicEthScheduler(TimeoutPolicy.NEVER_TIMEOUT)); + return create( + ProtocolScheduleFixture.MAINNET, + blockchain, + new DeterministicEthScheduler(TimeoutPolicy.NEVER_TIMEOUT)); } public static EthProtocolManager create( + final ProtocolSchedule protocolSchedule, final Blockchain blockchain, final WorldStateArchive worldStateArchive, final TransactionPool transactionPool, final EthProtocolConfiguration ethProtocolConfiguration) { return create( + protocolSchedule, blockchain, new DeterministicEthScheduler(TimeoutPolicy.NEVER_TIMEOUT), worldStateArchive, @@ -166,10 +175,11 @@ public static EthProtocolManager create(final EthScheduler ethScheduler) { final GenesisConfigFile config = GenesisConfigFile.mainnet(); final GenesisState genesisState = GenesisState.fromConfig(config, protocolSchedule); final Blockchain blockchain = createInMemoryBlockchain(genesisState.getBlock()); - return create(blockchain, ethScheduler); + return create(protocolSchedule, blockchain, ethScheduler); } public static EthProtocolManager create( + final ProtocolSchedule protocolSchedule, final Blockchain blockchain, final EthScheduler ethScheduler, final WorldStateArchive worldStateArchive, @@ -178,6 +188,7 @@ public static EthProtocolManager create( EthPeers peers = new EthPeers( EthProtocol.NAME, + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), new NoOpMetricsSystem(), 25, @@ -196,6 +207,7 @@ public static EthProtocolManager create( } public static EthProtocolManager create( + final ProtocolSchedule protocolSchedule, final Blockchain blockchain, final EthScheduler ethScheduler, final WorldStateArchive worldStateArchive, @@ -205,6 +217,7 @@ public static EthProtocolManager create( EthPeers peers = new EthPeers( EthProtocol.NAME, + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), new NoOpMetricsSystem(), 25, @@ -224,10 +237,13 @@ public static EthProtocolManager create( } public static EthProtocolManager create( - final Blockchain blockchain, final EthScheduler ethScheduler) { + final ProtocolSchedule protocolSchedule, + final Blockchain blockchain, + final EthScheduler ethScheduler) { EthPeers peers = new EthPeers( EthProtocol.NAME, + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), new NoOpMetricsSystem(), 25, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index 9ab9b1eef29..d7bcfd6f97e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java @@ -90,6 +90,7 @@ public void setupTest() { spy( new EthPeers( EthProtocol.NAME, + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), metricsSystem, MAX_PEERS, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java index 5bea199ccad..6d6881c01ff 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java @@ -69,7 +69,12 @@ protected EthTask>> createTask final List requestedData) { final BlockHeader firstHeader = requestedData.get(0); return GetHeadersFromPeerByHashTask.startingAtHash( - protocolSchedule, ethContext, firstHeader.getHash(), requestedData.size(), metricsSystem); + protocolSchedule, + ethContext, + firstHeader.getHash(), + firstHeader.getNumber(), + requestedData.size(), + metricsSystem); } @Test @@ -113,6 +118,7 @@ private void getHeadersFromHash(final int skip, final boolean reverse) { protocolSchedule, ethContext, blockchain.getBlockHashByNumber(startNumber).get(), + startNumber, count, skip, reverse, @@ -135,6 +141,8 @@ private void getHeadersFromHash(final int skip, final boolean reverse) { @Test public void checkThatSequentialHeadersFormingAChainWorks() { + final int startNumber = 1; + final BlockHeader block1 = new BlockHeaderTestFixture().number(1).parentHash(generateTestBlockHash(0)).buildHeader(); final BlockHeader block2 = @@ -145,7 +153,14 @@ public void checkThatSequentialHeadersFormingAChainWorks() { final AbstractGetHeadersFromPeerTask task = new GetHeadersFromPeerByHashTask( - protocolSchedule, ethContext, block1.getHash(), 2, 0, false, metricsSystem); + protocolSchedule, + ethContext, + block1.getHash(), + startNumber, + 2, + 0, + false, + metricsSystem); final Optional> optionalBlockHeaders = task.processResponse(false, BlockHeadersMessage.create(headers), peer); assertThat(optionalBlockHeaders).isNotNull(); @@ -158,6 +173,7 @@ public void checkThatSequentialHeadersFormingAChainWorks() { @Test public void checkThatSequentialHeadersNotFormingAChainFails() { + final int startNumber = 1; final BlockHeader block1 = new BlockHeaderTestFixture().number(1).parentHash(generateTestBlockHash(0)).buildHeader(); final BlockHeader block2 = @@ -168,7 +184,14 @@ public void checkThatSequentialHeadersNotFormingAChainFails() { final AbstractGetHeadersFromPeerTask task = new GetHeadersFromPeerByHashTask( - protocolSchedule, ethContext, block1.getHash(), 2, 0, false, metricsSystem); + protocolSchedule, + ethContext, + block1.getHash(), + startNumber, + 2, + 0, + false, + metricsSystem); final Optional> optionalBlockHeaders = task.processResponse(false, BlockHeadersMessage.create(headers), peer); assertThat(optionalBlockHeaders).isNotNull(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java index e332e4aeb97..57256334f20 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java @@ -106,6 +106,7 @@ protected void setup(final DataStorageFormat dataStorageFormat) { tempProtocolContext.getConsensusContext(ConsensusContext.class)); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, blockchainUtil.getWorldArchive(), blockchainUtil.getTransactionPool(), @@ -617,6 +618,7 @@ public void shouldNotImportBlocksThatAreAlreadyBeingImported() { new EthContext( new EthPeers( "eth", + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), metricsSystem, 25, @@ -749,6 +751,7 @@ public Object answer(final InvocationOnMock invocation) throws Throwable { new EthContext( new EthPeers( "eth", + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), metricsSystem, 25, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java index 0a0570b8a54..503d59c910a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java @@ -74,6 +74,7 @@ public static void setUpClass() { public void setUpTest() { ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, () -> false, protocolContext.getWorldStateArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java index 6b61831cced..ddb15422559 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java @@ -90,7 +90,9 @@ public void setup() { protocolContext = localBlockchainSetup.getProtocolContext(); ethProtocolManager = EthProtocolManagerTestUtil.create( - localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); + protocolSchedule, + localBlockchain, + new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); ethContext = ethProtocolManager.ethContext(); final int blockNumber = 10; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java index b5657ab4f97..ec9313ed907 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; +import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; @@ -61,6 +62,7 @@ public void setUp() { TransactionPool transactionPool = mock(TransactionPool.class); ethProtocolManager = EthProtocolManagerTestUtil.create( + ProtocolScheduleFixture.MAINNET, blockchain, () -> false, protocolContext.getWorldStateArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java index b5bc8168dae..7fdab1e0d3c 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; @@ -94,6 +95,7 @@ public void setUp() { blockchain = blockchainSetupUtil.getBlockchain(); ethProtocolManager = EthProtocolManagerTestUtil.create( + ProtocolScheduleFixture.MAINNET, blockchain, () -> timeoutCount.getAndDecrement() > 0, blockchainSetupUtil.getWorldArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java index efe523322c7..9f3031ab65d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java @@ -89,7 +89,9 @@ public void setup() { protocolContext = localBlockchainSetup.getProtocolContext(); ethProtocolManager = EthProtocolManagerTestUtil.create( - localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); + protocolSchedule, + localBlockchain, + new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); ethContext = ethProtocolManager.ethContext(); syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java index 11b4e1d249b..741334643cb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java @@ -85,6 +85,7 @@ public void setUp() { protocolContext = blockchainSetupUtil.getProtocolContext(); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, timeout::get, blockchainSetupUtil.getWorldArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java index e25293634ce..80bc2b9d2a4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java @@ -88,6 +88,7 @@ public void setUp() { transactionPool = blockchainSetupUtil.getTransactionPool(); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, blockchain, timeout::get, blockchainSetupUtil.getWorldArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java index 3c877bd2309..cda6e900932 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java @@ -64,6 +64,7 @@ public void setupTest() { protocolContext = localBlockchainSetup.getProtocolContext(); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), localBlockchainSetup.getWorldArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java index 24d9fa2e305..f9c4cb1e9fa 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java @@ -101,6 +101,7 @@ public void setupTest() { protocolContext = localBlockchainSetup.getProtocolContext(); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), localBlockchainSetup.getWorldArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java index b80e94450d5..1ec29f6994f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java @@ -84,6 +84,7 @@ public void setupTest() { protocolContext = localBlockchainSetup.getProtocolContext(); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), localBlockchainSetup.getWorldArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java index 1214c5da1e6..65e81aafe32 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java @@ -76,6 +76,7 @@ public void setupTest() { protocolContext = localBlockchainSetup.getProtocolContext(); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), localBlockchainSetup.getWorldArchive(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java index 4a766c5d288..495cbfd203d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java @@ -83,6 +83,7 @@ public void setup() { new ProtocolContext(localBlockchain, localWorldState, null); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), localWorldState, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java index e5f31408a26..b3abf90364a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java @@ -144,6 +144,7 @@ public void searchesAgainstNetwork() { final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); final EthProtocolManager ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, localBlockchain, worldStateArchive, mock(TransactionPool.class), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java index f8523b3c557..2976facbe6c 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java @@ -80,6 +80,7 @@ public void setup() { final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); ethProtocolManager = EthProtocolManagerTestUtil.create( + protocolSchedule, localBlockchain, worldStateArchive, mock(TransactionPool.class), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index 22a6840f413..63493da4bfa 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java @@ -132,6 +132,7 @@ public TestNode( final EthPeers ethPeers = new EthPeers( EthProtocol.NAME, + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()), TestClock.fixed(), metricsSystem, 25, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index cd17fd07adf..b8295945878 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -40,6 +40,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.forkid.ForkIdManager; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.testutil.TestClock; @@ -60,6 +61,7 @@ public class TransactionPoolFactoryTest { @Mock ProtocolSchedule schedule; @Mock ProtocolContext context; + @Mock ProtocolSpec protocolSpec; @Mock MutableBlockchain blockchain; @Mock EthContext ethContext; @Mock EthMessages ethMessages; @@ -85,6 +87,7 @@ public void setup() { ethPeers = new EthPeers( "ETH", + () -> protocolSpec, TestClock.fixed(), new NoOpMetricsSystem(), 25, diff --git a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/NetstatsUrl.java b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/NetstatsUrl.java index 00f6d9bba7f..7ff46e0f67c 100644 --- a/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/NetstatsUrl.java +++ b/ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/NetstatsUrl.java @@ -26,7 +26,7 @@ @Value.Immutable public interface NetstatsUrl { - Pattern NETSTATS_URL_REGEX = Pattern.compile("([-\\w]+):([\\w]+)?@([-.\\w]+)(:([\\d]+))?"); + Pattern NETSTATS_URL_REGEX = Pattern.compile("([-\\w]+):([-\\w]+)?@([-.\\w]+)(:([\\d]+))?"); String getNodeName(); diff --git a/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/NetstatsUrlTest.java b/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/NetstatsUrlTest.java index 4d0a8c6aa06..a59f4fd872a 100644 --- a/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/NetstatsUrlTest.java +++ b/ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/NetstatsUrlTest.java @@ -21,7 +21,7 @@ public class NetstatsUrlTest { - private final String VALID_NETSTATS_URL = "Dev-Node-1:secret@127.0.0.1:3001"; + private final String VALID_NETSTATS_URL = "Dev-Node-1:secret-with-dashes@127.0.0.1:3001"; private final String CONTACT = "contact@mail.fr"; @@ -34,7 +34,7 @@ public void buildWithValidParams() { assertThat(netstatsUrl.getHost()).isEqualTo("127.0.0.1"); assertThat(netstatsUrl.getNodeName()).isEqualTo("Dev-Node-1"); assertThat(netstatsUrl.getPort()).isEqualTo(3001); - assertThat(netstatsUrl.getSecret()).isEqualTo("secret"); + assertThat(netstatsUrl.getSecret()).isEqualTo("secret-with-dashes"); assertThat(netstatsUrl.getContact()).isEqualTo(CONTACT); } diff --git a/ethereum/referencetests/src/reference-test/external-resources b/ethereum/referencetests/src/reference-test/external-resources index 69c4c2a98dc..638da7ca7b2 160000 --- a/ethereum/referencetests/src/reference-test/external-resources +++ b/ethereum/referencetests/src/reference-test/external-resources @@ -1 +1 @@ -Subproject commit 69c4c2a98dc8a712d4c6f5a817da4f21ff719006 +Subproject commit 638da7ca7b2ca371ebb33d7d7d2562981aafd9b2 diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java index cee9cdf1293..e072101d2f6 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java @@ -82,7 +82,8 @@ public ProtocolSpec getByBlockNumber(final long number) { original.getBadBlocksManager(), Optional.empty(), original.getWithdrawalsValidator(), - original.getWithdrawalsProcessor()); + original.getWithdrawalsProcessor(), + original.isPoS()); } @Override diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java index 6ae8d70b81d..c0608943ab6 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java @@ -67,6 +67,7 @@ import java.util.Optional; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.tuweni.bytes.Bytes; @@ -191,9 +192,12 @@ private boolean buildContext( // mining support + final Supplier currentProtocolSpecSupplier = + () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()); final EthPeers ethPeers = new EthPeers( "reteseth", + currentProtocolSpecSupplier, retestethClock, metricsSystem, 0, diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java index ca28eecdb62..a2ebcf472df 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java @@ -80,6 +80,12 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { final MutableAccount account = frame.getWorldUpdater().getAccount(address).getMutable(); frame.clearReturnData(); + final long inputOffset = clampedToLong(frame.getStackItem(1)); + final long inputSize = clampedToLong(frame.getStackItem(2)); + if (inputSize > maxInitcodeSize) { + frame.popStackItems(getStackItemsConsumed()); + return new OperationResult(cost, ExceptionalHaltReason.CODE_TOO_LARGE); + } if (value.compareTo(account.getBalance()) > 0 || frame.getMessageStackDepth() >= 1024 @@ -88,12 +94,6 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { } else { account.incrementNonce(); - final long inputOffset = clampedToLong(frame.getStackItem(1)); - final long inputSize = clampedToLong(frame.getStackItem(2)); - if (inputSize > maxInitcodeSize) { - frame.popStackItems(getStackItemsConsumed()); - return new OperationResult(cost, ExceptionalHaltReason.CODE_TOO_LARGE); - } final Bytes inputData = frame.readMemory(inputOffset, inputSize); // Never cache CREATEx initcode. The amount of reuse is very low, and caching mostly // addresses disk loading delay, and we already have the code. diff --git a/gradle.properties b/gradle.properties index 5335c6a8cea..2e2a4bbdbf9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=23.1.0 +version=23.1.1-SNAPSHOT org.gradle.welcome=never # Set exports/opens flags required by Google Java Format and ErrorProne plugins. (JEP-396)