Release 23.1.1 rc1 (#5106)

* Prepare for version 23.1.1-SNAPSHOT (#5067)

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* Add getPayloadBodiesByRangeV1 and getPayloadBodiesByHash engine methods (#4980)

* Add engine get payload body methods and test

Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com>
Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add header

Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com>

* Update result struct & add test

Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com>

* Change constant to use upper case

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add PayloadBody class and withdrawals to response of methods

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add unit tests

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add changelog

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* spotless

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add check to prevent returning trailing null results past the head

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add test to check trailing null post head scenario

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Split tests into pre and post shanghai

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* spotless

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Rename methods

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Use getName() to log method name

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* spotless

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Rename variable

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Call constructor directly

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Fix ByHash json parsing
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* Fix json parsing again
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* Add check to prevent unnecessary queries

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Refactor method

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add new error code for EngineGetPayloadBodies methods

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add return error for request above the API limit

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add constructor for empty response

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* add check for number of blocks requested and for requests of post head

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add test to check error code when request exceeds API limits

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* add constant for max blocks allowed per request

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* spotless

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Fix some nits

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add invalid params check

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add tests for invalid params check

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Fix test and spotless

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Revert "Fix json parsing again"

This reverts commit 558d325bf3.

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Revert "Fix ByHash json parsing Signed-off-by: Simon Dudley <simon.dudley@consensys.net>"

This reverts commit 663e11e2

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Use UnsignedLongParameter to cast params of the request

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add optional withdrawals to the NewPayload log (#5021)

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* kubernetes and errorprone - update versions (#5013)

* update errorprone and kubernetes versions
* fixed errorprone issues in prod cod
* fixed errorprone issues in test code

---------

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

* Rename JsonRpcService to EngineJsonRpcService (#5036)

* rename JsonRpcService to EngineJsonRpcService

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

* Params should be single item of array type, not outer array of strings (#5037)

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* Add EIP-2537 (BLS12-381 curve precompiles) to Cancun (#5017)

Add the BLS curve precompiles into the registry for cancun.  All of the
curve precompiles have been here since berlin, so this is just wiring
them in.

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>

* Use UnsignedLongParameter to cast params of the request

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add optional withdrawals to the NewPayload log (#5021)

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* kubernetes and errorprone - update versions (#5013)

* update errorprone and kubernetes versions
* fixed errorprone issues in prod cod
* fixed errorprone issues in test code

---------

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

* Rename JsonRpcService to EngineJsonRpcService (#5036)

* rename JsonRpcService to EngineJsonRpcService

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

* Params should be single item of array type, not outer array of strings (#5037)

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* Add EIP-2537 (BLS12-381 curve precompiles) to Cancun (#5017)

Add the BLS curve precompiles into the registry for cancun.  All of the
curve precompiles have been here since berlin, so this is just wiring
them in.

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>

* Convert start and count from hex to match JSON-RPC Spec standard

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

---------

Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com>
Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>
Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
Co-authored-by: Zhenyang Shi <wcgcyx@gmail.com>
Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
Co-authored-by: Daniel Lehrner <daniel.lehrner@consensys.net>
Co-authored-by: Danno Ferrin <danno.ferrin@swirldslabs.com>

* Revert "Keep Worldstate Storage open for Bonsai archive latest layer (#5039)" (#5073)

This reverts commit e7150102ea.

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* Support post merge forks at genesis for hive tests (#5019)

Signed-off-by: Jason Frame <jason.frame@consensys.net>

* Fix manifest docker not skipping interim builds for RCs (#5068)

Signed-off-by: Jason Frame <jason.frame@consensys.net>

* Fix PoS checkpoint validation (#5081)

* change validation to lessThan

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Change exception message to PoS instead of Near head

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add unit test and fix message of existing unit test

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

---------

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* moves check for init code length before balance check (#5077)

Signed-off-by: Justin Florentine <justin+github@florentine.us>

* bump revision for 23.1.x release branch

Signed-off-by: garyschulte <garyschulte@gmail.com>

* Burn in build of 23.1.0 (#5093)

* rebase off of burn-in release, remove unreleased 23.1.0-RC2 from CHANGELOG

Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
Signed-off-by: Ameziane H <ameziane.hamlat@consensys.net>
Signed-off-by: Karim TAAM <karim.t2am@gmail.com>

* re-default global max rpc batch size to 1k (#5104) (#5105)

* default global max rpc batch size to 1000 for now

Signed-off-by: garyschulte <garyschulte@gmail.com>

* Fix Layered World State issue (#5076)

* Use the copy during prepareTrieLog instead of saveTrieLog
* add final flag on BonsaiWorldStateUpdater
* Use a copy of BonsaiInMemoryWorldState inside prepareTrieLog
* add link to persisted worldstate storage
* fix tests
* Make a copy of the worldstate after committing changes to the trielog
* spotless + remove maybeUnSubscribe in setNextWorldView
* subscribe storage on layered worldstate
* fix null issue
* not close layered worldstate during getAccount
* clean code
* Add changelog entry

---------

Signed-off-by: ahamlat <ameziane.hamlat@consensys.net>
Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
Co-authored-by: Karim TAAM <karim.t2am@gmail.com>

* Add shanghaiTime to sepolia (#5088)

Update and fix forkId tests

Move timestamp forks from getForkBlockNumbers to getForkBlockTimestamps in JsonGenesisConfigOptions - this ultimately gets used to popoulate the ForkIdManager which handles lists of blocks and timestamps the same way so this hasn't changed any actual behaviour, but rather supports the test fixes.

Implement TransitionProtocolSchedule.streamMilestoneBlocks as a concatenation of blockNumbers++blockTimestamps. This may have been a latent bug since it's used to update the node record when a fork transition occurs.

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* If a PoS block creation repetition takes less than a configurable dur… (#5048)

* If a PoS block creation repetition takes less than a configurable duration, then waits before next repetition

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Update CHANGELOG

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Add unit test

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Update besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java

Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Update besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java

Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

---------

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>

* Allow dashes in ethstats password (#5090)

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* reintroduce checking of block height for certain tasks when we are not PoS (Revert PR#3911) (#5083)

* reintroduce checking of block height for certain tasks when we are not PoS (Revert PR#3911)

Signed-off-by: Stefan Pingel <16143240+pinges@users.noreply.github.com>

* Allow other users to read the /opt/besu dir when using docker (#5092)

Signed-off-by: Rafael Matias <rafael@skyle.net>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>

* Only use MAINNET version of KZG (#5095)

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* add more context to exception messages and debug logging (#5066)

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

* Fix block value calculation (#5100)

* Add gasUsed calculation

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Fix unit test

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Fix typo

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

---------

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

* Add 23.1.1-RC1 changelog

Signed-off-by: Jason Frame <jason.frame@consensys.net>

* Change version to 23.1.1-RC1

Signed-off-by: Jason Frame <jason.frame@consensys.net>

---------

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com>
Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>
Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
Signed-off-by: Jason Frame <jason.frame@consensys.net>
Signed-off-by: Justin Florentine <justin+github@florentine.us>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Signed-off-by: Ameziane H <ameziane.hamlat@consensys.net>
Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
Signed-off-by: ahamlat <ameziane.hamlat@consensys.net>
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
Signed-off-by: Stefan Pingel <16143240+pinges@users.noreply.github.com>
Signed-off-by: Rafael Matias <rafael@skyle.net>
Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
Co-authored-by: Gabriel Fukushima <gabrielfukushima@gmail.com>
Co-authored-by: Zhenyang Shi <wcgcyx@gmail.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
Co-authored-by: Daniel Lehrner <daniel.lehrner@consensys.net>
Co-authored-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
Co-authored-by: Justin Florentine <justin+github@florentine.us>
Co-authored-by: garyschulte <garyschulte@gmail.com>
Co-authored-by: ahamlat <ameziane.hamlat@consensys.net>
Co-authored-by: Karim TAAM <karim.t2am@gmail.com>
Co-authored-by: Fabio Di Fabio <fabio.difabio@consensys.net>
Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com>
Co-authored-by: Rafael Matias <rafael@skyle.net>
pull/5155/head 23.1.1-RC1
Jason Frame 2 years ago committed by GitHub
parent 79c1a97fc8
commit d048798f1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      CHANGELOG.md
  2. 6
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/EthSendRawTransactionTest.java
  3. 19
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  4. 19
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java
  5. 4
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  6. 16
      besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java
  7. 14
      besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java
  8. 25
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  9. 56
      besu/src/test/resources/valid_pos_checkpoint_pos_TD_equals_TTD.json
  10. 13
      build.gradle
  11. 8
      config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java
  12. 12
      config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java
  13. 1
      config/src/main/resources/sepolia.json
  14. 1
      consensus/ibftlegacy/src/test/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManagerTest.java
  15. 7
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java
  16. 17
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java
  17. 5
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java
  18. 32
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java
  19. 10
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionUtils.java
  20. 14
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java
  21. 54
      consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java
  22. 3
      docker/graalvm/Dockerfile
  23. 3
      docker/openjdk-17-debug/Dockerfile
  24. 3
      docker/openjdk-17/Dockerfile
  25. 3
      docker/openjdk-latest/Dockerfile
  26. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java
  27. 15
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransaction.java
  28. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java
  29. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java
  30. 85
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1.java
  31. 113
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1.java
  32. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java
  33. 12
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java
  34. 79
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java
  35. 6
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java
  36. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java
  37. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java
  38. 267
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java
  39. 352
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java
  40. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/Blockchain.java
  41. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockValueCalculator.java
  42. 34
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java
  43. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultTimestampSchedule.java
  44. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/HeaderBasedProtocolSchedule.java
  45. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
  46. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java
  47. 15
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java
  48. 9
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java
  49. 4
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockValueCalculatorTest.java
  50. 13
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java
  51. 11
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTestUtil.java
  52. 11
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TimestampScheduleBuilderTest.java
  53. 25
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java
  54. 4
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java
  55. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBlockFromPeerTask.java
  56. 4
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetBodiesFromPeerTask.java
  57. 39
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTask.java
  58. 3
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByNumberTask.java
  59. 19
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java
  60. 1
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTracker.java
  61. 1
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DownloadHeadersStep.java
  62. 1
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStep.java
  63. 6
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java
  64. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromSafeBlock.java
  65. 1
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersFetcher.java
  66. 7
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java
  67. 11
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java
  68. 26
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java
  69. 22
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java
  70. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java
  71. 29
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetHeadersFromPeerByHashTaskTest.java
  72. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java
  73. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersFetcherTest.java
  74. 4
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java
  75. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java
  76. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java
  77. 4
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java
  78. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java
  79. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetrieverTest.java
  80. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderForkTest.java
  81. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTest.java
  82. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncChainDownloaderTotalTerminalDifficultyTest.java
  83. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncDownloaderTest.java
  84. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/FullSyncTargetManagerTest.java
  85. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java
  86. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java
  87. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java
  88. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java
  89. 2
      ethereum/ethstats/src/main/java/org/hyperledger/besu/ethstats/util/NetstatsUrl.java
  90. 4
      ethereum/ethstats/src/test/java/org/hyperledger/besu/ethstats/util/NetstatsUrlTest.java
  91. 2
      ethereum/referencetests/src/reference-test/external-resources
  92. 3
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java
  93. 4
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java
  94. 12
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java
  95. 84
      evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java
  96. 92
      evm/src/test/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompileContractTest.java
  97. 1474
      evm/src/test/resources/org/hyperledger/besu/evm/precompile/fail_pointEvaluation.json
  98. 170
      evm/src/test/resources/org/hyperledger/besu/evm/precompile/pointEvaluationPrecompile.json
  99. 71
      evm/src/test/resources/org/hyperledger/besu/evm/precompile/trusted_setup_4.txt
  100. 8318
      evm/src/test/resources/org/hyperledger/besu/evm/precompile/trusted_setup_4096.txt
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,5 +1,15 @@
# Changelog # Changelog
## 23.1.1-RC1
Besu 23.1.1-RC is a required update only for users who want to test Shanghai on Sepolia.
### Additions and Improvements
- 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)
- 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)
- Fix engine_getPayloadV2 block value calculation [#5040](https://github.com/hyperledger/besu/issues/5040)
- Add support for Shanghai in Sepolia [#5088](https://github.com/hyperledger/besu/pull/5088)
## 23.1.0 ## 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. Besu 23.1.0 is a recommended update for Mainnet users. Thank you all for your patience as we crafted this quarterly release.

@ -65,6 +65,12 @@ public class EthSendRawTransactionTest extends AcceptanceTestBase {
strictNode.verify(eth.expectEthSendRawTransactionException(rawTx, "ChainId is required")); strictNode.verify(eth.expectEthSendRawTransactionException(rawTx, "ChainId is required"));
} }
@Test
public void shouldFailToSendWithInvalidRlp() {
final String invalidRawTx = "0x5555";
strictNode.verify(eth.expectEthSendRawTransactionException(invalidRawTx, "Invalid params"));
}
@Test @Test
public void shouldSendSuccessfullyWithChainId_lenientNode() { public void shouldSendSuccessfullyWithChainId_lenientNode() {
final TransferTransaction tx = createTransactionWithChainId(); final TransferTransaction tx = createTransactionWithChainId();

@ -1891,6 +1891,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
throw new ParameterException( throw new ParameterException(
this.commandLine, "--Xpos-block-creation-max-time must be positive and ≤ 12000"); 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 class BesuCommand implements DefaultCommandValues, Runnable {
.powJobTimeToLive(unstableMiningOptions.getPowJobTimeToLive()) .powJobTimeToLive(unstableMiningOptions.getPowJobTimeToLive())
.maxOmmerDepth(unstableMiningOptions.getMaxOmmersDepth()) .maxOmmerDepth(unstableMiningOptions.getMaxOmmersDepth())
.posBlockCreationMaxTime(unstableMiningOptions.getPosBlockCreationMaxTime()) .posBlockCreationMaxTime(unstableMiningOptions.getPosBlockCreationMaxTime())
.posBlockCreationRepetitionMinDuration(
unstableMiningOptions.getPosBlockCreationRepetitionMinDuration())
.build()) .build())
.transactionPoolConfiguration(buildTransactionPoolConfiguration()) .transactionPoolConfiguration(buildTransactionPoolConfiguration())
.nodeKey(new NodeKey(securityModule())) .nodeKey(new NodeKey(securityModule()))
@ -3510,7 +3519,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
if (synchronizerConfiguration.isCheckpointPostMergeEnabled()) { if (synchronizerConfiguration.isCheckpointPostMergeEnabled()) {
if (!checkpointConfigOptions.isValid()) { if (!checkpointConfigOptions.isValid()) {
throw new InvalidConfigurationException( 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( terminalTotalDifficulty.ifPresentOrElse(
ttd -> { ttd -> {
@ -3519,18 +3528,18 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.equals(UInt256.ZERO) .equals(UInt256.ZERO)
&& ttd.equals(UInt256.ZERO)) { && ttd.equals(UInt256.ZERO)) {
throw new InvalidConfigurationException( 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( if (UInt256.fromHexString(
genesisOptions.getCheckpointOptions().getTotalDifficulty().get()) genesisOptions.getCheckpointOptions().getTotalDifficulty().get())
.lessOrEqualThan(ttd)) { .lessThan(ttd)) {
throw new InvalidConfigurationException( 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( throw new InvalidConfigurationException(
"Near head checkpoint sync requires TTD in the genesis file"); "PoS checkpoint sync requires TTD in the genesis file");
}); });
} }
} }

@ -16,6 +16,7 @@ package org.hyperledger.besu.cli.options.unstable;
import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_MAX_OMMERS_DEPTH; 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_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_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_LIMIT;
import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_TTL; 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)") "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; 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. * Create mining options.
* *
@ -129,4 +139,13 @@ public class MiningOptions {
public Long getPosBlockCreationMaxTime() { public Long getPosBlockCreationMaxTime() {
return posBlockCreationMaxTime; return posBlockCreationMaxTime;
} }
/**
* Gets pos block creation repetition min duration.
*
* @return the pos block creation repetition min duration.
*/
public Long getPosBlockCreationRepetitionMinDuration() {
return posBlockCreationRepetitionMinDuration;
}
} }

@ -75,6 +75,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; 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.p2p.config.SubProtocolConfiguration;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
@ -548,9 +549,12 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
} }
} }
final int maxMessageSize = ethereumWireProtocolConfiguration.getMaxMessageSize(); final int maxMessageSize = ethereumWireProtocolConfiguration.getMaxMessageSize();
final Supplier<ProtocolSpec> currentProtocolSpecSupplier =
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader());
final EthPeers ethPeers = final EthPeers ethPeers =
new EthPeers( new EthPeers(
getSupportedProtocol(), getSupportedProtocol(),
currentProtocolSpecSupplier,
clock, clock,
metricsSystem, metricsSystem,
maxPeers, maxPeers,

@ -14,6 +14,7 @@
*/ */
package org.hyperledger.besu.controller; package org.hyperledger.besu.controller;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.MergeContext;
import org.hyperledger.besu.consensus.merge.MergeProtocolSchedule; import org.hyperledger.besu.consensus.merge.MergeProtocolSchedule;
import org.hyperledger.besu.consensus.merge.PostMergeContext; import org.hyperledger.besu.consensus.merge.PostMergeContext;
@ -186,19 +187,24 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder {
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule) { final ProtocolSchedule protocolSchedule) {
OptionalLong terminalBlockNumber = configOptionsSupplier.get().getTerminalBlockNumber(); final GenesisConfigOptions genesisConfigOptions = configOptionsSupplier.get();
Optional<Hash> terminalBlockHash = configOptionsSupplier.get().getTerminalBlockHash(); final OptionalLong terminalBlockNumber = genesisConfigOptions.getTerminalBlockNumber();
final Optional<Hash> terminalBlockHash = genesisConfigOptions.getTerminalBlockHash();
final boolean isPostMergeAtGenesis =
genesisConfigOptions.getTerminalTotalDifficulty().isPresent()
&& genesisConfigOptions.getTerminalTotalDifficulty().get().isZero()
&& blockchain.getGenesisBlockHeader().getDifficulty().isZero();
final MergeContext mergeContext = final MergeContext mergeContext =
PostMergeContext.get() PostMergeContext.get()
.setSyncState(syncState.get()) .setSyncState(syncState.get())
.setTerminalTotalDifficulty( .setTerminalTotalDifficulty(
configOptionsSupplier genesisConfigOptions
.get()
.getTerminalTotalDifficulty() .getTerminalTotalDifficulty()
.map(Difficulty::of) .map(Difficulty::of)
.orElse(Difficulty.ZERO)) .orElse(Difficulty.ZERO))
.setCheckpointPostMergeSync(syncConfig.isCheckpointPostMergeEnabled()); .setCheckpointPostMergeSync(syncConfig.isCheckpointPostMergeEnabled())
.setPostMergeAtGenesis(isPostMergeAtGenesis);
blockchain blockchain
.getFinalized() .getFinalized()

@ -24,14 +24,13 @@ import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName; import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions; 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.Blockchain;
import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.forkid.ForkId; import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager; 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.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -73,8 +72,9 @@ public class ForkIdsNetworkConfigTest {
NetworkName.SEPOLIA, NetworkName.SEPOLIA,
List.of( List.of(
new ForkId(Bytes.ofUnsignedInt(0xfe3366e7L), 1735371L), new ForkId(Bytes.ofUnsignedInt(0xfe3366e7L), 1735371L),
new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L), new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 1677557088L),
new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L)) new ForkId(Bytes.ofUnsignedInt(0xf7f9bc08L), 0L),
new ForkId(Bytes.ofUnsignedInt(0xf7f9bc08L), 0L))
}, },
new Object[] { new Object[] {
NetworkName.RINKEBY, NetworkName.RINKEBY,
@ -168,8 +168,7 @@ public class ForkIdsNetworkConfigTest {
final GenesisConfigFile genesisConfigFile = final GenesisConfigFile genesisConfigFile =
GenesisConfigFile.fromConfig(EthNetworkConfig.jsonConfig(chainName)); GenesisConfigFile.fromConfig(EthNetworkConfig.jsonConfig(chainName));
final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions(); final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions();
final ProtocolSchedule schedule = final ProtocolSchedule schedule = TransitionProtocolSchedule.fromConfig(configOptions);
MainnetProtocolSchedule.fromConfig(configOptions, EvmConfiguration.DEFAULT);
final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, schedule); final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, schedule);
final Blockchain mockBlockchain = mock(Blockchain.class); final Blockchain mockBlockchain = mock(Blockchain.class);
final BlockHeader mockBlockHeader = mock(BlockHeader.class); final BlockHeader mockBlockHeader = mock(BlockHeader.class);
@ -179,6 +178,7 @@ public class ForkIdsNetworkConfigTest {
final AtomicLong blockNumber = new AtomicLong(); final AtomicLong blockNumber = new AtomicLong();
when(mockBlockchain.getChainHeadHeader()).thenReturn(mockBlockHeader); when(mockBlockchain.getChainHeadHeader()).thenReturn(mockBlockHeader);
when(mockBlockHeader.getNumber()).thenAnswer(o -> blockNumber.get()); when(mockBlockHeader.getNumber()).thenAnswer(o -> blockNumber.get());
when(mockBlockHeader.getTimestamp()).thenAnswer(o -> blockNumber.get());
final ForkIdManager forkIdManager = final ForkIdManager forkIdManager =
new ForkIdManager( new ForkIdManager(
@ -187,7 +187,7 @@ public class ForkIdsNetworkConfigTest {
genesisConfigFile.getForkTimestamps(), genesisConfigFile.getForkTimestamps(),
false); false);
final var actualForkIds = final List<ForkId> actualForkIds =
Streams.concat(schedule.streamMilestoneBlocks(), Stream.of(Long.MAX_VALUE)) Streams.concat(schedule.streamMilestoneBlocks(), Stream.of(Long.MAX_VALUE))
.map( .map(
block -> { block -> {

@ -5518,7 +5518,7 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)) 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 @Test
@ -5529,7 +5529,7 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)) assertThat(commandErrorOutput.toString(UTF_8))
.contains( .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 @Test
@ -5559,6 +5559,25 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); 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 @Test
public void checkpointMergeAtGenesisWithGenesisBlockDifficultyZeroFails() throws IOException { public void checkpointMergeAtGenesisWithGenesisBlockDifficultyZeroFails() throws IOException {
final String configText = final String configText =
@ -5577,6 +5596,6 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)) assertThat(commandErrorOutput.toString(UTF_8))
.contains( .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");
} }
} }

@ -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"
}
}
}

@ -715,10 +715,7 @@ task dockerUpload {
additionalTags.add('develop') additionalTags.add('develop')
} }
def isInterimBuild = (dockerBuildVersion ==~ /.*-SNAPSHOT/) || (dockerBuildVersion ==~ /.*-alpha/) if (!isInterimBuild(dockerBuildVersion)) {
|| (dockerBuildVersion ==~ /.*-beta/) || (dockerBuildVersion ==~ /.*-RC.*/)
if (!isInterimBuild) {
additionalTags.add(dockerBuildVersion.split(/\./)[0..1].join('.')) additionalTags.add(dockerBuildVersion.split(/\./)[0..1].join('.'))
} }
@ -778,7 +775,7 @@ task manifestDocker {
tags.add("${dockerImageName}:develop") tags.add("${dockerImageName}:develop")
} }
if (!(dockerBuildVersion ==~ /.*-SNAPSHOT/)) { if (!isInterimBuild(dockerBuildVersion)) {
tags.add("${dockerImageName}:" + dockerBuildVersion.split(/\./)[0..1].join('.')) 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") { tasks.register("verifyDistributions") {
dependsOn distTar dependsOn distTar
dependsOn distZip dependsOn distZip

@ -596,10 +596,6 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
getArrowGlacierBlockNumber(), getArrowGlacierBlockNumber(),
getGrayGlacierBlockNumber(), getGrayGlacierBlockNumber(),
getMergeNetSplitBlockNumber(), getMergeNetSplitBlockNumber(),
getShanghaiTime(),
getCancunTime(),
getFutureEipsTime(),
getExperimentalEipsTime(),
getEcip1015BlockNumber(), getEcip1015BlockNumber(),
getDieHardBlockNumber(), getDieHardBlockNumber(),
getGothamBlockNumber(), getGothamBlockNumber(),
@ -623,7 +619,9 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
@Override @Override
public List<Long> getForkBlockTimestamps() { public List<Long> getForkBlockTimestamps() {
Stream<OptionalLong> forkBlockTimestamps = Stream.of(getShanghaiTime(), getCancunTime()); Stream<OptionalLong> forkBlockTimestamps =
Stream.of(
getShanghaiTime(), getCancunTime(), getFutureEipsTime(), getExperimentalEipsTime());
// when adding forks add an entry to ${REPO_ROOT}/config/src/test/resources/all_forks.json // when adding forks add an entry to ${REPO_ROOT}/config/src/test/resources/all_forks.json
return forkBlockTimestamps return forkBlockTimestamps

@ -622,22 +622,22 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
/** /**
* Future EIPs Time block. * Future EIPs Time block.
* *
* @param blockNumber the block number * @param timestamp the block timestamp
* @return the stub genesis config options * @return the stub genesis config options
*/ */
public StubGenesisConfigOptions futureEipsTime(final long blockNumber) { public StubGenesisConfigOptions futureEipsTime(final long timestamp) {
futureEipsTime = OptionalLong.of(blockNumber); futureEipsTime = OptionalLong.of(timestamp);
return this; return this;
} }
/** /**
* Experimental EIPs Time block. * Experimental EIPs Time block.
* *
* @param blockNumber the block number * @param timestamp the block timestamp
* @return the stub genesis config options * @return the stub genesis config options
*/ */
public StubGenesisConfigOptions experimentalEipsTime(final long blockNumber) { public StubGenesisConfigOptions experimentalEipsTime(final long timestamp) {
experimentalEipsTime = OptionalLong.of(blockNumber); experimentalEipsTime = OptionalLong.of(timestamp);
return this; return this;
} }

@ -13,6 +13,7 @@
"londonBlock":0, "londonBlock":0,
"mergeNetSplitBlock": 1735371, "mergeNetSplitBlock": 1735371,
"terminalTotalDifficulty": 17000000000000000, "terminalTotalDifficulty": 17000000000000000,
"shanghaiTime": 1677557088,
"ethash":{}, "ethash":{},
"discovery": { "discovery": {
"dns": "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.sepolia.ethdisco.net", "dns": "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.sepolia.ethdisco.net",

@ -111,6 +111,7 @@ public class Istanbul99ProtocolManagerTest {
EthPeers peers = EthPeers peers =
new EthPeers( new EthPeers(
Istanbul99Protocol.NAME, Istanbul99Protocol.NAME,
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
25, 25,

@ -192,4 +192,11 @@ public interface MergeContext extends ConsensusContext {
* @return the boolean * @return the boolean
*/ */
boolean isCheckpointPostMergeSync(); boolean isCheckpointPostMergeSync();
/**
* Is configured for a post-merge from genesis.
*
* @return the boolean
*/
boolean isPostMergeAtGenesis();
} }

@ -70,6 +70,7 @@ public class PostMergeContext implements MergeContext {
private final AtomicReference<Optional<BlockHeader>> terminalPoWBlock = private final AtomicReference<Optional<BlockHeader>> terminalPoWBlock =
new AtomicReference<>(Optional.empty()); new AtomicReference<>(Optional.empty());
private boolean isCheckpointPostMergeSync; private boolean isCheckpointPostMergeSync;
private boolean isPostMergeAtGenesis;
// TODO: cleanup - isChainPruningEnabled will not be required after // TODO: cleanup - isChainPruningEnabled will not be required after
// https://github.com/hyperledger/besu/pull/4703 is merged. // https://github.com/hyperledger/besu/pull/4703 is merged.
@ -329,4 +330,20 @@ public class PostMergeContext implements MergeContext {
public boolean isCheckpointPostMergeSync() { public boolean isCheckpointPostMergeSync() {
return this.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;
}
} }

@ -154,4 +154,9 @@ public class TransitionContext implements MergeContext {
public boolean isCheckpointPostMergeSync() { public boolean isCheckpointPostMergeSync() {
return false; return false;
} }
@Override
public boolean isPostMergeAtGenesis() {
return postMergeContext.isPostMergeAtGenesis();
}
} }

@ -16,11 +16,14 @@ package org.hyperledger.besu.consensus.merge;
import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; 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.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Difficulty; 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.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.core.TransactionFilter;
import org.hyperledger.besu.ethereum.mainnet.HeaderBasedProtocolSchedule; 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.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule;
@ -60,6 +63,29 @@ public class TransitionProtocolSchedule implements ProtocolSchedule {
new TransitionUtils<>(preMergeProtocolSchedule, postMergeProtocolSchedule, mergeContext); 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. * Gets pre merge schedule.
* *
@ -162,8 +188,10 @@ public class TransitionProtocolSchedule implements ProtocolSchedule {
*/ */
@Override @Override
public Stream<Long> streamMilestoneBlocks() { public Stream<Long> streamMilestoneBlocks() {
return transitionUtils.dispatchFunctionAccordingToMergeState( Stream<Long> milestoneBlockNumbers =
ProtocolSchedule::streamMilestoneBlocks); transitionUtils.dispatchFunctionAccordingToMergeState(
ProtocolSchedule::streamMilestoneBlocks);
return Stream.concat(milestoneBlockNumbers, timestampSchedule.streamMilestoneBlocks());
} }
/** /**

@ -116,6 +116,13 @@ public class TransitionUtils<SwitchingObject> {
// if we cannot find difficulty or are merge-at-genesis // if we cannot find difficulty or are merge-at-genesis
.orElse(Difficulty.ZERO); .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()) { if (currentChainTotalDifficulty.isZero()) {
warnLambda( warnLambda(
LOG, LOG,
@ -123,8 +130,7 @@ public class TransitionUtils<SwitchingObject> {
header::toLogString, header::toLogString,
header::getParentHash); header::getParentHash);
} }
Difficulty configuredTotalTerminalDifficulty = Difficulty configuredTotalTerminalDifficulty = consensusContext.getTerminalTotalDifficulty();
context.getConsensusContext(MergeContext.class).getTerminalTotalDifficulty();
if (currentChainTotalDifficulty if (currentChainTotalDifficulty
.add(headerDifficulty) .add(headerDifficulty)

@ -344,10 +344,20 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
private Void retryBlockCreationUntilUseful( private Void retryBlockCreationUntilUseful(
final PayloadIdentifier payloadIdentifier, final Supplier<BlockCreationResult> blockCreator) { final PayloadIdentifier payloadIdentifier, final Supplier<BlockCreationResult> blockCreator) {
long lastStartAt;
while (!isBlockCreationCancelled(payloadIdentifier)) { while (!isBlockCreationCancelled(payloadIdentifier)) {
try { try {
recoverableBlockCreation(payloadIdentifier, blockCreator, System.currentTimeMillis()); lastStartAt = System.currentTimeMillis();
} catch (final CancellationException ce) { 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( debugLambda(
LOG, LOG,
"Block creation for payload id {} has been cancelled, reason {}", "Block creation for payload id {} has been cancelled, reason {}",

@ -75,6 +75,7 @@ import org.hyperledger.besu.metrics.StubMetricsSystem;
import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.testutil.TestClock;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -114,6 +115,8 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper {
private static final KeyPair KEYS1 = private static final KeyPair KEYS1 =
new KeyPair(PRIVATE_KEY1, SIGNATURE_ALGORITHM.get().createPublicKey(PRIVATE_KEY1)); new KeyPair(PRIVATE_KEY1, SIGNATURE_ALGORITHM.get().createPublicKey(PRIVATE_KEY1));
private static final Optional<List<Withdrawal>> EMPTY_WITHDRAWALS = Optional.empty(); private static final Optional<List<Withdrawal>> EMPTY_WITHDRAWALS = Optional.empty();
private static final long REPETITION_MIN_DURATION = 100;
@Mock MergeContext mergeContext; @Mock MergeContext mergeContext;
@Mock BackwardSyncContext backwardSyncContext; @Mock BackwardSyncContext backwardSyncContext;
@ -121,7 +124,11 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper {
private final Address coinbase = genesisAllocations(getPosGenesisConfigFile()).findFirst().get(); private final Address coinbase = genesisAllocations(getPosGenesisConfigFile()).findFirst().get();
@Spy @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 MergeCoordinator coordinator;
private ProtocolContext protocolContext; private ProtocolContext protocolContext;
@ -353,6 +360,51 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper {
} }
} }
@Test
public void blockCreationRepetitionShouldTakeNotLessThanRepetitionMinDuration()
throws InterruptedException, ExecutionException {
final AtomicLong retries = new AtomicLong(0);
final AtomicLong lastPutAt = new AtomicLong();
final List<Long> 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 @Test
public void shouldRetryBlockCreationOnRecoverableError() public void shouldRetryBlockCreationOnRecoverableError()
throws InterruptedException, ExecutionException { throws InterruptedException, ExecutionException {

@ -3,7 +3,8 @@ FROM ghcr.io/graalvm/graalvm-ce:ol9-java17
ARG VERSION="dev" ARG VERSION="dev"
RUN adduser --home /opt/besu besu && \ RUN adduser --home /opt/besu besu && \
chown besu:besu /opt/besu chown besu:besu /opt/besu && \
chmod 0755 /opt/besu
USER besu USER besu
WORKDIR /opt/besu WORKDIR /opt/besu

@ -7,7 +7,8 @@ RUN apt-get update && \
apt-get clean && \ apt-get clean && \
rm -rf /var/lib/apt/lists/* && \ rm -rf /var/lib/apt/lists/* && \
adduser --disabled-password --gecos "" --home /opt/besu besu && \ adduser --disabled-password --gecos "" --home /opt/besu besu && \
chown besu:besu /opt/besu chown besu:besu /opt/besu && \
chmod 0755 /opt/besu
USER besu USER besu
WORKDIR /opt/besu WORKDIR /opt/besu

@ -7,7 +7,8 @@ RUN apt-get update && \
apt-get clean && \ apt-get clean && \
rm -rf /var/lib/apt/lists/* && \ rm -rf /var/lib/apt/lists/* && \
adduser --disabled-password --gecos "" --home /opt/besu besu && \ adduser --disabled-password --gecos "" --home /opt/besu besu && \
chown besu:besu /opt/besu chown besu:besu /opt/besu && \
chmod 0755 /opt/besu
USER besu USER besu
WORKDIR /opt/besu WORKDIR /opt/besu

@ -7,7 +7,8 @@ RUN apt-get update && \
apt-get clean && \ apt-get clean && \
rm -rf /var/lib/apt/lists/* && \ rm -rf /var/lib/apt/lists/* && \
adduser --disabled-password --gecos "" --home /opt/besu besu && \ adduser --disabled-password --gecos "" --home /opt/besu besu && \
chown besu:besu /opt/besu chown besu:besu /opt/besu && \
chmod 0755 /opt/besu
USER besu USER besu
WORKDIR /opt/besu WORKDIR /opt/besu

@ -56,6 +56,8 @@ public enum RpcMethod {
ENGINE_FORKCHOICE_UPDATED_V1("engine_forkchoiceUpdatedV1"), ENGINE_FORKCHOICE_UPDATED_V1("engine_forkchoiceUpdatedV1"),
ENGINE_FORKCHOICE_UPDATED_V2("engine_forkchoiceUpdatedV2"), ENGINE_FORKCHOICE_UPDATED_V2("engine_forkchoiceUpdatedV2"),
ENGINE_EXCHANGE_TRANSITION_CONFIGURATION("engine_exchangeTransitionConfigurationV1"), 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"), ENGINE_EXCHANGE_CAPABILITIES("engine_exchangeCapabilities"),
GOQUORUM_ETH_GET_QUORUM_PAYLOAD("eth_getQuorumPayload"), GOQUORUM_ETH_GET_QUORUM_PAYLOAD("eth_getQuorumPayload"),

@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; 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.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; 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.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
@ -68,13 +69,21 @@ public class EthSendRawTransaction implements JsonRpcMethod {
final Transaction transaction; final Transaction transaction;
try { try {
transaction = DomainObjectDecodeUtils.decodeRawTransaction(rawTransaction); transaction = DomainObjectDecodeUtils.decodeRawTransaction(rawTransaction);
} catch (final RLPException | IllegalArgumentException e) { LOG.trace("Received local transaction {}", transaction);
} catch (final RLPException e) {
LOG.debug("RLPException: {} caused by {}", e.getMessage(), e.getCause());
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
} catch (final InvalidJsonRpcRequestException i) {
LOG.debug("InvalidJsonRpcRequestException: {} caused by {}", i.getMessage(), i.getCause());
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
} catch (final IllegalArgumentException ill) {
LOG.debug("IllegalArgumentException: {} caused by {}", ill.getMessage(), ill.getCause());
return new JsonRpcErrorResponse( return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS); requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
} }
LOG.trace("Received local transaction {}", transaction);
final ValidationResult<TransactionInvalidReason> validationResult = final ValidationResult<TransactionInvalidReason> validationResult =
transactionPool.get().addLocalTransaction(transaction); transactionPool.get().addLocalTransaction(transaction);
return validationResult.either( return validationResult.either(

@ -121,6 +121,7 @@ public abstract class AbstractEngineForkchoiceUpdated extends ExecutionEngineJso
// TODO: post-merge cleanup, this should be unnecessary after merge // TODO: post-merge cleanup, this should be unnecessary after merge
if (requireTerminalPoWBlockValidation() if (requireTerminalPoWBlockValidation()
&& !mergeContext.get().isCheckpointPostMergeSync() && !mergeContext.get().isCheckpointPostMergeSync()
&& !mergeContext.get().isPostMergeAtGenesis()
&& !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead) && !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead)
&& !mergeContext.get().isChainPruningEnabled()) { && !mergeContext.get().isChainPruningEnabled()) {
logForkchoiceUpdatedCall(INVALID, forkChoice); logForkchoiceUpdatedCall(INVALID, forkChoice);

@ -213,6 +213,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
// TODO: post-merge cleanup // TODO: post-merge cleanup
if (requireTerminalPoWBlockValidation() if (requireTerminalPoWBlockValidation()
&& !mergeContext.get().isCheckpointPostMergeSync() && !mergeContext.get().isCheckpointPostMergeSync()
&& !mergeContext.get().isPostMergeAtGenesis()
&& !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader) && !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader)
&& !mergeContext.get().isChainPruningEnabled()) { && !mergeContext.get().isChainPruningEnabled()) {
mergeCoordinator.addBadBlock(block, Optional.empty()); mergeCoordinator.addBadBlock(block, Optional.empty());

@ -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;
}
}

@ -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;
}
}

@ -83,7 +83,7 @@ public enum JsonRpcError {
INVALID_TERMINAL_BLOCK(-32002, "Terminal block doesn't satisfy terminal block conditions"), INVALID_TERMINAL_BLOCK(-32002, "Terminal block doesn't satisfy terminal block conditions"),
INVALID_FORKCHOICE_STATE(-38002, "Invalid forkchoice state"), INVALID_FORKCHOICE_STATE(-38002, "Invalid forkchoice state"),
INVALID_PAYLOAD_ATTRIBUTES(-38003, "Invalid payload attributes"), INVALID_PAYLOAD_ATTRIBUTES(-38003, "Invalid payload attributes"),
INVALID_RANGE_REQUEST_TOO_LARGE(-38004, "Too large request"),
// Miner failures // Miner failures
COINBASE_NOT_SET(-32010, "Coinbase not set. Unable to start mining without a coinbase"), 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"), NO_HASHES_PER_SECOND(-32011, "No hashes being generated by the current node"),

@ -16,9 +16,11 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; 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.BlockWithMetadata;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.core.Block; 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.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockValueCalculator; import org.hyperledger.besu.ethereum.core.BlockValueCalculator;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
@ -26,6 +28,7 @@ import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@ -115,6 +118,15 @@ public class BlockResultFactory {
Quantity.create(blockValue)); Quantity.create(blockValue));
} }
public EngineGetPayloadBodiesResultV1 payloadBodiesCompleteV1(
final List<Optional<BlockBody>> blockBodies) {
final List<PayloadBody> payloadBodies =
blockBodies.stream()
.map(maybeBody -> maybeBody.map(PayloadBody::new).orElse(null))
.collect(Collectors.toList());
return new EngineGetPayloadBodiesResultV1(payloadBodies);
}
public BlockResult transactionHash(final BlockWithMetadata<Hash, Hash> blockWithMetadata) { public BlockResult transactionHash(final BlockWithMetadata<Hash, Hash> blockWithMetadata) {
return transactionHash(blockWithMetadata, false); return transactionHash(blockWithMetadata, false);
} }

@ -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<PayloadBody> payloadBodies;
public EngineGetPayloadBodiesResultV1() {
this.payloadBodies = Collections.<PayloadBody>emptyList();
}
public EngineGetPayloadBodiesResultV1(final List<PayloadBody> payloadBody) {
this.payloadBodies = payloadBody;
}
@JsonValue
public List<PayloadBody> getPayloadBodies() {
return payloadBodies;
}
public static class PayloadBody {
private final List<String> transactions;
private final List<WithdrawalParameter> 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<String> getTransactions() {
return transactions;
}
@JsonGetter(value = "withdrawals")
public List<WithdrawalParameter> getWithdrawals() {
return withdrawals;
}
}
}

@ -22,6 +22,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineE
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineExchangeTransitionConfiguration; 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.EngineForkchoiceUpdatedV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV2; 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.EngineGetPayloadV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV2; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV2;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayloadV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayloadV1;
@ -114,6 +116,10 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods {
engineQosTimer), engineQosTimer),
new EngineExchangeTransitionConfiguration( new EngineExchangeTransitionConfiguration(
consensusEngineServer, protocolContext, engineQosTimer), consensusEngineServer, protocolContext, engineQosTimer),
new EngineGetPayloadBodiesByHashV1(
consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer),
new EngineGetPayloadBodiesByRangeV1(
consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer),
new EngineExchangeCapabilities(consensusEngineServer, protocolContext, engineQosTimer)); new EngineExchangeCapabilities(consensusEngineServer, protocolContext, engineQosTimer));
} else { } else {
return mapOf( return mapOf(

@ -30,8 +30,10 @@ public class DomainObjectDecodeUtils {
Bytes txnBytes = Bytes.fromHexString(rawTransaction); Bytes txnBytes = Bytes.fromHexString(rawTransaction);
final boolean isGoQuorumCompatibilityMode = GoQuorumOptions.getGoQuorumCompatibilityMode(); final boolean isGoQuorumCompatibilityMode = GoQuorumOptions.getGoQuorumCompatibilityMode();
return TransactionDecoder.decodeOpaqueBytes(txnBytes, isGoQuorumCompatibilityMode); return TransactionDecoder.decodeOpaqueBytes(txnBytes, isGoQuorumCompatibilityMode);
} catch (final IllegalArgumentException | RLPException e) { } catch (final IllegalArgumentException e) {
throw new InvalidJsonRpcRequestException("Invalid raw transaction hex", e); throw new InvalidJsonRpcRequestException("Invalid raw transaction hex", e);
} catch (final RLPException r) {
throw new InvalidJsonRpcRequestException("Invalid RLP in raw transaction hex", r);
} }
} }
} }

@ -113,7 +113,8 @@ public class EthGetTransactionReceiptTest {
null, null,
Optional.of(PoWHasher.ETHASH_LIGHT), Optional.of(PoWHasher.ETHASH_LIGHT),
null, null,
Optional.empty()); Optional.empty(),
true);
private final ProtocolSpec statusTransactionTypeSpec = private final ProtocolSpec statusTransactionTypeSpec =
new ProtocolSpec( new ProtocolSpec(
"status", "status",
@ -140,7 +141,8 @@ public class EthGetTransactionReceiptTest {
null, null,
Optional.of(PoWHasher.ETHASH_LIGHT), Optional.of(PoWHasher.ETHASH_LIGHT),
null, null,
Optional.empty()); Optional.empty(),
true);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class); private final ProtocolSchedule protocolSchedule = mock(ProtocolSchedule.class);

@ -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();
}
}

@ -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();
}
}

@ -94,6 +94,11 @@ public interface Blockchain {
.orElseThrow(() -> new IllegalStateException("Missing genesis block.")); .orElseThrow(() -> new IllegalStateException("Missing genesis block."));
} }
default BlockHeader getGenesisBlockHeader() {
return getBlockHeader(BlockHeader.GENESIS_BLOCK_NUMBER)
.orElseThrow(() -> new IllegalStateException("Missing genesis block header."));
}
default Optional<Block> getBlockByHash(final Hash blockHash) { default Optional<Block> getBlockByHash(final Hash blockHash) {
return getBlockHeader(blockHash) return getBlockHeader(blockHash)
.flatMap(header -> getBlockBody(blockHash).map(body -> new Block(header, body))); .flatMap(header -> getBlockBody(blockHash).map(body -> new Block(header, body)));

@ -27,7 +27,13 @@ public class BlockValueCalculator {
Wei totalFee = Wei.ZERO; Wei totalFee = Wei.ZERO;
for (int i = 0; i < txs.size(); i++) { for (int i = 0; i < txs.size(); i++) {
final Wei minerFee = txs.get(i).getEffectivePriorityFeePerGas(block.getHeader().getBaseFee()); final Wei minerFee = txs.get(i).getEffectivePriorityFeePerGas(block.getHeader().getBaseFee());
totalFee = totalFee.add(minerFee.multiply(receipts.get(i).getCumulativeGasUsed())); // we don't store gasUsed and need to calculate that on the fly
// receipts are fetched in ascending sorted by cumulativeGasUsed
long gasUsed = receipts.get(i).getCumulativeGasUsed();
if (i > 0) {
gasUsed = gasUsed - receipts.get(i - 1).getCumulativeGasUsed();
}
totalFee = totalFee.add(minerFee.multiply(gasUsed));
} }
return totalFee; return totalFee;
} }

@ -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_MAX_TIME = Duration.ofSeconds(12).toMillis();
public static final long DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION =
Duration.ofMillis(500).toMillis();
private final Optional<Address> coinbase; private final Optional<Address> coinbase;
private final Optional<AtomicLong> targetGasLimit; private final Optional<AtomicLong> targetGasLimit;
private final Wei minTransactionGasPrice; private final Wei minTransactionGasPrice;
@ -52,6 +55,7 @@ public class MiningParameters {
private final long powJobTimeToLive; private final long powJobTimeToLive;
private final int maxOmmerDepth; private final int maxOmmerDepth;
private final long posBlockCreationMaxTime; private final long posBlockCreationMaxTime;
private final long posBlockCreationRepetitionMinDuration;
private MiningParameters( private MiningParameters(
final Address coinbase, final Address coinbase,
@ -69,7 +73,8 @@ public class MiningParameters {
final long remoteSealersTimeToLive, final long remoteSealersTimeToLive,
final long powJobTimeToLive, final long powJobTimeToLive,
final int maxOmmerDepth, final int maxOmmerDepth,
final long posBlockCreationMaxTime) { final long posBlockCreationMaxTime,
final long posBlockCreationRepetitionMinDuration) {
this.coinbase = Optional.ofNullable(coinbase); this.coinbase = Optional.ofNullable(coinbase);
this.targetGasLimit = Optional.ofNullable(targetGasLimit).map(AtomicLong::new); this.targetGasLimit = Optional.ofNullable(targetGasLimit).map(AtomicLong::new);
this.minTransactionGasPrice = minTransactionGasPrice; this.minTransactionGasPrice = minTransactionGasPrice;
@ -86,6 +91,7 @@ public class MiningParameters {
this.powJobTimeToLive = powJobTimeToLive; this.powJobTimeToLive = powJobTimeToLive;
this.maxOmmerDepth = maxOmmerDepth; this.maxOmmerDepth = maxOmmerDepth;
this.posBlockCreationMaxTime = posBlockCreationMaxTime; this.posBlockCreationMaxTime = posBlockCreationMaxTime;
this.posBlockCreationRepetitionMinDuration = posBlockCreationRepetitionMinDuration;
} }
public Optional<Address> getCoinbase() { public Optional<Address> getCoinbase() {
@ -152,6 +158,10 @@ public class MiningParameters {
return posBlockCreationMaxTime; return posBlockCreationMaxTime;
} }
public long getPosBlockCreationRepetitionMinDuration() {
return posBlockCreationRepetitionMinDuration;
}
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
if (this == o) return true; if (this == o) return true;
@ -170,7 +180,8 @@ public class MiningParameters {
&& remoteSealersTimeToLive == that.remoteSealersTimeToLive && remoteSealersTimeToLive == that.remoteSealersTimeToLive
&& remoteSealersLimit == that.remoteSealersLimit && remoteSealersLimit == that.remoteSealersLimit
&& powJobTimeToLive == that.powJobTimeToLive && powJobTimeToLive == that.powJobTimeToLive
&& posBlockCreationMaxTime == that.posBlockCreationMaxTime; && posBlockCreationMaxTime == that.posBlockCreationMaxTime
&& posBlockCreationRepetitionMinDuration == that.posBlockCreationRepetitionMinDuration;
} }
@Override @Override
@ -189,7 +200,8 @@ public class MiningParameters {
remoteSealersLimit, remoteSealersLimit,
remoteSealersTimeToLive, remoteSealersTimeToLive,
powJobTimeToLive, powJobTimeToLive,
posBlockCreationMaxTime); posBlockCreationMaxTime,
posBlockCreationRepetitionMinDuration);
} }
@Override @Override
@ -227,6 +239,8 @@ public class MiningParameters {
+ powJobTimeToLive + powJobTimeToLive
+ ", posBlockCreationMaxTime=" + ", posBlockCreationMaxTime="
+ posBlockCreationMaxTime + posBlockCreationMaxTime
+ ", posBlockCreationRepetitionMinDuration="
+ posBlockCreationRepetitionMinDuration
+ '}'; + '}';
} }
@ -249,6 +263,9 @@ public class MiningParameters {
private int maxOmmerDepth = DEFAULT_MAX_OMMERS_DEPTH; private int maxOmmerDepth = DEFAULT_MAX_OMMERS_DEPTH;
private long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; private long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME;
private long posBlockCreationRepetitionMinDuration =
DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION;
public Builder() { public Builder() {
// zero arg // zero arg
} }
@ -273,6 +290,8 @@ public class MiningParameters {
this.powJobTimeToLive = existing.getPowJobTimeToLive(); this.powJobTimeToLive = existing.getPowJobTimeToLive();
this.maxOmmerDepth = existing.getMaxOmmerDepth(); this.maxOmmerDepth = existing.getMaxOmmerDepth();
this.posBlockCreationMaxTime = existing.getPosBlockCreationMaxTime(); this.posBlockCreationMaxTime = existing.getPosBlockCreationMaxTime();
this.posBlockCreationRepetitionMinDuration =
existing.getPosBlockCreationRepetitionMinDuration();
} }
public Builder coinbase(final Address address) { public Builder coinbase(final Address address) {
@ -355,6 +374,12 @@ public class MiningParameters {
return this; return this;
} }
public Builder posBlockCreationRepetitionMinDuration(
final long posBlockCreationRepetitionMinDuration) {
this.posBlockCreationRepetitionMinDuration = posBlockCreationRepetitionMinDuration;
return this;
}
public MiningParameters build() { public MiningParameters build() {
return new MiningParameters( return new MiningParameters(
coinbase, coinbase,
@ -372,7 +397,8 @@ public class MiningParameters {
remoteSealersTimeToLive, remoteSealersTimeToLive,
powJobTimeToLive, powJobTimeToLive,
maxOmmerDepth, maxOmmerDepth,
posBlockCreationMaxTime); posBlockCreationMaxTime,
posBlockCreationRepetitionMinDuration);
} }
} }
} }

@ -26,6 +26,7 @@ import java.util.NavigableSet;
import java.util.Optional; import java.util.Optional;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
public class DefaultTimestampSchedule implements TimestampSchedule { public class DefaultTimestampSchedule implements TimestampSchedule {
private final NavigableSet<TimedProtocolSpec> protocolSpecs = private final NavigableSet<TimedProtocolSpec> protocolSpecs =
@ -46,6 +47,11 @@ public class DefaultTimestampSchedule implements TimestampSchedule {
return Optional.empty(); return Optional.empty();
} }
@Override
public Stream<Long> streamMilestoneBlocks() {
return protocolSpecs.stream().map(TimedProtocolSpec::getTimestamp).sorted();
}
@Override @Override
public Optional<BigInteger> getChainId() { public Optional<BigInteger> getChainId() {
return chainId; return chainId;

@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream;
public interface HeaderBasedProtocolSchedule { public interface HeaderBasedProtocolSchedule {
@ -31,4 +32,6 @@ public interface HeaderBasedProtocolSchedule {
void putMilestone(final long blockOrTimestamp, final ProtocolSpec protocolSpec); void putMilestone(final long blockOrTimestamp, final ProtocolSpec protocolSpec);
String listMilestones(); String listMilestones();
Stream<Long> streamMilestoneBlocks();
} }

@ -638,7 +638,8 @@ public abstract class MainnetProtocolSpecs {
.difficultyCalculator(MainnetDifficultyCalculators.PROOF_OF_STAKE_DIFFICULTY) .difficultyCalculator(MainnetDifficultyCalculators.PROOF_OF_STAKE_DIFFICULTY)
.blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::mergeBlockHeaderValidator) .blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::mergeBlockHeaderValidator)
.blockReward(Wei.ZERO) .blockReward(Wei.ZERO)
.name("ParisFork"); .name("ParisFork")
.isPoS(true);
} }
static ProtocolSpecBuilder shanghaiDefinition( static ProtocolSpecBuilder shanghaiDefinition(

@ -16,15 +16,11 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import java.util.stream.Stream;
public interface ProtocolSchedule public interface ProtocolSchedule
extends HeaderBasedProtocolSchedule, PrivacySupportingProtocolSchedule { extends HeaderBasedProtocolSchedule, PrivacySupportingProtocolSchedule {
ProtocolSpec getByBlockNumber(long number); ProtocolSpec getByBlockNumber(long number);
Stream<Long> streamMilestoneBlocks();
@Override @Override
default ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { default ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) {
return getByBlockNumber(blockHeader.getNumber()); return getByBlockNumber(blockHeader.getNumber());

@ -80,6 +80,7 @@ public class ProtocolSpec {
private final Optional<WithdrawalsProcessor> withdrawalsProcessor; private final Optional<WithdrawalsProcessor> withdrawalsProcessor;
private final boolean isPoS;
/** /**
* Creates a new protocol specification instance. * Creates a new protocol specification instance.
* *
@ -108,6 +109,7 @@ public class ProtocolSpec {
* @param powHasher the proof-of-work hasher * @param powHasher the proof-of-work hasher
* @param withdrawalsValidator the withdrawals validator to use * @param withdrawalsValidator the withdrawals validator to use
* @param withdrawalsProcessor the Withdrawals processor to use * @param withdrawalsProcessor the Withdrawals processor to use
* @param isPoS indicates whether the current spec is PoS
*/ */
public ProtocolSpec( public ProtocolSpec(
final String name, final String name,
@ -134,7 +136,8 @@ public class ProtocolSpec {
final BadBlockManager badBlockManager, final BadBlockManager badBlockManager,
final Optional<PoWHasher> powHasher, final Optional<PoWHasher> powHasher,
final WithdrawalsValidator withdrawalsValidator, final WithdrawalsValidator withdrawalsValidator,
final Optional<WithdrawalsProcessor> withdrawalsProcessor) { final Optional<WithdrawalsProcessor> withdrawalsProcessor,
final boolean isPoS) {
this.name = name; this.name = name;
this.evm = evm; this.evm = evm;
this.transactionValidator = transactionValidator; this.transactionValidator = transactionValidator;
@ -160,6 +163,7 @@ public class ProtocolSpec {
this.powHasher = powHasher; this.powHasher = powHasher;
this.withdrawalsValidator = withdrawalsValidator; this.withdrawalsValidator = withdrawalsValidator;
this.withdrawalsProcessor = withdrawalsProcessor; this.withdrawalsProcessor = withdrawalsProcessor;
this.isPoS = isPoS;
} }
/** /**
@ -367,4 +371,13 @@ public class ProtocolSpec {
public Optional<WithdrawalsProcessor> getWithdrawalsProcessor() { public Optional<WithdrawalsProcessor> getWithdrawalsProcessor() {
return withdrawalsProcessor; 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;
}
} }

@ -79,6 +79,7 @@ public class ProtocolSpecBuilder {
private FeeMarket feeMarket = FeeMarket.legacy(); private FeeMarket feeMarket = FeeMarket.legacy();
private BadBlockManager badBlockManager; private BadBlockManager badBlockManager;
private PoWHasher powHasher = PoWHasher.ETHASH_LIGHT; private PoWHasher powHasher = PoWHasher.ETHASH_LIGHT;
private boolean isPoS = false;
public ProtocolSpecBuilder gasCalculator(final Supplier<GasCalculator> gasCalculatorBuilder) { public ProtocolSpecBuilder gasCalculator(final Supplier<GasCalculator> gasCalculatorBuilder) {
this.gasCalculatorBuilder = gasCalculatorBuilder; this.gasCalculatorBuilder = gasCalculatorBuilder;
@ -257,6 +258,11 @@ public class ProtocolSpecBuilder {
return this; return this;
} }
public ProtocolSpecBuilder isPoS(final boolean isPoS) {
this.isPoS = isPoS;
return this;
}
public ProtocolSpec build(final HeaderBasedProtocolSchedule protocolSchedule) { public ProtocolSpec build(final HeaderBasedProtocolSchedule protocolSchedule) {
checkNotNull(gasCalculatorBuilder, "Missing gasCalculator"); checkNotNull(gasCalculatorBuilder, "Missing gasCalculator");
checkNotNull(gasLimitCalculator, "Missing gasLimitCalculator"); checkNotNull(gasLimitCalculator, "Missing gasLimitCalculator");
@ -363,7 +369,8 @@ public class ProtocolSpecBuilder {
badBlockManager, badBlockManager,
Optional.ofNullable(powHasher), Optional.ofNullable(powHasher),
withdrawalsValidator, withdrawalsValidator,
Optional.ofNullable(withdrawalsProcessor)); Optional.ofNullable(withdrawalsProcessor),
isPoS);
} }
private PrivateTransactionProcessor createPrivateTransactionProcessor( private PrivateTransactionProcessor createPrivateTransactionProcessor(

@ -88,8 +88,8 @@ public class BlockValueCalculatorTest {
new BlockValueCalculator() new BlockValueCalculator()
.calculateBlockValue( .calculateBlockValue(
new BlockWithReceipts(block, List.of(receipt1, receipt2, receipt3))); new BlockWithReceipts(block, List.of(receipt1, receipt2, receipt3)));
// Block value = 71 * 1 + 143 * 2 + 214 * 5 = 1427 // Block value = 71 * 1 + (143-71) * 2 + (214-143) * 5 = 1427
assertThat(blockValue).isEqualTo(Wei.of(1427L)); assertThat(blockValue).isEqualTo(Wei.of(570L));
} }
@Test @Test

@ -313,11 +313,20 @@ public class ForkIdTest {
empty() empty()
}, },
{ {
"Sepolia // Future", "Sepolia // Shanghai",
Network.SEPOLIA, Network.SEPOLIA,
1735371L, 1735371L,
0L, 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), Optional.of(ForkIds.SEPOLIA),
empty() empty()
}, },

@ -73,8 +73,11 @@ public class ForkIdTestUtil {
Arrays.asList( Arrays.asList(
1920000L, 1150000L, 2463000L, 2675000L, 2675000L, 4370000L, 7280000L, 7280000L, 1920000L, 1150000L, 2463000L, 2675000L, 2675000L, 4370000L, 7280000L, 7280000L,
9069000L, 9200000L, 12244000L, 12965000L, 13773000L, 15050000L); 9069000L, 9200000L, 12244000L, 12965000L, 13773000L, 15050000L);
public static final List<Long> SEPOLIA = public static final List<Long> SEPOLIA_BLOCKNUMBERS =
Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1735371L); Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1735371L);
public static final List<Long> SEPOLIA_TIMESTAMPS = Arrays.asList(1677557088L);
public static final List<Long> RINKEBY = public static final List<Long> RINKEBY =
Arrays.asList(1L, 2L, 3L, 3L, 1035301L, 3660663L, 4321234L, 5435345L); Arrays.asList(1L, 2L, 3L, 3L, 1035301L, 3660663L, 4321234L, 5435345L);
public static final List<Long> GOERLI = Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1561651L); public static final List<Long> GOERLI = Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1561651L);
@ -106,7 +109,8 @@ public class ForkIdTestUtil {
public static final List<ForkId> SEPOLIA = public static final List<ForkId> SEPOLIA =
Arrays.asList( Arrays.asList(
new ForkId(Bytes.fromHexString("0xfe3366e7"), 1735371L), 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<ForkId> RINKEBY = public static final List<ForkId> RINKEBY =
Arrays.asList( Arrays.asList(
new ForkId(Bytes.fromHexString("0x3b8e0691"), 1L), new ForkId(Bytes.fromHexString("0x3b8e0691"), 1L),
@ -145,7 +149,8 @@ public class ForkIdTestUtil {
public static class Network { public static class Network {
public static final Network MAINNET = network(GenesisHash.MAINNET, Forks.MAINNET, emptyList()); 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 RINKEBY = network(GenesisHash.RINKEBY, Forks.RINKEBY, emptyList());
public static final Network GOERLI = network(GenesisHash.GOERLI, Forks.GOERLI, emptyList()); public static final Network GOERLI = network(GenesisHash.GOERLI, Forks.GOERLI, emptyList());
public static final Network PRIVATE = network(GenesisHash.PRIVATE, Forks.PRIVATE, emptyList()); public static final Network PRIVATE = network(GenesisHash.PRIVATE, Forks.PRIVATE, emptyList());

@ -138,4 +138,15 @@ public class TimestampScheduleBuilderTest {
assertThat(schedule.getByBlockHeader(BLOCK_HEADER)).isNull(); 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);
}
} }

@ -18,6 +18,7 @@ import static org.hyperledger.besu.util.Slf4jLambdaHelper.infoLambda;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer.DisconnectCallback; import org.hyperledger.besu.ethereum.eth.manager.EthPeer.DisconnectCallback;
import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; 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.connections.PeerConnection;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
@ -36,6 +37,7 @@ import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -67,26 +69,37 @@ public class EthPeers {
private final Subscribers<ConnectCallback> connectCallbacks = Subscribers.create(); private final Subscribers<ConnectCallback> connectCallbacks = Subscribers.create();
private final Subscribers<DisconnectCallback> disconnectCallbacks = Subscribers.create(); private final Subscribers<DisconnectCallback> disconnectCallbacks = Subscribers.create();
private final Collection<PendingPeerRequest> pendingRequests = new CopyOnWriteArrayList<>(); private final Collection<PendingPeerRequest> pendingRequests = new CopyOnWriteArrayList<>();
private final Supplier<ProtocolSpec> currentProtocolSpecSupplier;
private Comparator<EthPeer> bestPeerComparator; private Comparator<EthPeer> bestPeerComparator;
public EthPeers( public EthPeers(
final String protocolName, final String protocolName,
final Supplier<ProtocolSpec> currentProtocolSpecSupplier,
final Clock clock, final Clock clock,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final int maxPeers, final int maxPeers,
final int maxMessageSize) { final int maxMessageSize) {
this(protocolName, clock, metricsSystem, maxPeers, maxMessageSize, Collections.emptyList()); this(
protocolName,
currentProtocolSpecSupplier,
clock,
metricsSystem,
maxPeers,
maxMessageSize,
Collections.emptyList());
} }
public EthPeers( public EthPeers(
final String protocolName, final String protocolName,
final Supplier<ProtocolSpec> currentProtocolSpecSupplier,
final Clock clock, final Clock clock,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final int maxPeers, final int maxPeers,
final int maxMessageSize, final int maxMessageSize,
final List<NodeMessagePermissioningProvider> permissioningProviders) { final List<NodeMessagePermissioningProvider> permissioningProviders) {
this.protocolName = protocolName; this.protocolName = protocolName;
this.currentProtocolSpecSupplier = currentProtocolSpecSupplier;
this.clock = clock; this.clock = clock;
this.permissioningProviders = permissioningProviders; this.permissioningProviders = permissioningProviders;
this.maxPeers = maxPeers; this.maxPeers = maxPeers;
@ -148,8 +161,16 @@ public class EthPeers {
public PendingPeerRequest executePeerRequest( public PendingPeerRequest executePeerRequest(
final PeerRequest request, final long minimumBlockNumber, final Optional<EthPeer> peer) { final PeerRequest request, final long minimumBlockNumber, final Optional<EthPeer> 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 = final PendingPeerRequest pendingPeerRequest =
new PendingPeerRequest(this, request, minimumBlockNumber, peer); new PendingPeerRequest(this, request, actualMinBlockNumber, peer);
synchronized (this) { synchronized (this) {
if (!pendingPeerRequest.attemptExecution()) { if (!pendingPeerRequest.attemptExecution()) {
pendingRequests.add(pendingPeerRequest); pendingRequests.add(pendingPeerRequest);

@ -85,10 +85,6 @@ public abstract class AbstractPeerRequestTask<R> extends AbstractPeerTask<R> {
}); });
} }
public PendingPeerRequest sendRequestToPeer(final PeerRequest request) {
return sendRequestToPeer(request, 0L);
}
public PendingPeerRequest sendRequestToPeer( public PendingPeerRequest sendRequestToPeer(
final PeerRequest request, final long minimumBlockNumber) { final PeerRequest request, final long minimumBlockNumber) {
return ethContext.getEthPeers().executePeerRequest(request, minimumBlockNumber, assignedPeer); return ethContext.getEthPeers().executePeerRequest(request, minimumBlockNumber, assignedPeer);

@ -103,7 +103,7 @@ public class GetBlockFromPeerTask extends AbstractPeerTask<Block> {
hash.map( hash.map(
value -> value ->
GetHeadersFromPeerByHashTask.forSingleHash( GetHeadersFromPeerByHashTask.forSingleHash(
protocolSchedule, ethContext, value, metricsSystem)) protocolSchedule, ethContext, value, blockNumber, metricsSystem))
.orElseGet( .orElseGet(
() -> () ->
GetHeadersFromPeerByNumberTask.forSingleNumber( GetHeadersFromPeerByNumberTask.forSingleNumber(

@ -83,12 +83,14 @@ public class GetBodiesFromPeerTask extends AbstractPeerRequestTask<List<Block>>
protected PendingPeerRequest sendRequest() { protected PendingPeerRequest sendRequest() {
final List<Hash> blockHashes = final List<Hash> blockHashes =
headers.stream().map(BlockHeader::getHash).collect(Collectors.toList()); headers.stream().map(BlockHeader::getHash).collect(Collectors.toList());
final long minimumRequiredBlockNumber = headers.get(headers.size() - 1).getNumber();
return sendRequestToPeer( return sendRequestToPeer(
peer -> { peer -> {
LOG.debug("Requesting {} bodies from peer {}.", blockHashes.size(), peer); LOG.debug("Requesting {} bodies from peer {}.", blockHashes.size(), peer);
return peer.getBodies(blockHashes); return peer.getBodies(blockHashes);
}); },
minimumRequiredBlockNumber);
} }
@Override @Override

@ -32,17 +32,20 @@ public class GetHeadersFromPeerByHashTask extends AbstractGetHeadersFromPeerTask
private static final Logger LOG = LoggerFactory.getLogger(GetHeadersFromPeerByHashTask.class); private static final Logger LOG = LoggerFactory.getLogger(GetHeadersFromPeerByHashTask.class);
private final Hash referenceHash; private final Hash referenceHash;
private final long minimumRequiredBlockNumber;
@VisibleForTesting @VisibleForTesting
GetHeadersFromPeerByHashTask( GetHeadersFromPeerByHashTask(
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash referenceHash, final Hash referenceHash,
final long minimumRequiredBlockNumber,
final int count, final int count,
final int skip, final int skip,
final boolean reverse, final boolean reverse,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
super(protocolSchedule, ethContext, count, skip, reverse, metricsSystem); super(protocolSchedule, ethContext, count, skip, reverse, metricsSystem);
this.minimumRequiredBlockNumber = minimumRequiredBlockNumber;
checkNotNull(referenceHash); checkNotNull(referenceHash);
this.referenceHash = referenceHash; this.referenceHash = referenceHash;
} }
@ -51,40 +54,65 @@ public class GetHeadersFromPeerByHashTask extends AbstractGetHeadersFromPeerTask
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash firstHash, final Hash firstHash,
final long firstBlockNumber,
final int segmentLength, final int segmentLength,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
return new GetHeadersFromPeerByHashTask( return new GetHeadersFromPeerByHashTask(
protocolSchedule, ethContext, firstHash, segmentLength, 0, false, metricsSystem); protocolSchedule,
ethContext,
firstHash,
firstBlockNumber,
segmentLength,
0,
false,
metricsSystem);
} }
public static AbstractGetHeadersFromPeerTask startingAtHash( public static AbstractGetHeadersFromPeerTask startingAtHash(
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash firstHash, final Hash firstHash,
final long firstBlockNumber,
final int segmentLength, final int segmentLength,
final int skip, final int skip,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
return new GetHeadersFromPeerByHashTask( return new GetHeadersFromPeerByHashTask(
protocolSchedule, ethContext, firstHash, segmentLength, skip, false, metricsSystem); protocolSchedule,
ethContext,
firstHash,
firstBlockNumber,
segmentLength,
skip,
false,
metricsSystem);
} }
public static AbstractGetHeadersFromPeerTask endingAtHash( public static AbstractGetHeadersFromPeerTask endingAtHash(
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash lastHash, final Hash lastHash,
final long lastBlockNumber,
final int segmentLength, final int segmentLength,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
return new GetHeadersFromPeerByHashTask( return new GetHeadersFromPeerByHashTask(
protocolSchedule, ethContext, lastHash, segmentLength, 0, true, metricsSystem); protocolSchedule,
ethContext,
lastHash,
lastBlockNumber,
segmentLength,
0,
true,
metricsSystem);
} }
public static AbstractGetHeadersFromPeerTask forSingleHash( public static AbstractGetHeadersFromPeerTask forSingleHash(
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash hash, final Hash hash,
final long minimumRequiredBlockNumber,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
return new GetHeadersFromPeerByHashTask( return new GetHeadersFromPeerByHashTask(
protocolSchedule, ethContext, hash, 1, 0, false, metricsSystem); protocolSchedule, ethContext, hash, minimumRequiredBlockNumber, 1, 0, false, metricsSystem);
} }
@Override @Override
@ -97,7 +125,8 @@ public class GetHeadersFromPeerByHashTask extends AbstractGetHeadersFromPeerTask
referenceHash.slice(0, 6), referenceHash.slice(0, 6),
peer); peer);
return peer.getHeadersByHash(referenceHash, count, skip, reverse); return peer.getHeadersByHash(referenceHash, count, skip, reverse);
}); },
minimumRequiredBlockNumber);
} }
@Override @Override

@ -80,7 +80,8 @@ public class GetHeadersFromPeerByNumberTask extends AbstractGetHeadersFromPeerTa
LOG.debug( LOG.debug(
"Requesting {} headers (blockNumber {}) from peer {}.", count, blockNumber, peer); "Requesting {} headers (blockNumber {}) from peer {}.", count, blockNumber, peer);
return peer.getHeadersByNumber(blockNumber, count, skip, reverse); return peer.getHeadersByNumber(blockNumber, count, skip, reverse);
}); },
blockNumber);
} }
@Override @Override

@ -39,6 +39,7 @@ public class RetryingGetHeadersEndingAtFromPeerByHashTask
private final Hash referenceHash; private final Hash referenceHash;
private final ProtocolSchedule protocolSchedule; private final ProtocolSchedule protocolSchedule;
private final long minimumRequiredBlockNumber;
private final int count; private final int count;
@VisibleForTesting @VisibleForTesting
@ -46,11 +47,13 @@ public class RetryingGetHeadersEndingAtFromPeerByHashTask
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash referenceHash, final Hash referenceHash,
final long minimumRequiredBlockNumber,
final int count, final int count,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final int maxRetries) { final int maxRetries) {
super(ethContext, metricsSystem, List::isEmpty, maxRetries); super(ethContext, metricsSystem, List::isEmpty, maxRetries);
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.minimumRequiredBlockNumber = minimumRequiredBlockNumber;
this.count = count; this.count = count;
checkNotNull(referenceHash); checkNotNull(referenceHash);
this.referenceHash = referenceHash; this.referenceHash = referenceHash;
@ -60,11 +63,18 @@ public class RetryingGetHeadersEndingAtFromPeerByHashTask
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash referenceHash, final Hash referenceHash,
final long minimumRequiredBlockNumber,
final int count, final int count,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final int maxRetries) { final int maxRetries) {
return new RetryingGetHeadersEndingAtFromPeerByHashTask( return new RetryingGetHeadersEndingAtFromPeerByHashTask(
protocolSchedule, ethContext, referenceHash, count, metricsSystem, maxRetries); protocolSchedule,
ethContext,
referenceHash,
minimumRequiredBlockNumber,
count,
metricsSystem,
maxRetries);
} }
@Override @Override
@ -72,7 +82,12 @@ public class RetryingGetHeadersEndingAtFromPeerByHashTask
final EthPeer currentPeer) { final EthPeer currentPeer) {
final AbstractGetHeadersFromPeerTask task = final AbstractGetHeadersFromPeerTask task =
GetHeadersFromPeerByHashTask.endingAtHash( GetHeadersFromPeerByHashTask.endingAtHash(
protocolSchedule, getEthContext(), referenceHash, count, getMetricsSystem()); protocolSchedule,
getEthContext(),
referenceHash,
minimumRequiredBlockNumber,
count,
getMetricsSystem());
task.assignPeer(currentPeer); task.assignPeer(currentPeer);
return executeSubTask(task::run) return executeSubTask(task::run)
.thenApply( .thenApply(

@ -73,6 +73,7 @@ public class ChainHeadTracker implements ConnectCallback {
protocolSchedule, protocolSchedule,
ethContext, ethContext,
Hash.wrap(peer.chainState().getBestBlock().getHash()), Hash.wrap(peer.chainState().getBestBlock().getHash()),
0,
metricsSystem) metricsSystem)
.assignPeer(peer) .assignPeer(peer)
.run() .run()

@ -96,6 +96,7 @@ public class DownloadHeadersStep
protocolSchedule, protocolSchedule,
ethContext, ethContext,
range.getStart().getHash(), range.getStart().getHash(),
range.getStart().getNumber(),
headerRequestSize, headerRequestSize,
metricsSystem) metricsSystem)
.assignPeer(range.getSyncTarget()) .assignPeer(range.getSyncTarget())

@ -76,6 +76,7 @@ public class BackwardSyncStep {
context.getProtocolSchedule(), context.getProtocolSchedule(),
context.getEthContext(), context.getEthContext(),
hash, hash,
0,
batchSize, batchSize,
context.getMetricsSystem(), context.getMetricsSystem(),
context.getEthContext().getEthPeers().peerCount()); context.getEthContext().getEthPeers().peerCount());

@ -171,7 +171,11 @@ public class FastSyncActions {
private CompletableFuture<FastSyncState> downloadPivotBlockHeader(final Hash hash) { private CompletableFuture<FastSyncState> downloadPivotBlockHeader(final Hash hash) {
LOG.debug("Downloading pivot block header by hash {}", hash); LOG.debug("Downloading pivot block header by hash {}", hash);
return RetryingGetHeaderFromPeerByHashTask.byHash( return RetryingGetHeaderFromPeerByHashTask.byHash(
protocolSchedule, ethContext, hash, metricsSystem) protocolSchedule,
ethContext,
hash,
pivotBlockSelector.getMinRequiredBlockNumber(),
metricsSystem)
.getHeader() .getHeader()
.whenComplete( .whenComplete(
(blockHeader, throwable) -> { (blockHeader, throwable) -> {

@ -137,7 +137,7 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
private CompletableFuture<BlockHeader> downloadBlockHeader(final Hash hash) { private CompletableFuture<BlockHeader> downloadBlockHeader(final Hash hash) {
return RetryingGetHeaderFromPeerByHashTask.byHash( return RetryingGetHeaderFromPeerByHashTask.byHash(
protocolSchedule, ethContext, hash, metricsSystem) protocolSchedule, ethContext, hash, 0, metricsSystem)
.getHeader() .getHeader()
.whenComplete( .whenComplete(
(blockHeader, throwable) -> { (blockHeader, throwable) -> {

@ -106,6 +106,7 @@ public class RangeHeadersFetcher {
protocolSchedule, protocolSchedule,
ethContext, ethContext,
referenceHeader.getHash(), referenceHeader.getHash(),
referenceHeader.getNumber(),
// + 1 because lastHeader will be returned as well. // + 1 because lastHeader will be returned as well.
headerCount + 1, headerCount + 1,
skip, skip,

@ -166,7 +166,12 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
// Ask for count + 1 because we'll retrieve the previous header as well // Ask for count + 1 because we'll retrieve the previous header as well
final AbstractGetHeadersFromPeerTask headersTask = final AbstractGetHeadersFromPeerTask headersTask =
GetHeadersFromPeerByHashTask.endingAtHash( GetHeadersFromPeerByHashTask.endingAtHash(
protocolSchedule, ethContext, referenceHash, count + 1, metricsSystem); protocolSchedule,
ethContext,
referenceHash,
referenceHeaderForNextRequest.getNumber(),
count + 1,
metricsSystem);
assignedPeer.ifPresent(headersTask::assignPeer); assignedPeer.ifPresent(headersTask::assignPeer);
return headersTask.run(); return headersTask.run();
}); });

@ -40,16 +40,19 @@ public class RetryingGetHeaderFromPeerByHashTask
LoggerFactory.getLogger(RetryingGetHeaderFromPeerByHashTask.class); LoggerFactory.getLogger(RetryingGetHeaderFromPeerByHashTask.class);
private final Hash referenceHash; private final Hash referenceHash;
private final ProtocolSchedule protocolSchedule; private final ProtocolSchedule protocolSchedule;
private final long minimumRequiredBlockNumber;
@VisibleForTesting @VisibleForTesting
RetryingGetHeaderFromPeerByHashTask( RetryingGetHeaderFromPeerByHashTask(
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash referenceHash, final Hash referenceHash,
final long minimumRequiredBlockNumber,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final int maxRetries) { final int maxRetries) {
super(ethContext, metricsSystem, List::isEmpty, maxRetries); super(ethContext, metricsSystem, List::isEmpty, maxRetries);
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.minimumRequiredBlockNumber = minimumRequiredBlockNumber;
checkNotNull(referenceHash); checkNotNull(referenceHash);
this.referenceHash = referenceHash; this.referenceHash = referenceHash;
} }
@ -58,11 +61,13 @@ public class RetryingGetHeaderFromPeerByHashTask
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final Hash referenceHash, final Hash referenceHash,
final long minimumRequiredBlockNumber,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
return new RetryingGetHeaderFromPeerByHashTask( return new RetryingGetHeaderFromPeerByHashTask(
protocolSchedule, protocolSchedule,
ethContext, ethContext,
referenceHash, referenceHash,
minimumRequiredBlockNumber,
metricsSystem, metricsSystem,
ethContext.getEthPeers().peerCount()); ethContext.getEthPeers().peerCount());
} }
@ -71,7 +76,11 @@ public class RetryingGetHeaderFromPeerByHashTask
protected CompletableFuture<List<BlockHeader>> executeTaskOnCurrentPeer(final EthPeer peer) { protected CompletableFuture<List<BlockHeader>> executeTaskOnCurrentPeer(final EthPeer peer) {
final AbstractGetHeadersFromPeerTask task = final AbstractGetHeadersFromPeerTask task =
GetHeadersFromPeerByHashTask.forSingleHash( GetHeadersFromPeerByHashTask.forSingleHash(
protocolSchedule, getEthContext(), referenceHash, getMetricsSystem()); protocolSchedule,
getEthContext(),
referenceHash,
minimumRequiredBlockNumber,
getMetricsSystem());
task.assignPeer(peer); task.assignPeer(peer);
return executeSubTask(task::run) return executeSubTask(task::run)
.thenApply( .thenApply(

@ -131,6 +131,7 @@ public final class EthProtocolManagerTest {
public void handleMalformedRequestIdMessage() { public void handleMalformedRequestIdMessage() {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -149,6 +150,7 @@ public final class EthProtocolManagerTest {
public void disconnectOnUnsolicitedMessage() { public void disconnectOnUnsolicitedMessage() {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -166,6 +168,7 @@ public final class EthProtocolManagerTest {
public void disconnectOnFailureToSendStatusMessage() { public void disconnectOnFailureToSendStatusMessage() {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -184,6 +187,7 @@ public final class EthProtocolManagerTest {
public void disconnectOnWrongChainId() { public void disconnectOnWrongChainId() {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -214,6 +218,7 @@ public final class EthProtocolManagerTest {
final MergePeerFilter mergePeerFilter = new MergePeerFilter(); final MergePeerFilter mergePeerFilter = new MergePeerFilter();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
transactionPool, transactionPool,
@ -262,6 +267,7 @@ public final class EthProtocolManagerTest {
public void doNotDisconnectOnLargeMessageWithinLimits() { public void doNotDisconnectOnLargeMessageWithinLimits() {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -281,6 +287,7 @@ public final class EthProtocolManagerTest {
public void disconnectOnWrongGenesisHash() { public void disconnectOnWrongGenesisHash() {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -310,6 +317,7 @@ public final class EthProtocolManagerTest {
public void doNotDisconnectOnValidMessage() { public void doNotDisconnectOnValidMessage() {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -331,6 +339,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -370,6 +379,7 @@ public final class EthProtocolManagerTest {
EthProtocolConfiguration.builder().maxGetBlockHeaders(limit).build(); EthProtocolConfiguration.builder().maxGetBlockHeaders(limit).build();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -406,6 +416,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -442,6 +453,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -481,6 +493,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -541,6 +554,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -578,6 +592,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -612,6 +627,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -664,6 +680,7 @@ public final class EthProtocolManagerTest {
EthProtocolConfiguration.builder().maxGetBlockBodies(limit).build(); EthProtocolConfiguration.builder().maxGetBlockBodies(limit).build();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -712,6 +729,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -754,6 +772,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -804,6 +823,7 @@ public final class EthProtocolManagerTest {
EthProtocolConfiguration.builder().maxGetReceipts(limit).build(); EthProtocolConfiguration.builder().maxGetReceipts(limit).build();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -851,6 +871,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -895,6 +916,7 @@ public final class EthProtocolManagerTest {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -942,6 +964,7 @@ public final class EthProtocolManagerTest {
public void newBlockMinedSendsNewBlockMessageToAllPeers() { public void newBlockMinedSendsNewBlockMessageToAllPeers() {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -1012,6 +1035,7 @@ public final class EthProtocolManagerTest {
final CompletableFuture<Void> done = new CompletableFuture<>(); final CompletableFuture<Void> done = new CompletableFuture<>();
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -1077,6 +1101,7 @@ public final class EthProtocolManagerTest {
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
ethScheduler, ethScheduler,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
@ -1110,6 +1135,7 @@ public final class EthProtocolManagerTest {
final EthScheduler ethScheduler = mock(EthScheduler.class); final EthScheduler ethScheduler = mock(EthScheduler.class);
try (final EthProtocolManager ethManager = try (final EthProtocolManager ethManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
ethScheduler, ethScheduler,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),

@ -48,12 +48,14 @@ import java.util.OptionalLong;
public class EthProtocolManagerTestUtil { public class EthProtocolManagerTestUtil {
public static EthProtocolManager create( public static EthProtocolManager create(
final ProtocolSchedule protocolSchedule,
final Blockchain blockchain, final Blockchain blockchain,
final TimeoutPolicy timeoutPolicy, final TimeoutPolicy timeoutPolicy,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
final TransactionPool transactionPool, final TransactionPool transactionPool,
final EthProtocolConfiguration ethereumWireProtocolConfiguration) { final EthProtocolConfiguration ethereumWireProtocolConfiguration) {
return create( return create(
protocolSchedule,
blockchain, blockchain,
new DeterministicEthScheduler(timeoutPolicy), new DeterministicEthScheduler(timeoutPolicy),
worldStateArchive, worldStateArchive,
@ -62,6 +64,7 @@ public class EthProtocolManagerTestUtil {
} }
public static EthProtocolManager create( public static EthProtocolManager create(
final ProtocolSchedule protocolSchedule,
final Blockchain blockchain, final Blockchain blockchain,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
final TransactionPool transactionPool, final TransactionPool transactionPool,
@ -71,6 +74,7 @@ public class EthProtocolManagerTestUtil {
EthPeers peers = EthPeers peers =
new EthPeers( new EthPeers(
EthProtocol.NAME, EthProtocol.NAME,
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
25, 25,
@ -145,15 +149,20 @@ public class EthProtocolManagerTestUtil {
} }
public static EthProtocolManager create(final Blockchain blockchain) { 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( public static EthProtocolManager create(
final ProtocolSchedule protocolSchedule,
final Blockchain blockchain, final Blockchain blockchain,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
final TransactionPool transactionPool, final TransactionPool transactionPool,
final EthProtocolConfiguration ethProtocolConfiguration) { final EthProtocolConfiguration ethProtocolConfiguration) {
return create( return create(
protocolSchedule,
blockchain, blockchain,
new DeterministicEthScheduler(TimeoutPolicy.NEVER_TIMEOUT), new DeterministicEthScheduler(TimeoutPolicy.NEVER_TIMEOUT),
worldStateArchive, worldStateArchive,
@ -166,10 +175,11 @@ public class EthProtocolManagerTestUtil {
final GenesisConfigFile config = GenesisConfigFile.mainnet(); final GenesisConfigFile config = GenesisConfigFile.mainnet();
final GenesisState genesisState = GenesisState.fromConfig(config, protocolSchedule); final GenesisState genesisState = GenesisState.fromConfig(config, protocolSchedule);
final Blockchain blockchain = createInMemoryBlockchain(genesisState.getBlock()); final Blockchain blockchain = createInMemoryBlockchain(genesisState.getBlock());
return create(blockchain, ethScheduler); return create(protocolSchedule, blockchain, ethScheduler);
} }
public static EthProtocolManager create( public static EthProtocolManager create(
final ProtocolSchedule protocolSchedule,
final Blockchain blockchain, final Blockchain blockchain,
final EthScheduler ethScheduler, final EthScheduler ethScheduler,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
@ -178,6 +188,7 @@ public class EthProtocolManagerTestUtil {
EthPeers peers = EthPeers peers =
new EthPeers( new EthPeers(
EthProtocol.NAME, EthProtocol.NAME,
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
25, 25,
@ -196,6 +207,7 @@ public class EthProtocolManagerTestUtil {
} }
public static EthProtocolManager create( public static EthProtocolManager create(
final ProtocolSchedule protocolSchedule,
final Blockchain blockchain, final Blockchain blockchain,
final EthScheduler ethScheduler, final EthScheduler ethScheduler,
final WorldStateArchive worldStateArchive, final WorldStateArchive worldStateArchive,
@ -205,6 +217,7 @@ public class EthProtocolManagerTestUtil {
EthPeers peers = EthPeers peers =
new EthPeers( new EthPeers(
EthProtocol.NAME, EthProtocol.NAME,
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
25, 25,
@ -224,10 +237,13 @@ public class EthProtocolManagerTestUtil {
} }
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 = EthPeers peers =
new EthPeers( new EthPeers(
EthProtocol.NAME, EthProtocol.NAME,
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
25, 25,

@ -90,6 +90,7 @@ public abstract class AbstractMessageTaskTest<T, R> {
spy( spy(
new EthPeers( new EthPeers(
EthProtocol.NAME, EthProtocol.NAME,
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
metricsSystem, metricsSystem,
MAX_PEERS, MAX_PEERS,

@ -69,7 +69,12 @@ public class GetHeadersFromPeerByHashTaskTest extends PeerMessageTaskTest<List<B
final List<BlockHeader> requestedData) { final List<BlockHeader> requestedData) {
final BlockHeader firstHeader = requestedData.get(0); final BlockHeader firstHeader = requestedData.get(0);
return GetHeadersFromPeerByHashTask.startingAtHash( return GetHeadersFromPeerByHashTask.startingAtHash(
protocolSchedule, ethContext, firstHeader.getHash(), requestedData.size(), metricsSystem); protocolSchedule,
ethContext,
firstHeader.getHash(),
firstHeader.getNumber(),
requestedData.size(),
metricsSystem);
} }
@Test @Test
@ -113,6 +118,7 @@ public class GetHeadersFromPeerByHashTaskTest extends PeerMessageTaskTest<List<B
protocolSchedule, protocolSchedule,
ethContext, ethContext,
blockchain.getBlockHashByNumber(startNumber).get(), blockchain.getBlockHashByNumber(startNumber).get(),
startNumber,
count, count,
skip, skip,
reverse, reverse,
@ -135,6 +141,8 @@ public class GetHeadersFromPeerByHashTaskTest extends PeerMessageTaskTest<List<B
@Test @Test
public void checkThatSequentialHeadersFormingAChainWorks() { public void checkThatSequentialHeadersFormingAChainWorks() {
final int startNumber = 1;
final BlockHeader block1 = final BlockHeader block1 =
new BlockHeaderTestFixture().number(1).parentHash(generateTestBlockHash(0)).buildHeader(); new BlockHeaderTestFixture().number(1).parentHash(generateTestBlockHash(0)).buildHeader();
final BlockHeader block2 = final BlockHeader block2 =
@ -145,7 +153,14 @@ public class GetHeadersFromPeerByHashTaskTest extends PeerMessageTaskTest<List<B
final AbstractGetHeadersFromPeerTask task = final AbstractGetHeadersFromPeerTask task =
new GetHeadersFromPeerByHashTask( new GetHeadersFromPeerByHashTask(
protocolSchedule, ethContext, block1.getHash(), 2, 0, false, metricsSystem); protocolSchedule,
ethContext,
block1.getHash(),
startNumber,
2,
0,
false,
metricsSystem);
final Optional<List<BlockHeader>> optionalBlockHeaders = final Optional<List<BlockHeader>> optionalBlockHeaders =
task.processResponse(false, BlockHeadersMessage.create(headers), peer); task.processResponse(false, BlockHeadersMessage.create(headers), peer);
assertThat(optionalBlockHeaders).isNotNull(); assertThat(optionalBlockHeaders).isNotNull();
@ -158,6 +173,7 @@ public class GetHeadersFromPeerByHashTaskTest extends PeerMessageTaskTest<List<B
@Test @Test
public void checkThatSequentialHeadersNotFormingAChainFails() { public void checkThatSequentialHeadersNotFormingAChainFails() {
final int startNumber = 1;
final BlockHeader block1 = final BlockHeader block1 =
new BlockHeaderTestFixture().number(1).parentHash(generateTestBlockHash(0)).buildHeader(); new BlockHeaderTestFixture().number(1).parentHash(generateTestBlockHash(0)).buildHeader();
final BlockHeader block2 = final BlockHeader block2 =
@ -168,7 +184,14 @@ public class GetHeadersFromPeerByHashTaskTest extends PeerMessageTaskTest<List<B
final AbstractGetHeadersFromPeerTask task = final AbstractGetHeadersFromPeerTask task =
new GetHeadersFromPeerByHashTask( new GetHeadersFromPeerByHashTask(
protocolSchedule, ethContext, block1.getHash(), 2, 0, false, metricsSystem); protocolSchedule,
ethContext,
block1.getHash(),
startNumber,
2,
0,
false,
metricsSystem);
final Optional<List<BlockHeader>> optionalBlockHeaders = final Optional<List<BlockHeader>> optionalBlockHeaders =
task.processResponse(false, BlockHeadersMessage.create(headers), peer); task.processResponse(false, BlockHeadersMessage.create(headers), peer);
assertThat(optionalBlockHeaders).isNotNull(); assertThat(optionalBlockHeaders).isNotNull();

@ -106,6 +106,7 @@ public abstract class AbstractBlockPropagationManagerTest {
tempProtocolContext.getConsensusContext(ConsensusContext.class)); tempProtocolContext.getConsensusContext(ConsensusContext.class));
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
blockchainUtil.getWorldArchive(), blockchainUtil.getWorldArchive(),
blockchainUtil.getTransactionPool(), blockchainUtil.getTransactionPool(),
@ -617,6 +618,7 @@ public abstract class AbstractBlockPropagationManagerTest {
new EthContext( new EthContext(
new EthPeers( new EthPeers(
"eth", "eth",
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
metricsSystem, metricsSystem,
25, 25,
@ -749,6 +751,7 @@ public abstract class AbstractBlockPropagationManagerTest {
new EthContext( new EthContext(
new EthPeers( new EthPeers(
"eth", "eth",
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
metricsSystem, metricsSystem,
25, 25,

@ -74,6 +74,7 @@ public class RangeHeadersFetcherTest {
public void setUpTest() { public void setUpTest() {
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),

@ -90,7 +90,9 @@ public class CheckPointSyncChainDownloaderTest {
protocolContext = localBlockchainSetup.getProtocolContext(); protocolContext = localBlockchainSetup.getProtocolContext();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); protocolSchedule,
localBlockchain,
new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()));
ethContext = ethProtocolManager.ethContext(); ethContext = ethProtocolManager.ethContext();
final int blockNumber = 10; final int blockNumber = 10;

@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; 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.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
@ -61,6 +62,7 @@ public class DownloadReceiptsStepTest {
TransactionPool transactionPool = mock(TransactionPool.class); TransactionPool transactionPool = mock(TransactionPool.class);
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
ProtocolScheduleFixture.MAINNET,
blockchain, blockchain,
() -> false, () -> false,
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),

@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.core.Difficulty; 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.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
@ -94,6 +95,7 @@ public class FastSyncActionsTest {
blockchain = blockchainSetupUtil.getBlockchain(); blockchain = blockchainSetupUtil.getBlockchain();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
ProtocolScheduleFixture.MAINNET,
blockchain, blockchain,
() -> timeoutCount.getAndDecrement() > 0, () -> timeoutCount.getAndDecrement() > 0,
blockchainSetupUtil.getWorldArchive(), blockchainSetupUtil.getWorldArchive(),

@ -89,7 +89,9 @@ public class FastSyncChainDownloaderTest {
protocolContext = localBlockchainSetup.getProtocolContext(); protocolContext = localBlockchainSetup.getProtocolContext();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
localBlockchain, new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); protocolSchedule,
localBlockchain,
new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()));
ethContext = ethProtocolManager.ethContext(); ethContext = ethProtocolManager.ethContext();
syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers());

@ -85,6 +85,7 @@ public class PivotBlockConfirmerTest {
protocolContext = blockchainSetupUtil.getProtocolContext(); protocolContext = blockchainSetupUtil.getProtocolContext();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
timeout::get, timeout::get,
blockchainSetupUtil.getWorldArchive(), blockchainSetupUtil.getWorldArchive(),

@ -88,6 +88,7 @@ public class PivotBlockRetrieverTest {
transactionPool = blockchainSetupUtil.getTransactionPool(); transactionPool = blockchainSetupUtil.getTransactionPool();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
blockchain, blockchain,
timeout::get, timeout::get,
blockchainSetupUtil.getWorldArchive(), blockchainSetupUtil.getWorldArchive(),

@ -64,6 +64,7 @@ public class FullSyncChainDownloaderForkTest {
protocolContext = localBlockchainSetup.getProtocolContext(); protocolContext = localBlockchainSetup.getProtocolContext();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
localBlockchain, localBlockchain,
new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()),
localBlockchainSetup.getWorldArchive(), localBlockchainSetup.getWorldArchive(),

@ -101,6 +101,7 @@ public class FullSyncChainDownloaderTest {
protocolContext = localBlockchainSetup.getProtocolContext(); protocolContext = localBlockchainSetup.getProtocolContext();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
localBlockchain, localBlockchain,
new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()),
localBlockchainSetup.getWorldArchive(), localBlockchainSetup.getWorldArchive(),

@ -84,6 +84,7 @@ public class FullSyncChainDownloaderTotalTerminalDifficultyTest {
protocolContext = localBlockchainSetup.getProtocolContext(); protocolContext = localBlockchainSetup.getProtocolContext();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
localBlockchain, localBlockchain,
new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()),
localBlockchainSetup.getWorldArchive(), localBlockchainSetup.getWorldArchive(),

@ -76,6 +76,7 @@ public class FullSyncDownloaderTest {
protocolContext = localBlockchainSetup.getProtocolContext(); protocolContext = localBlockchainSetup.getProtocolContext();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
localBlockchain, localBlockchain,
new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()),
localBlockchainSetup.getWorldArchive(), localBlockchainSetup.getWorldArchive(),

@ -83,6 +83,7 @@ public class FullSyncTargetManagerTest {
new ProtocolContext(localBlockchain, localWorldState, null); new ProtocolContext(localBlockchain, localWorldState, null);
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
localBlockchain, localBlockchain,
new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()), new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()),
localWorldState, localWorldState,

@ -144,6 +144,7 @@ public class DetermineCommonAncestorTaskParameterizedTest {
final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive();
final EthProtocolManager ethProtocolManager = final EthProtocolManager ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
localBlockchain, localBlockchain,
worldStateArchive, worldStateArchive,
mock(TransactionPool.class), mock(TransactionPool.class),

@ -80,6 +80,7 @@ public class DetermineCommonAncestorTaskTest {
final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive();
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
protocolSchedule,
localBlockchain, localBlockchain,
worldStateArchive, worldStateArchive,
mock(TransactionPool.class), mock(TransactionPool.class),

@ -132,6 +132,7 @@ public class TestNode implements Closeable {
final EthPeers ethPeers = final EthPeers ethPeers =
new EthPeers( new EthPeers(
EthProtocol.NAME, EthProtocol.NAME,
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()),
TestClock.fixed(), TestClock.fixed(),
metricsSystem, metricsSystem,
25, 25,

@ -40,6 +40,7 @@ import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter; import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager; import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; 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.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.testutil.TestClock;
@ -60,6 +61,7 @@ import org.mockito.junit.MockitoJUnitRunner;
public class TransactionPoolFactoryTest { public class TransactionPoolFactoryTest {
@Mock ProtocolSchedule schedule; @Mock ProtocolSchedule schedule;
@Mock ProtocolContext context; @Mock ProtocolContext context;
@Mock ProtocolSpec protocolSpec;
@Mock MutableBlockchain blockchain; @Mock MutableBlockchain blockchain;
@Mock EthContext ethContext; @Mock EthContext ethContext;
@Mock EthMessages ethMessages; @Mock EthMessages ethMessages;
@ -85,6 +87,7 @@ public class TransactionPoolFactoryTest {
ethPeers = ethPeers =
new EthPeers( new EthPeers(
"ETH", "ETH",
() -> protocolSpec,
TestClock.fixed(), TestClock.fixed(),
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
25, 25,

@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory;
@Value.Immutable @Value.Immutable
public interface NetstatsUrl { 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(); String getNodeName();

@ -21,7 +21,7 @@ import org.junit.Test;
public class NetstatsUrlTest { 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"; private final String CONTACT = "contact@mail.fr";
@ -34,7 +34,7 @@ public class NetstatsUrlTest {
assertThat(netstatsUrl.getHost()).isEqualTo("127.0.0.1"); assertThat(netstatsUrl.getHost()).isEqualTo("127.0.0.1");
assertThat(netstatsUrl.getNodeName()).isEqualTo("Dev-Node-1"); assertThat(netstatsUrl.getNodeName()).isEqualTo("Dev-Node-1");
assertThat(netstatsUrl.getPort()).isEqualTo(3001); assertThat(netstatsUrl.getPort()).isEqualTo(3001);
assertThat(netstatsUrl.getSecret()).isEqualTo("secret"); assertThat(netstatsUrl.getSecret()).isEqualTo("secret-with-dashes");
assertThat(netstatsUrl.getContact()).isEqualTo(CONTACT); assertThat(netstatsUrl.getContact()).isEqualTo(CONTACT);
} }

@ -1 +1 @@
Subproject commit 69c4c2a98dc8a712d4c6f5a817da4f21ff719006 Subproject commit 638da7ca7b2ca371ebb33d7d7d2562981aafd9b2

@ -82,7 +82,8 @@ public class NoRewardProtocolScheduleWrapper implements ProtocolSchedule {
original.getBadBlocksManager(), original.getBadBlocksManager(),
Optional.empty(), Optional.empty(),
original.getWithdrawalsValidator(), original.getWithdrawalsValidator(),
original.getWithdrawalsProcessor()); original.getWithdrawalsProcessor(),
original.isPoS());
} }
@Override @Override

@ -67,6 +67,7 @@ import org.hyperledger.besu.util.Subscribers;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
@ -191,9 +192,12 @@ public class RetestethContext {
// mining support // mining support
final Supplier<ProtocolSpec> currentProtocolSpecSupplier =
() -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader());
final EthPeers ethPeers = final EthPeers ethPeers =
new EthPeers( new EthPeers(
"reteseth", "reteseth",
currentProtocolSpecSupplier,
retestethClock, retestethClock,
metricsSystem, metricsSystem,
0, 0,

@ -80,6 +80,12 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
final MutableAccount account = frame.getWorldUpdater().getAccount(address).getMutable(); final MutableAccount account = frame.getWorldUpdater().getAccount(address).getMutable();
frame.clearReturnData(); 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 if (value.compareTo(account.getBalance()) > 0
|| frame.getMessageStackDepth() >= 1024 || frame.getMessageStackDepth() >= 1024
@ -88,12 +94,6 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
} else { } else {
account.incrementNonce(); 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); final Bytes inputData = frame.readMemory(inputOffset, inputSize);
// Never cache CREATEx initcode. The amount of reuse is very low, and caching mostly // Never cache CREATEx initcode. The amount of reuse is very low, and caching mostly
// addresses disk loading delay, and we already have the code. // addresses disk loading delay, and we already have the code.

@ -19,15 +19,13 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import ethereum.ckzg4844.CKZG4844JNI; import ethereum.ckzg4844.CKZG4844JNI;
@ -37,6 +35,9 @@ import org.jetbrains.annotations.NotNull;
/** The KZGPointEval precompile contract. */ /** The KZGPointEval precompile contract. */
public class KZGPointEvalPrecompiledContract implements PrecompiledContract { public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
private static final AtomicBoolean loaded = new AtomicBoolean(false);
private final Bytes successResult;
/** Instantiates a new KZGPointEval precompile contract. */ /** Instantiates a new KZGPointEval precompile contract. */
public KZGPointEvalPrecompiledContract() { public KZGPointEvalPrecompiledContract() {
@ -49,53 +50,41 @@ public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
* @param pathToTrustedSetup the trusted setup path * @param pathToTrustedSetup the trusted setup path
*/ */
public KZGPointEvalPrecompiledContract(final Optional<Path> pathToTrustedSetup) { public KZGPointEvalPrecompiledContract(final Optional<Path> pathToTrustedSetup) {
if (loaded.compareAndSet(false, true)) {
String absolutePathToSetup; String absolutePathToSetup;
CKZG4844JNI.Preset bitLength; if (pathToTrustedSetup.isPresent()) {
if (pathToTrustedSetup.isPresent()) { Path pathToSetup = pathToTrustedSetup.get();
Path pathToSetup = pathToTrustedSetup.get(); absolutePathToSetup = pathToSetup.toAbsolutePath().toString();
absolutePathToSetup = pathToSetup.toAbsolutePath().toString();
} else {
InputStream is =
KZGPointEvalPrecompiledContract.class.getResourceAsStream(
"mainnet_kzg_trusted_setup_4096.txt");
try {
File jniWillLoadFrom = File.createTempFile("kzgTrustedSetup", "txt");
jniWillLoadFrom.deleteOnExit();
Files.copy(is, jniWillLoadFrom.toPath(), REPLACE_EXISTING);
is.close();
absolutePathToSetup = jniWillLoadFrom.getAbsolutePath();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
try (BufferedReader setupFile =
Files.newBufferedReader(Paths.get(absolutePathToSetup), Charset.defaultCharset())) {
String firstLine = setupFile.readLine();
if ("4".equals(firstLine)) {
bitLength = CKZG4844JNI.Preset.MINIMAL;
} else if ("4096".equals(firstLine)) {
bitLength = CKZG4844JNI.Preset.MAINNET;
} else { } else {
throw new IllegalArgumentException("provided file not a setup for either 4 or 4096 bits"); InputStream is =
} KZGPointEvalPrecompiledContract.class.getResourceAsStream(
CKZG4844JNI.loadNativeLibrary(bitLength); "mainnet_kzg_trusted_setup_4096.txt");
try { try {
CKZG4844JNI.loadTrustedSetup(absolutePathToSetup); File jniWillLoadFrom = File.createTempFile("kzgTrustedSetup", "txt");
} catch (RuntimeException mightBeAlreadyLoaded) { jniWillLoadFrom.deleteOnExit();
if (!mightBeAlreadyLoaded.getMessage().contains("Trusted Setup is already loaded")) { Files.copy(is, jniWillLoadFrom.toPath(), REPLACE_EXISTING);
throw mightBeAlreadyLoaded; is.close();
absolutePathToSetup = jniWillLoadFrom.getAbsolutePath();
} catch (IOException e) {
throw new RuntimeException(e);
} }
} }
} catch (IOException e) { CKZG4844JNI.loadNativeLibrary(CKZG4844JNI.Preset.MAINNET);
throw new RuntimeException(e); CKZG4844JNI.loadTrustedSetup(absolutePathToSetup);
} }
Bytes fieldElementsPerBlob =
Bytes32.wrap(Bytes.ofUnsignedInt(CKZG4844JNI.getFieldElementsPerBlob()).xor(Bytes32.ZERO));
Bytes blsModulus =
Bytes32.wrap(Bytes.of(CKZG4844JNI.BLS_MODULUS.toByteArray()).xor(Bytes32.ZERO));
successResult = Bytes.concatenate(fieldElementsPerBlob, blsModulus);
} }
/** free up resources. */ /** free up resources. */
@VisibleForTesting @VisibleForTesting
public void tearDown() { public void tearDown() {
CKZG4844JNI.freeTrustedSetup(); CKZG4844JNI.freeTrustedSetup();
loaded.set(false);
} }
@Override @Override
@ -126,7 +115,6 @@ public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
Bytes commitment = input.slice(96, 48); Bytes commitment = input.slice(96, 48);
Bytes proof = input.slice(144, 48); Bytes proof = input.slice(144, 48);
Bytes output = Bytes.EMPTY;
PrecompileContractResult result; PrecompileContractResult result;
try { try {
boolean proved = boolean proved =
@ -134,21 +122,13 @@ public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
commitment.toArray(), z.toArray(), y.toArray(), proof.toArray()); commitment.toArray(), z.toArray(), y.toArray(), proof.toArray());
if (proved) { if (proved) {
Bytes fieldElementsPerBlob =
Bytes32.wrap(
Bytes.of(CKZG4844JNI.getFieldElementsPerBlob()).xor(Bytes32.ZERO)); // usually 4096
Bytes blsModulus =
Bytes32.wrap(Bytes.of(CKZG4844JNI.BLS_MODULUS.toByteArray()).xor(Bytes32.ZERO));
output = Bytes.concatenate(fieldElementsPerBlob, blsModulus);
result = result =
new PrecompileContractResult( new PrecompileContractResult(
output, false, MessageFrame.State.COMPLETED_SUCCESS, Optional.empty()); successResult, false, MessageFrame.State.COMPLETED_SUCCESS, Optional.empty());
} else { } else {
result = result =
new PrecompileContractResult( new PrecompileContractResult(
output, Bytes.EMPTY,
false, false,
MessageFrame.State.COMPLETED_FAILED, MessageFrame.State.COMPLETED_FAILED,
Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR));
@ -158,7 +138,7 @@ public class KZGPointEvalPrecompiledContract implements PrecompiledContract {
System.out.println(kzgFailed.getMessage()); System.out.println(kzgFailed.getMessage());
result = result =
new PrecompileContractResult( new PrecompileContractResult(
output, Bytes.EMPTY,
false, false,
MessageFrame.State.COMPLETED_FAILED, MessageFrame.State.COMPLETED_FAILED,
Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR));

@ -15,77 +15,79 @@
package org.hyperledger.besu.evm.precompile; package org.hyperledger.besu.evm.precompile;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import ethereum.ckzg4844.CKZG4844JNI; import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.AfterAll;
import org.junit.BeforeClass; import org.junit.jupiter.api.BeforeAll;
import org.junit.Test; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class KZGPointEvalPrecompileContractTest { public class KZGPointEvalPrecompileContractTest {
private static KZGPointEvalPrecompiledContract contract; private static KZGPointEvalPrecompiledContract contract;
private final MessageFrame toRun = mock(MessageFrame.class); private final MessageFrame toRun = mock(MessageFrame.class);
@BeforeClass @BeforeAll
public static void init() { public static void init() {
Path testSetupAbsolutePath = Path testSetupAbsolutePath =
Path.of( Path.of(
KZGPointEvalPrecompileContractTest.class.getResource("trusted_setup_4.txt").getPath()); KZGPointEvalPrecompileContractTest.class
.getResource("trusted_setup_4096.txt")
.getPath());
contract = new KZGPointEvalPrecompiledContract(Optional.of(testSetupAbsolutePath)); contract = new KZGPointEvalPrecompiledContract(Optional.of(testSetupAbsolutePath));
} }
@Test @AfterAll
public void happyPath() { public static void tearDown() {
Bytes input = contract.tearDown();
Bytes.fromHexString(
"013c03613f6fc558fb7e61e75602241ed9a2f04e36d8670aadd286e71b5ca9cc420000000000000000000000000000000000000000000000000000000000000031e5a2356cbc2ef6a733eae8d54bf48719ae3d990017ca787c419c7d369f8e3c83fac17c3f237fc51f90e2c660eb202a438bc2025baded5cd193c1a018c5885bc9281ba704d5566082e851235c7be763b2a99adff965e0a121ee972ebc472d02944a74f5c6243e14052e105124b70bf65faf85ad3a494325e269fad097842cba");
Bytes fieldElementsPerBlob =
Bytes32.wrap(Bytes.ofUnsignedInt(CKZG4844JNI.getFieldElementsPerBlob()).xor(Bytes32.ZERO));
Bytes blsModulus =
Bytes32.wrap(Bytes.of(CKZG4844JNI.BLS_MODULUS.toByteArray()).xor(Bytes32.ZERO));
Bytes expectedOutput = Bytes.concatenate(fieldElementsPerBlob, blsModulus);
// contract input is encoded as follows: versioned_hash | z | y | commitment | proof |
PrecompiledContract.PrecompileContractResult result = contract.computePrecompile(input, toRun);
assertThat(result.getOutput()).isEqualTo(expectedOutput);
MessageFrame.State endState = result.getState();
assertThat(endState).isEqualTo(MessageFrame.State.COMPLETED_SUCCESS);
} }
@Test @ParameterizedTest(name = "{index}")
public void sadPaths() { @MethodSource("getPointEvaluationPrecompileTestVectors")
try (InputStream failVectors = public void testComputePrecompile(final PrecompileTestParameters parameters) {
KZGPointEvalPrecompileContractTest.class.getResourceAsStream("fail_pointEvaluation.json")) { PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(parameters.input, toRun);
ObjectMapper jsonMapper = new ObjectMapper(); if (parameters.valid) {
JsonNode failJson = jsonMapper.readTree(failVectors); assertThat(result.getState()).isEqualTo(MessageFrame.State.COMPLETED_SUCCESS);
assertThat(result.getOutput()).isEqualTo(parameters.returnValue);
for (JsonNode testCase : failJson) { } else {
assertThat(result.getState()).isNotEqualTo(MessageFrame.State.COMPLETED_SUCCESS);
Bytes input = Bytes.fromHexString(testCase.get("Input").asText()); }
}
PrecompiledContract.PrecompileContractResult result = public static List<PrecompileTestParameters> getPointEvaluationPrecompileTestVectors()
contract.computePrecompile(input, toRun); throws IOException {
MessageFrame.State endState = result.getState(); final JsonNode jsonNode;
assertThat(endState).isEqualTo(MessageFrame.State.COMPLETED_FAILED); try (final InputStream testVectors =
assertThat(result.getHaltReason()).isPresent(); KZGPointEvalPrecompileContractTest.class.getResourceAsStream(
assertThat(result.getHaltReason().get()).isEqualTo(ExceptionalHaltReason.PRECOMPILE_ERROR); "pointEvaluationPrecompile.json")) {
} jsonNode = new ObjectMapper().readTree(testVectors);
} catch (IOException ioe) {
fail("couldn't load test vectors", ioe);
} }
final ArrayNode testCases = (ArrayNode) jsonNode.get("TestCases");
final Bytes returnValue = Bytes.fromHexString(jsonNode.get("PrecompileReturnValue").asText());
return IntStream.range(0, testCases.size())
.mapToObj(
i -> {
final JsonNode testCase = testCases.get(i);
final Bytes input = Bytes.fromHexString(testCase.get("Input").asText());
final boolean valid = testCase.get("Valid").asBoolean();
return new PrecompileTestParameters(input, valid, returnValue);
})
.collect(Collectors.toList());
} }
record PrecompileTestParameters(Bytes input, boolean valid, Bytes returnValue) {}
} }

@ -0,0 +1,170 @@
{
"PrecompileReturnValue": "000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001",
"TestCases": [
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "",
"Valid": true
},
{
"Input": "012801238108394529333e45adfaff59edde33727fa766ee99752921b472893611f5bc1101693a3a77098f71ec13c7ccaf4542a037b9397dd4ebe522e05d9d47629f4dddbcf4a5c28f5b09c9bee1895d3de14ea9312df7cf607d09517eb7863dabb6bcbe313530ce7779abdf633d5a3594a41fbad9a79f4a9b46b89c0cfe78f6a15948dec92c4404aedac8b5e7dd60598a963e56a55c2659c306beeb49ac79b7bd375fad150619b2fb5d835ee8f8305c3aac541ca6adad9be851b4f6dca5cd73",
"FailureMode": "",
"Valid": true
},
{
"Input": "0116f63b849a1a5704c55538e61f3576b09fe82fe038a39c96a3cd97986777a97ca4870f96b96f3c0ccef8ebccb186d1df0eccad55374fcf2262bc32e224763f5ac3abbe48a5c2f3731087f86bbf567910fe098f6183a2be6c1bd97ed2e1c562a4429aefed1de5145c9426c68b2fa5dc9ac0bd0c7d0420e0763824849abf47ff9be8942d481525d54dbf8d2508490e42a5e6166b8755b63c54b54802049c01c4a79b6c55b3cf3b7a22e9382cf4960f703b339622aa530e0961ef6747faf3ebf3",
"FailureMode": "",
"Valid": true
},
{
"Input": "01aebaf22aa7b4019a4917f97176f9c0e79513f1e297b4daef1158fbed94f8afe753520d2b0aa53ea1926266ad4f46d60fd855bb73b5642171d89242e4eb4e3735096476da0d660f9e2913bbe7d29301fa96a178d02349323fac041d6ac1070d934abbb7ff0028c06ce8d27accbf0312fd4bfd55e58e6d8920aaf9d7d51f1a59ac00b34e7eedf5464ddf69b3c6e3e8d1b577b30ec9d82eb5e56827c875fb33892e29b504198fa7a6b196ac7cd6d64838ca452d94adeb57f1ae4b5d894d26d616",
"FailureMode": "",
"Valid": true
},
{
"Input": "016ee58067bdbc41ad3978fb379e8fe3ab0bc4cda0f131ee9baf2db213cd4dc552031d0bc05ada403657cce08ded05db3fa1dfc891337a73bf4e6952e6b2272f02b04885539a8052bd8e104f6f894fca92355da265a04fc5a16b2fca2e016252a90cf079520942b69d207a57445406dc1f539f60467cf2bcd805814190ea87280103f02e68e50a314b25dea197c2543488e5992ffd5e03890ef5c362569a670b955cb11d923b176b152750e853190ee7dd6b56074f009580e191d79e3888bc26",
"FailureMode": "",
"Valid": true
},
{
"Input": "01bbbb1a74e35dd8cb8faec442693b1355f40ab9d0b44c47a9ec8ff197987929bdb2e70855ab0f43cb1b365b6e8bc5df6f6a69d6afb18fc50dc53f62e879002728aa2577ad9b59293956d5d76783b1e54c1777d3ebc2ac5dea349f10a66735399913a98b55d225411649847f9cf0c5afedf4f30623392cea17ed509864d8e0d87ecfa303e0f9c9c083456d9125a3a8d5b723e9a64edda406fc74ab8685039dd6039b6d2f8ed8d15887776860d7ea57a3767410a4eb46bba045f925b41e2fa299",
"FailureMode": "",
"Valid": true
},
{
"Input": "01792bd31013b362e1383652ea9c6d7d0f6c7880f4478eab785923d2a24417fe2862b206eafb444560e09fd54e2985e49f33f3e3cd2fa5175c3b1672ea40d91e808310a87ca1c24a2b2258c38e495d0df51d1cea6c11431679cc04a8468c9f5a86bdcd35acafb637235ccb8c908332cea2ca9e4efa5afc66c24f9f3ea0281ff3c588b147d90844248b36b79cbae7d016b6c46951710384a5fc425bfc89f804b9bfe0148805c54162a4ec091e5bf063db88577b12b9839def3fb15ab4b15e46e8",
"FailureMode": "",
"Valid": true
},
{
"Input": "0111c228100fd51f22a0be9e86211f971ab6c7a5dfe6988b5b45e159c77d937b93117d047f4c7a47f5a409502fc744e9cffc7cf1ebadba69aab1ec81ec07b2166770490221efc59c136280d4152adcfee9dbd2d17b6b727a4838373258054631b416564857a5239934c918dd7ce1585016082ca9bb79a0626d1ccb00afcd458910d69b36e69752791ff49736af318707855231b9ecc3cd8ed8f52eb31673482ad804ccaeeadb91fda7104f90b483d609fefa5b677efe9ceb772a4d80decbf404",
"FailureMode": "",
"Valid": true
},
{
"Input": "016d0d27b2a1b5266e1f6fe2f987bff57bd67157222831d9260f782dbf85e957fec04702149daf498a6973ca0f6504eeffc506ff092cd0bbf827c391eece8a0e004ddc8a839cd6c7d381795dd08e8ef23e97f59e7c34457f3aa802b5edbba35a94c3f402eb91cf43a4f502d486f22f0f04bd99c1a8180353d93e6c612ddb22c7838d3e03c471b4289bd2fd5060a615379172bbbf1f4606d3c777886412b18c5e551b098d9373cec1957dc333e9b83d0306941c61a7a0fdf031f243c4e2fc0919",
"FailureMode": "",
"Valid": true
},
{
"Input": "011459b168df56c35b2a1712329aabd7f904735dfb7e948b12869a4396d7cb9e69701200a9ede44b1f2edd44f002c4f22f8f900c28aae50d479e99a1f0956306740e0b40715e2d1d5b32c1960253f8a2b2c32db833279863237e1da14867b24b840eedd5e97ba21d82aaa67583b8f9b8936b1d0e11e69c77ab9f8381cf47f3013dc258944bf04fd91fe5663aa33b5397a05bcb8545682fbdc37663bbf01010c13164a422915a9c8961efe82825fb68302a3435ed2cf7e01bbac059a420277f05",
"FailureMode": "",
"Valid": true
},
{
"Input": "01dc43cf428476b6fde56262f081988eeeb5ae6e665a2fcbcd667f93b474ebc9d51fddfd3c3e1a4eb34e45bfd344414b6530bc234e003593dd910ddb45042a72c1f4fd101b80df1af58a2d77804c711e999d09a90f2e379ef18c752dd3866e34ac51bce1515c3df45ee85b5342c88291288a171f8799d31b1e77ff2d692f3f1f6880e2fd0262132fdaac0e4245958fafaaed1182c6af9f27f01e9e0c47dd3278496c3d3b4126c9f62a6fb81542d3223a480323fa09fb524ad4f70c83f46150f1",
"FailureMode": "",
"Valid": true
},
{
"Input": "0111c36a6aa83254e02e96995ac0ac766f5edadd8044fd0170d4e459df72267a40cfa7fbd18e4f504813af39b4e2005095f945316c7e4ae52b08e4ea47cb026a43dfedc72048fbe7a9107e8abcdca472f722cd3327c78a6a1dd475d556e1063f8a6775af1fb1d442d7fef688d3e34aa7055e131fa13be05528cde77479d33ffd2f21708b479d3e36fabff48ccaceec19acbd62bfac28c7f29f62e0e3b8587fb50abd49370c1e164f3555abbe9199aabacf170d7c39beafb36506ec73847a6729",
"FailureMode": "",
"Valid": true
},
{
"Input": "014adbe3d78e1a41777dc899baa9597dc97bcffa2bc6d8f79fe9de417078d8f8ab7e72f966df8452ddd718b49480c054c5c2cf3e8afc5f377a7ebafa4992db617d7ec99ffb7dac5dd4d5dc011447816b11b46094b584d5070fb620ef71edb114a8d63144a4ed21007c816a63e56701ad142dd4a26feaf9249040246b1b290450fac06edfc3f223e98aca2b7c758c459884b90ccabd00e842e492ffdea7495f3732dd2cfe142892400089b121bcac3dd21ab347d0f6dc092f23710354ea071438",
"FailureMode": "",
"Valid": true
},
{
"Input": "01cbb255a9e362102497d90841b3099aa812f281980b20c12951fdfdc30204c7162e3df7fb2fba54729c822e751e8059f58b594ca87a7589c8f4900a4c59b45904ec35e25ea7595f7e7352abbe50d6c1fa57c612b43cf77d17ab598ffa0f023f8a20f1cbae3472de159c30b66bcec852689326c449720ffeaa87d5b86629489ce1a5c660bb06c2a2539dcf1438d2c960a246002bcfe66adb8f9463c873b855ade410313c5128a8adfab5492da5e662cc556999ee653b697a449a21628c1585c7",
"FailureMode": "",
"Valid": true
},
{
"Input": "0103a676648fcc81830d61b0b07937aaf48690aeda04d5b02b5a251bd5ca5c4f81dd07f59080ef560761eca855bc3f5e2555e359c6f88adb166b671a4e208d51e6ecb876da33438c5cf8fe1463008e14d012cda7365474e61148e2eb76d3910a852f33ed26a17a7a6b9db96b03c110d5709251a5377d0e86d4349bce0610d01ae2d6c4e2a45aea1d20822988bcbca345b17fca68d1b4024f157d9b81f57ff2917d0101f8e02cc05ae8c6655102b4dd55d8461c6f971f5111f1f0b82338837cb5",
"FailureMode": "",
"Valid": true
},
{
"Input": "01e7ab7a7aaea9ee3e2fc8d17bde6badc12e2bf824bfe8db0eafc43dd0762bf1ec8cd2f225d124599c255623365aff62551e6d67e476a02d65e13d2a50e76549efae7b3b28a8d235894e618237f4abaffaa500fff7cb926e9309a7d4fe7eb53cab1484ed8e82a622d2647871e0e784fc676e55047dde4cf156b2036f937562dfff92102fd993352513fb75913935b47e89dc14149659b5d999abd29d2fc33f76b287b0140434c6c26c214fb0aa3f1ac27369ea89f4b2ab79aa03040720d32c67",
"FailureMode": "",
"Valid": true
},
{
"Input": "010b73d38034466a538f1acaf463f7575d3d3f4baa23dcf6d559700e8fb5fd82573c9df0ba215a5b31eabf9d16f8be6785e7f67402f5b57fb357143a52ae3e4144abb69b6b607cce5f1830f05ad98f8c184d39a1c76d860876fffb5852fc450fa372cb9c0a5b0c14406f59e4926acde14f737d69d4a926906fbabad357e743f2ecab5a7da7e5384dca593697eaeaf58aa1b8b02d82fac14d98121dae7e04d9f3e38a5fc4164e0d0dd6692ba0b55b8063d4aee0987a0f811396617f4045609a71",
"FailureMode": "",
"Valid": true
},
{
"Input": "013e3ff78fc9bb6c6564d205fe1064aa6e11eddef9f0e985d8f364005d03c22fc2eb67ee4f728f5dc6ae2918f7957e6cb5b080822073cbd101ceea4954751739e3e04001d6c2037a831ff7ad639fbdb277264edd75b50d025eb183120464f940a86e11eedc9683475153b147c8ce10ae29495aed6cf2e58c5c3385f1be4d2162696d0488a94b4a2a552eeb0502eae3cc80049aaaf808839090c40d57463ffb5b56228d88f2329b5811ac7f5931085fa7360876a58893cc049debf820bc7ab88b",
"FailureMode": "",
"Valid": true
},
{
"Input": "019f4cc64584a59f7d924fb921ede13a7a04c1d595bdd96ba66722baeb145e862d9b32ece4c2c45f5b739392d7333e71e5790a903ef1e0235044c159563cf0309ae1b4c885a4afeb472ccf74b3ec7d68044ab28890a647d76939d31097645025817785fe342e0354ee0845753542d0eaff5c0acb9a7c2206de60c930a57c81b6db2e2b414ba3ab2730f3364f7d35dfdfa4df917a3c7c9e3457871234e6bf9a35ad025f0e40ef2a2502a5024c7f0ce709cc27c3bd2399c9a1ec02238d38124c9e",
"FailureMode": "",
"Valid": true
},
{
"Input": "0128f689b5b1121319a69abacd871979a1075506bd04ac7f08399a1996626201984afde97913fa61f037fd0cb8d1fd751543949d5c6ff6759eba97695803c9284b3b9280d5b4d8f18181f4a0d199bd69e63463b75a2722835b23fe5145711a5997885c37b0edb98b1569af211135fa3b2ec29871005ef58bd429533bbabb70275840fec04fdd4fc327c730d0919fb0d08bd1b47fac65f7874afc7d394b5873c48c82a70e67c5c4dac616896fcec24df35f7e1ac5a6236927671d11aaa0a25c71",
"FailureMode": "",
"Valid": true
},
{
"Input": "",
"FailureMode": "incorrectPrecompileLength",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac5",
"FailureMode": "incorrectPrecompileLength",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "incorrectPrecompileLength",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682c3b23e313cacf2ce5e5e13219c5a54851bc51a0ef723a0e13805186b13f245a7ebbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "nonCanonicalInputPoint",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44f98b392451fdc18899c205e8b9f9286daf331b974cba0af44e3343dc307b3baeca97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "nonCanonicalOutputPoint",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "cannotDeserialiseCommitment",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "cannotDeserialiseCommitment",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"FailureMode": "cannotDeserialiseProof",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"FailureMode": "cannotDeserialiseProof",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea84676820000000000000000000000000000000000000000000000000000000000000000ebbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "invalidOpening",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44f0000000000000000000000000000000000000000000000000000000000000000a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "invalidOpening",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8cd9ff4ff4f98ba4ea89e80747cfdc694ac9969b841c8d558dc41bceb3c8f97c8c48c1409304ec70176c4e24fc7f6fa",
"FailureMode": "invalidOpening",
"Valid": false
},
{
"Input": "01c357eb79e30f84b7f1b78e2dc064d5e889714a94a879218ffe6ffea8467682a645f2136c180538e24425f70b7607c87f7cb892193b242b86750f13de96c44febbab307c43d34e34553a2cb7115749fd5aef0958386e668419b3ef6f1eac524a97456b8097baed6e90ce381d2b21c970a3f9ad4f6c92b1bb26337f919bd639dd43bd470839153db09115e2862051f33c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"FailureMode": "invalidOpening",
"Valid": false
}
]
}

@ -1,71 +0,0 @@
4
65
97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb
854262641262cb9e056a8512808ea6864d903dbcad713fd6da8dddfa5ce40d85612c912063ace060ed8c4bf005bab839
86f708eee5ae0cf40be36993e760d9cb3b2371f22db3209947c5d21ea68e55186b30871c50bf11ef29e5248bf42d5678
94f9c0bafb23cbbf34a93a64243e3e0f934b57593651f3464de7dc174468123d9698f1b9dfa22bb5b6eb96eae002f29f
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save