Merge branch 'main' of github.com:hyperledger/besu into 5561migrate-tests-to-Junit5

5561migrate-tests-to-Junit5
Sally MacFarlane 1 year ago
commit 2d350cf7f3
  1. 48
      .circleci/config.yml
  2. 16
      CHANGELOG.md
  3. 9
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/OpenTelemetryAcceptanceTest.java
  4. 8
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineCancunBlockBuildingAcceptanceTest.java
  5. 17
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/01_cancun_send_blob_tx.json
  6. 47
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/02_cancun_get_blob_tx.json
  7. 15
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/03_cancun_send_blob_tx.json
  8. 15
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/04_cancun_send_blob_tx.json
  9. 15
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/05_cancun_send_blob_tx.json
  10. 17
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/06_cancun_send_blob_tx.json
  11. 17
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/07_cancun_send_blob_tx.json
  12. 17
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/08_cancun_send_blob_tx.json
  13. 96
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/10_cancun_build_on_genesis.json
  14. 205
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/block-production/12_cancun_get_built_block.json
  15. 8
      besu/src/main/java/org/hyperledger/besu/chainimport/RlpBlockImporter.java
  16. 32
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  17. 49
      besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java
  18. 22
      besu/src/main/java/org/hyperledger/besu/cli/options/TransactionPoolOptions.java
  19. 86
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java
  20. 14
      besu/src/main/java/org/hyperledger/besu/components/BesuComponent.java
  21. 38
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  22. 25
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  23. 5
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  24. 18
      besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java
  25. 111
      besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java
  26. 15
      besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java
  27. 1
      besu/src/test/resources/everything_config.toml
  28. 2
      build.gradle
  29. 8320
      config/src/main/resources/kzg-trusted-setups/mainnet.txt
  30. 1
      consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java
  31. 1
      consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java
  32. 1
      consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java
  33. 1
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java
  34. 2
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java
  35. 1
      consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java
  36. 1
      consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java
  37. 15
      datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java
  38. 63
      datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java
  39. 15
      datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java
  40. 15
      datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGProof.java
  41. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java
  42. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java
  43. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java
  44. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java
  45. 84
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractTraceCall.java
  46. 91
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceCall.java
  47. 45
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java
  48. 81
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceCall.java
  49. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java
  50. 17
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/StructLog.java
  51. 11
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/DebugJsonRpcMethods.java
  52. 8
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugJsonRpcHttpBySpecTest.java
  53. 41
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/DebugTraceJsonRpcHttpBySpecTest.java
  54. 9
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugJsonRpcHttpBySpecTest.java
  55. 41
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/forest/DebugTraceJsonRpcHttpBySpecTest.java
  56. 75
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java
  57. 29
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java
  58. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/account-at/debug_accountAt.json
  59. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/account-range/debug_accountRange_blockHash.json
  60. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/account-range/debug_accountRange_complete.json
  61. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/account-range/debug_accountRange_partial.json
  62. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/batch-send-raw-transaction/debug_batchSendRawTransaction_multipleTxError.json
  63. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/batch-send-raw-transaction/debug_batchSendRawTransaction_multipleTxMixedStatuses.json
  64. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/batch-send-raw-transaction/debug_batchSendRawTransaction_multipleTxSuccess.json
  65. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/batch-send-raw-transaction/debug_batchSendRawTransaction_singleTxError.json
  66. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/batch-send-raw-transaction/debug_batchSendRawTransaction_singleTxErrorInvalidSignatureV.json
  67. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/batch-send-raw-transaction/debug_batchSendRawTransaction_singleTxSuccess.json
  68. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/storage-range/debug_storageRangeAt_blockHash.json
  69. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/storage-range/debug_storageRangeAt_blockNumber.json
  70. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/storage-range/debug_storageRangeAt_midBlock.json
  71. 300
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_all.json
  72. 297
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_complete.json
  73. 300
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_disableMemory.json
  74. 300
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_disableStack.json
  75. 300
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-call/debug_traceCall_disableStorage.json
  76. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-transaction/debug_traceTransaction_complete.json
  77. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-transaction/debug_traceTransaction_disableMemory.json
  78. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-transaction/debug_traceTransaction_disableStack.json
  79. 0
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/debug/trace-transaction/debug_traceTransaction_disableStorage.json
  80. 75
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java
  81. 1
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java
  82. 89
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java
  83. 6
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java
  84. 4
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java
  85. 1
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java
  86. 7
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java
  87. 12
      ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java
  88. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java
  89. 14
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java
  90. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogManager.java
  91. 194
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/trielog/TrieLogPruner.java
  92. 9
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/Blockchain.java
  93. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java
  94. 25
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
  95. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionDecoder.java
  96. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/debug/TraceFrame.java
  97. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampBoundedByFutureParameter.java
  98. 1
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java
  99. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java
  100. 34
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -4,14 +4,6 @@ orbs:
win: circleci/windows@5.0 win: circleci/windows@5.0
executors: executors:
besu_executor_small:
docker:
- image: cimg/openjdk:17.0
resource_class: small
working_directory: ~/project
environment:
GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=2
besu_executor_med: # 2cpu, 4G ram besu_executor_med: # 2cpu, 4G ram
docker: docker:
- image: cimg/openjdk:17.0 - image: cimg/openjdk:17.0
@ -189,7 +181,7 @@ jobs:
- capture_test_results - capture_test_results
integrationTests: integrationTests:
executor: xl_machine_executor executor: xl_machine_executor # needs the machine executor since privacy test uses container tests (docker)
steps: steps:
- prepare - prepare
- attach_workspace: - attach_workspace:
@ -219,8 +211,8 @@ jobs:
- capture_test_results - capture_test_results
acceptanceTests: acceptanceTests:
parallelism: 4 parallelism: 2
executor: xl_machine_executor executor: xl_machine_executor # needs the machine executor since privacy test uses container tests (docker)
steps: steps:
- prepare - prepare
- attach_workspace: - attach_workspace:
@ -241,8 +233,7 @@ jobs:
- capture_test_logs - capture_test_logs
acceptanceTestsCliqueBft: acceptanceTestsCliqueBft:
parallelism: 6 executor: besu_executor_xl
executor: xl_machine_executor
steps: steps:
- prepare - prepare
- attach_workspace: - attach_workspace:
@ -251,20 +242,13 @@ jobs:
name: AcceptanceTests (Non-Mainnet) name: AcceptanceTests (Non-Mainnet)
no_output_timeout: 20m no_output_timeout: 20m
command: | command: |
CLASSNAMES=$(circleci tests glob "acceptance-tests/tests/src/test/java/**/*.java" \ ./gradlew --no-daemon acceptanceTestCliqueBft
| sed 's@.*/src/test/java/@@' \
| sed 's@/@.@g' \
| sed 's/.\{5\}$//' \
| circleci tests split --split-by=timings --timings-type=classname)
# Format the arguments to "./gradlew test"
GRADLE_ARGS=$(echo $CLASSNAMES | awk '{for (i=1; i<=NF; i++) print "--tests",$i}')
./gradlew --no-daemon acceptanceTestCliqueBft $GRADLE_ARGS
- capture_test_results - capture_test_results
- capture_test_logs - capture_test_logs
acceptanceTestsPrivacy: acceptanceTestsPrivacy:
parallelism: 6 parallelism: 4
executor: xl_machine_executor executor: xl_machine_executor # needs the machine executor since it uses container tests (docker)
steps: steps:
- prepare - prepare
- attach_workspace: - attach_workspace:
@ -285,8 +269,7 @@ jobs:
- capture_test_logs - capture_test_logs
acceptanceTestsPermissioning: acceptanceTestsPermissioning:
parallelism: 6 executor: besu_executor_xl
executor: xl_machine_executor
steps: steps:
- prepare - prepare
- attach_workspace: - attach_workspace:
@ -295,14 +278,7 @@ jobs:
name: AcceptanceTests (Non-Mainnet) name: AcceptanceTests (Non-Mainnet)
no_output_timeout: 20m no_output_timeout: 20m
command: | command: |
CLASSNAMES=$(circleci tests glob "acceptance-tests/tests/src/test/java/**/*.java" \ ./gradlew --no-daemon acceptanceTestPermissioning
| sed 's@.*/src/test/java/@@' \
| sed 's@/@.@g' \
| sed 's/.\{5\}$//' \
| circleci tests split --split-by=timings --timings-type=classname)
# Format the arguments to "./gradlew test"
GRADLE_ARGS=$(echo $CLASSNAMES | awk '{for (i=1; i<=NF; i++) print "--tests",$i}')
./gradlew --no-daemon acceptanceTestPermissioning $GRADLE_ARGS
- capture_test_results - capture_test_results
- capture_test_logs - capture_test_logs
@ -448,9 +424,6 @@ workflows:
- acceptanceTestsCliqueBft: - acceptanceTestsCliqueBft:
requires: requires:
- assemble - assemble
- acceptanceTestsPrivacy:
requires:
- assemble
- acceptanceTestsPermissioning: - acceptanceTestsPermissioning:
requires: requires:
- assemble - assemble
@ -525,3 +498,6 @@ workflows:
jobs: jobs:
- assemble - assemble
- dockerScan - dockerScan
- acceptanceTestsPrivacy:
requires:
- assemble

@ -1,8 +1,20 @@
# Changelog # Changelog
## 23.10.3
### Breaking Changes
### Deprecations
### Additions and Improvements
- Implement debug_traceCall [#5885](https://github.com/hyperledger/besu/pull/5885)
- Transactions that takes too long to evaluate, during block creation, are dropped from the txpool [#6163](https://github.com/hyperledger/besu/pull/6163)
- New option `tx-pool-min-gas-price` to set a lower bound when accepting txs to the pool [#6098](https://github.com/hyperledger/besu/pull/6098)
## 23.10.2 ## 23.10.2
### Breaking Changes ### Breaking Changes
- TX pool eviction in the legacy TX pool now favours keeping oldest transactions (more likely to evict higher nonces, less likely to introduce nonce gaps) [#6106](https://github.com/hyperledger/besu/pull/6106) and [#6146](https://github.com/hyperledger/besu/pull/6146)
### Deprecations ### Deprecations
@ -19,6 +31,7 @@
- Add `yParity` to GraphQL and JSON-RPC for relevant querise. [6119](https://github.com/hyperledger/besu/pull/6119) - Add `yParity` to GraphQL and JSON-RPC for relevant querise. [6119](https://github.com/hyperledger/besu/pull/6119)
- Force tx replacement price bump to zero when zero base fee market is configured or `--min-gas-price` is set to 0. This allows for easier tx replacement in networks where there is not gas price. [#6079](https://github.com/hyperledger/besu/pull/6079) - Force tx replacement price bump to zero when zero base fee market is configured or `--min-gas-price` is set to 0. This allows for easier tx replacement in networks where there is not gas price. [#6079](https://github.com/hyperledger/besu/pull/6079)
- Introduce the possibility to limit the time spent selecting pending transactions during block creation, using the new experimental option `Xblock-txs-selection-max-time` on PoS and PoW networks (by default set to 5000ms) or `Xpoa-block-txs-selection-max-time` on PoA networks (by default 75% of the min block time) [#6044](https://github.com/hyperledger/besu/pull/6044) - Introduce the possibility to limit the time spent selecting pending transactions during block creation, using the new experimental option `Xblock-txs-selection-max-time` on PoS and PoW networks (by default set to 5000ms) or `Xpoa-block-txs-selection-max-time` on PoA networks (by default 75% of the min block time) [#6044](https://github.com/hyperledger/besu/pull/6044)
- Remove LowestInvalidNonceCache from `legacy` transaction pool to make it more private networks friendly [#6148](https://github.com/hyperledger/besu/pull/6148)
### Bug fixes ### Bug fixes
- Upgrade netty to address CVE-2023-44487, CVE-2023-34462 [#6100](https://github.com/hyperledger/besu/pull/6100) - Upgrade netty to address CVE-2023-44487, CVE-2023-34462 [#6100](https://github.com/hyperledger/besu/pull/6100)
@ -29,6 +42,9 @@
--- ---
### Download Links ### Download Links
https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.10.2/besu-23.10.2.zip / sha256: 597ab71898d379180106baf24878239ed49acefea5772344fd359b0ff13fe19f
https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.10.2/besu-23.10.2.tar.gz / sha256: 255818a5c6067a38aa8b565d8f32a49a172a7536a1d370673bbb75f548263c2c
## 23.10.1 ## 23.10.1

@ -192,10 +192,11 @@ public class OpenTelemetryAcceptanceTest extends AcceptanceTestBase {
assertThat(internalSpan.getKind()).isEqualTo(Span.SpanKind.SPAN_KIND_INTERNAL); assertThat(internalSpan.getKind()).isEqualTo(Span.SpanKind.SPAN_KIND_INTERNAL);
final ByteString parent = internalSpan.getParentSpanId(); final ByteString parent = internalSpan.getParentSpanId();
assertThat(parent.isEmpty()).isFalse(); assertThat(parent.isEmpty()).isFalse();
final Span serverSpan = spans.get(0).getScopeSpans(0).getSpans(1); // this part of the test is flaky
assertThat(serverSpan.getKind()).isEqualTo(Span.SpanKind.SPAN_KIND_SERVER); // final Span serverSpan = spans.get(0).getScopeSpans(0).getSpans(1);
final ByteString rootSpanId = serverSpan.getParentSpanId(); // assertThat(serverSpan.getKind()).isEqualTo(Span.SpanKind.SPAN_KIND_SERVER);
assertThat(rootSpanId.isEmpty()).isTrue(); // final ByteString rootSpanId = serverSpan.getParentSpanId();
// assertThat(rootSpanId.isEmpty()).isTrue();
}); });
} }

@ -83,10 +83,10 @@ public class ExecutionEngineCancunBlockBuildingAcceptanceTest extends AbstractJs
assertThat(blobsBundle.get("blobs").getNodeType()).isEqualTo(JsonNodeType.ARRAY); assertThat(blobsBundle.get("blobs").getNodeType()).isEqualTo(JsonNodeType.ARRAY);
final ArrayNode blobs = (ArrayNode) blobsBundle.get("blobs"); final ArrayNode blobs = (ArrayNode) blobsBundle.get("blobs");
final ArrayNode proofs = (ArrayNode) blobsBundle.get("proofs"); final ArrayNode proofs = (ArrayNode) blobsBundle.get("proofs");
assertThat(2).isEqualTo(transactions.size()); assertThat(3).isEqualTo(transactions.size());
assertThat(6).isEqualTo(commitments.size()); assertThat(3).isEqualTo(commitments.size());
assertThat(6).isEqualTo(blobs.size()); assertThat(3).isEqualTo(blobs.size());
assertThat(6).isEqualTo(proofs.size()); assertThat(3).isEqualTo(proofs.size());
} }
} }

@ -1,95 +1,5 @@
{ {
"request": { "request" : {"jsonrpc":"2.0","id":5,"method":"engine_forkchoiceUpdatedV3","params":[{"headBlockHash":"0x33235e7b7a78302cdb54e5ddba66c7ae49b01c1f5498bb00cd0c8ed5206784bf","safeBlockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","finalizedBlockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"},{"timestamp":"0x1236","prevRandao":"0xc13da06dc53836ca0766057413b9683eb9a8773bbb8fcc5691e41c25b56dda1d","suggestedFeeRecipient":"0x0000000000000000000000000000000000000000","withdrawals":[{"index":"0xb","validatorIndex":"0x0","address":"0x0000000000000000000000000000000000000000","amount":"0x64"},{"index":"0xc","validatorIndex":"0x1","address":"0x0100000000000000000000000000000000000000","amount":"0x64"},{"index":"0xd","validatorIndex":"0x2","address":"0x0200000000000000000000000000000000000000","amount":"0x64"},{"index":"0xe","validatorIndex":"0x3","address":"0x0300000000000000000000000000000000000000","amount":"0x64"},{"index":"0xf","validatorIndex":"0x4","address":"0x0400000000000000000000000000000000000000","amount":"0x64"},{"index":"0x10","validatorIndex":"0x5","address":"0x0500000000000000000000000000000000000000","amount":"0x64"},{"index":"0x11","validatorIndex":"0x6","address":"0x0600000000000000000000000000000000000000","amount":"0x64"},{"index":"0x12","validatorIndex":"0x7","address":"0x0700000000000000000000000000000000000000","amount":"0x64"},{"index":"0x13","validatorIndex":"0x8","address":"0x0800000000000000000000000000000000000000","amount":"0x64"},{"index":"0x14","validatorIndex":"0x9","address":"0x0900000000000000000000000000000000000000","amount":"0x64"}],"parentBeaconBlockRoot":"0x062367f0b23e2d49ad5e770d9ad17b83c0c1c625c3f9a290cd9572b3fc6cfc9e"}]},
"jsonrpc": "2.0", "response" : {"jsonrpc":"2.0","id":5,"result":{"payloadStatus":{"status":"VALID","latestValidHash":"0x33235e7b7a78302cdb54e5ddba66c7ae49b01c1f5498bb00cd0c8ed5206784bf","validationError":null},"payloadId":"0x29e12df730769ab6"}},
"id": 1, "statusCode" : 200
"method": "engine_forkchoiceUpdatedV3",
"params": [
{
"headBlockHash": "0x33235e7b7a78302cdb54e5ddba66c7ae49b01c1f5498bb00cd0c8ed5206784bf",
"safeBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"timestamp": "0x1235",
"prevRandao": "0x31a3b9b03c64172b39b7fa7d35d86eaa0f9cbac30e2abbf9895a32b80ae1cd76",
"suggestedFeeRecipient": "0x0000000000000000000000000000000000000000",
"withdrawals": [
{
"index": "0x1",
"validatorIndex": "0x0",
"address": "0x0000000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0x2",
"validatorIndex": "0x1",
"address": "0x0100000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0x3",
"validatorIndex": "0x2",
"address": "0x0200000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0x4",
"validatorIndex": "0x3",
"address": "0x0300000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0x5",
"validatorIndex": "0x4",
"address": "0x0400000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0x6",
"validatorIndex": "0x5",
"address": "0x0500000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0x7",
"validatorIndex": "0x6",
"address": "0x0600000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0x8",
"validatorIndex": "0x7",
"address": "0x0700000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0x9",
"validatorIndex": "0x8",
"address": "0x0800000000000000000000000000000000000000",
"amount": "0x64"
},
{
"index": "0xa",
"validatorIndex": "0x9",
"address": "0x0900000000000000000000000000000000000000",
"amount": "0x64"
}
],
"parentBeaconBlockRoot": "0x169630f535b4a41330164c6e5c92b1224c0c407f582d407d0ac3d206cd32fd52"
}
]
},
"response": {
"jsonrpc": "2.0",
"id": 1,
"result": {
"payloadStatus": {
"status": "VALID",
"latestValidHash": "0x33235e7b7a78302cdb54e5ddba66c7ae49b01c1f5498bb00cd0c8ed5206784bf",
"validationError": null
},
"payloadId": "0x78d3b312ed5adeb5"
}
},
"statusCode": 200
} }

@ -156,7 +156,13 @@ public class RlpBlockImporter implements Closeable {
previousBlockFuture = previousBlockFuture =
validationFuture.runAfterBothAsync( validationFuture.runAfterBothAsync(
calculationFutures, calculationFutures,
() -> evaluateBlock(context, block, header, protocolSpec, skipPowValidation), () ->
evaluateBlock(
context,
block,
header,
protocolSchedule.getByBlockHeader(header),
skipPowValidation),
importExecutor); importExecutor);
previousBlockFuture.exceptionally( previousBlockFuture.exceptionally(
exception -> { exception -> {

@ -294,7 +294,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private final ChainPruningOptions unstableChainPruningOptions = ChainPruningOptions.create(); private final ChainPruningOptions unstableChainPruningOptions = ChainPruningOptions.create();
// stable CLI options // stable CLI options
private final DataStorageOptions dataStorageOptions = DataStorageOptions.create(); final DataStorageOptions dataStorageOptions = DataStorageOptions.create();
private final EthstatsOptions ethstatsOptions = EthstatsOptions.create(); private final EthstatsOptions ethstatsOptions = EthstatsOptions.create();
private final NodePrivateKeyFileOption nodePrivateKeyFileOption = private final NodePrivateKeyFileOption nodePrivateKeyFileOption =
NodePrivateKeyFileOption.create(); NodePrivateKeyFileOption.create();
@ -1785,6 +1785,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
validateChainDataPruningParams(); validateChainDataPruningParams();
validatePostMergeCheckpointBlockRequirements(); validatePostMergeCheckpointBlockRequirements();
validateTransactionPoolOptions(); validateTransactionPoolOptions();
validateDataStorageOptions();
p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine); p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine);
pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine); pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine);
} }
@ -1793,6 +1794,10 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
transactionPoolOptions.validate(commandLine, getActualGenesisConfigOptions()); transactionPoolOptions.validate(commandLine, getActualGenesisConfigOptions());
} }
private void validateDataStorageOptions() {
dataStorageOptions.validate(commandLine);
}
private void validateRequiredOptions() { private void validateRequiredOptions() {
commandLine commandLine
.getCommandSpec() .getCommandSpec()
@ -2825,6 +2830,23 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
txPoolConfBuilder.priceBump(Percentage.ZERO); txPoolConfBuilder.priceBump(Percentage.ZERO);
} }
if (getMiningParameters().getMinTransactionGasPrice().lessThan(txPoolConf.getMinGasPrice())) {
if (transactionPoolOptions.isMinGasPriceSet(commandLine)) {
throw new ParameterException(
commandLine, "tx-pool-min-gas-price cannot be greater than the value of min-gas-price");
} else {
// for backward compatibility, if tx-pool-min-gas-price is not set, we adjust its value
// to be the same as min-gas-price, so the behavior is as before this change, and we notify
// the user of the change
logger.warn(
"Forcing tx-pool-min-gas-price="
+ getMiningParameters().getMinTransactionGasPrice().toDecimalString()
+ ", since it cannot be greater than the value of min-gas-price");
txPoolConfBuilder.minGasPrice(getMiningParameters().getMinTransactionGasPrice());
}
}
return txPoolConfBuilder.build(); return txPoolConfBuilder.build();
} }
@ -3466,6 +3488,14 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
builder.setHighSpecEnabled(); builder.setHighSpecEnabled();
} }
if (dataStorageOptions.toDomainObject().getUnstable().getBonsaiTrieLogPruningEnabled()) {
builder.setTrieLogPruningEnabled();
builder.setTrieLogRetentionThreshold(
dataStorageOptions.toDomainObject().getUnstable().getBonsaiTrieLogRetentionThreshold());
builder.setTrieLogPruningLimit(
dataStorageOptions.toDomainObject().getUnstable().getBonsaiTrieLogPruningLimit());
}
builder.setTxPoolImplementation(buildTransactionPoolConfiguration().getTxPoolImplementation()); builder.setTxPoolImplementation(buildTransactionPoolConfiguration().getTxPoolImplementation());
builder.setWorldStateUpdateMode(unstableEvmOptions.toDomainObject().worldUpdaterMode()); builder.setWorldStateUpdateMode(unstableEvmOptions.toDomainObject().worldUpdaterMode());

@ -50,6 +50,9 @@ public class ConfigurationOverviewBuilder {
private Collection<String> engineApis; private Collection<String> engineApis;
private String engineJwtFilePath; private String engineJwtFilePath;
private boolean isHighSpec = false; private boolean isHighSpec = false;
private boolean isTrieLogPruningEnabled = false;
private long trieLogRetentionThreshold = 0;
private Integer trieLogPruningLimit = null;
private TransactionPoolConfiguration.Implementation txPoolImplementation; private TransactionPoolConfiguration.Implementation txPoolImplementation;
private EvmConfiguration.WorldUpdaterMode worldStateUpdateMode; private EvmConfiguration.WorldUpdaterMode worldStateUpdateMode;
private Map<String, String> environment; private Map<String, String> environment;
@ -171,6 +174,38 @@ public class ConfigurationOverviewBuilder {
return this; return this;
} }
/**
* Sets trie log pruning enabled
*
* @return the builder
*/
public ConfigurationOverviewBuilder setTrieLogPruningEnabled() {
isTrieLogPruningEnabled = true;
return this;
}
/**
* Sets trie log retention threshold
*
* @param threshold the number of blocks to retain trie logs for
* @return the builder
*/
public ConfigurationOverviewBuilder setTrieLogRetentionThreshold(final long threshold) {
trieLogRetentionThreshold = threshold;
return this;
}
/**
* Sets trie log pruning limit
*
* @param limit the max number of blocks to load and prune trie logs for at startup
* @return the builder
*/
public ConfigurationOverviewBuilder setTrieLogPruningLimit(final int limit) {
trieLogPruningLimit = limit;
return this;
}
/** /**
* Sets the txpool implementation in use. * Sets the txpool implementation in use.
* *
@ -266,13 +301,25 @@ public class ConfigurationOverviewBuilder {
lines.add("Engine JWT: " + engineJwtFilePath); lines.add("Engine JWT: " + engineJwtFilePath);
} }
lines.add("Using " + txPoolImplementation + " transaction pool implementation");
if (isHighSpec) { if (isHighSpec) {
lines.add("Experimental high spec configuration enabled"); lines.add("Experimental high spec configuration enabled");
} }
lines.add("Using " + txPoolImplementation + " transaction pool implementation");
lines.add("Using " + worldStateUpdateMode + " worldstate update mode"); lines.add("Using " + worldStateUpdateMode + " worldstate update mode");
if (isTrieLogPruningEnabled) {
final StringBuilder trieLogPruningString = new StringBuilder();
trieLogPruningString
.append("Trie log pruning enabled: retention: ")
.append(trieLogRetentionThreshold);
if (trieLogPruningLimit != null) {
trieLogPruningString.append("; prune limit: ").append(trieLogPruningLimit);
}
lines.add(trieLogPruningString.toString());
}
lines.add(""); lines.add("");
lines.add("Host:"); lines.add("Host:");

@ -54,6 +54,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
private static final String STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG = private static final String STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG =
"--strict-tx-replay-protection-enabled"; "--strict-tx-replay-protection-enabled";
private static final String TX_POOL_PRIORITY_SENDERS = "--tx-pool-priority-senders"; private static final String TX_POOL_PRIORITY_SENDERS = "--tx-pool-priority-senders";
private static final String TX_POOL_MIN_GAS_PRICE = "--tx-pool-min-gas-price";
@CommandLine.Option( @CommandLine.Option(
names = {TX_POOL_IMPLEMENTATION}, names = {TX_POOL_IMPLEMENTATION},
@ -122,6 +123,15 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
arity = "1..*") arity = "1..*")
private Set<Address> prioritySenders = TransactionPoolConfiguration.DEFAULT_PRIORITY_SENDERS; private Set<Address> prioritySenders = TransactionPoolConfiguration.DEFAULT_PRIORITY_SENDERS;
@CommandLine.Option(
names = {TX_POOL_MIN_GAS_PRICE},
paramLabel = "<Wei>",
description =
"Transactions with gas price (in Wei) lower than this minimum will not be accepted into the txpool"
+ "(not to be confused with min-gas-price, that is applied on block creation) (default: ${DEFAULT-VALUE})",
arity = "1")
private Wei minGasPrice = TransactionPoolConfiguration.DEFAULT_TX_POOL_MIN_GAS_PRICE;
@CommandLine.ArgGroup( @CommandLine.ArgGroup(
validate = false, validate = false,
heading = "@|bold Tx Pool Layered Implementation Options|@%n") heading = "@|bold Tx Pool Layered Implementation Options|@%n")
@ -257,6 +267,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
options.saveFile = config.getSaveFile(); options.saveFile = config.getSaveFile();
options.strictTxReplayProtectionEnabled = config.getStrictTransactionReplayProtectionEnabled(); options.strictTxReplayProtectionEnabled = config.getStrictTransactionReplayProtectionEnabled();
options.prioritySenders = config.getPrioritySenders(); options.prioritySenders = config.getPrioritySenders();
options.minGasPrice = config.getMinGasPrice();
options.layeredOptions.txPoolLayerMaxCapacity = options.layeredOptions.txPoolLayerMaxCapacity =
config.getPendingTransactionsLayerMaxCapacityBytes(); config.getPendingTransactionsLayerMaxCapacityBytes();
options.layeredOptions.txPoolMaxPrioritized = config.getMaxPrioritizedTransactions(); options.layeredOptions.txPoolMaxPrioritized = config.getMaxPrioritizedTransactions();
@ -312,6 +323,7 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
.saveFile(saveFile) .saveFile(saveFile)
.strictTransactionReplayProtectionEnabled(strictTxReplayProtectionEnabled) .strictTransactionReplayProtectionEnabled(strictTxReplayProtectionEnabled)
.prioritySenders(prioritySenders) .prioritySenders(prioritySenders)
.minGasPrice(minGasPrice)
.pendingTransactionsLayerMaxCapacityBytes(layeredOptions.txPoolLayerMaxCapacity) .pendingTransactionsLayerMaxCapacityBytes(layeredOptions.txPoolLayerMaxCapacity)
.maxPrioritizedTransactions(layeredOptions.txPoolMaxPrioritized) .maxPrioritizedTransactions(layeredOptions.txPoolMaxPrioritized)
.maxFutureBySender(layeredOptions.txPoolMaxFutureBySender) .maxFutureBySender(layeredOptions.txPoolMaxFutureBySender)
@ -340,4 +352,14 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
public boolean isPriceBumpSet(final CommandLine commandLine) { public boolean isPriceBumpSet(final CommandLine commandLine) {
return CommandLineUtils.isOptionSet(commandLine, TransactionPoolOptions.TX_POOL_PRICE_BUMP); return CommandLineUtils.isOptionSet(commandLine, TransactionPoolOptions.TX_POOL_PRICE_BUMP);
} }
/**
* Is min gas price option set?
*
* @param commandLine the command line
* @return true if tx-pool-min-gas-price is set
*/
public boolean isMinGasPriceSet(final CommandLine commandLine) {
return CommandLineUtils.isOptionSet(commandLine, TransactionPoolOptions.TX_POOL_MIN_GAS_PRICE);
}
} }

@ -17,8 +17,13 @@
package org.hyperledger.besu.cli.options.stable; package org.hyperledger.besu.cli.options.stable;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD; import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.DEFAULT_BONSAI_TRIE_LOG_PRUNING_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.DEFAULT_BONSAI_TRIE_LOG_PRUNING_LIMIT;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.DEFAULT_BONSAI_TRIE_LOG_RETENTION_THRESHOLD;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.MINIMUM_BONSAI_TRIE_LOG_RETENTION_THRESHOLD;
import org.hyperledger.besu.cli.options.CLIOptions; import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
@ -26,6 +31,7 @@ import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguratio
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import picocli.CommandLine;
import picocli.CommandLine.Option; import picocli.CommandLine.Option;
/** The Data storage CLI options. */ /** The Data storage CLI options. */
@ -42,7 +48,7 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
description = description =
"Format to store trie data in. Either FOREST or BONSAI (default: ${DEFAULT-VALUE}).", "Format to store trie data in. Either FOREST or BONSAI (default: ${DEFAULT-VALUE}).",
arity = "1") arity = "1")
private final DataStorageFormat dataStorageFormat = DataStorageFormat.FOREST; private DataStorageFormat dataStorageFormat = DataStorageFormat.FOREST;
@Option( @Option(
names = {BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD, "--bonsai-maximum-back-layers-to-load"}, names = {BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD, "--bonsai-maximum-back-layers-to-load"},
@ -50,8 +56,33 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
description = description =
"Limit of historical layers that can be loaded with BONSAI (default: ${DEFAULT-VALUE}).", "Limit of historical layers that can be loaded with BONSAI (default: ${DEFAULT-VALUE}).",
arity = "1") arity = "1")
private final Long bonsaiMaxLayersToLoad = DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD; private Long bonsaiMaxLayersToLoad = DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD;
@CommandLine.ArgGroup(validate = false)
private final DataStorageOptions.Unstable unstableOptions = new Unstable();
static class Unstable {
@CommandLine.Option(
hidden = true,
names = {"--Xbonsai-trie-log-pruning-enabled"},
description = "Enable trie log pruning. (default: ${DEFAULT-VALUE})")
private boolean bonsaiTrieLogPruningEnabled = DEFAULT_BONSAI_TRIE_LOG_PRUNING_ENABLED;
@CommandLine.Option(
hidden = true,
names = {"--Xbonsai-trie-log-retention-threshold"},
description =
"The number of blocks for which to retain trie logs. (default: ${DEFAULT-VALUE})")
private long bonsaiTrieLogRetentionThreshold = DEFAULT_BONSAI_TRIE_LOG_RETENTION_THRESHOLD;
@CommandLine.Option(
hidden = true,
names = {"--Xbonsai-trie-log-pruning-limit"},
description =
"The max number of blocks to load and prune trie logs for at startup. (default: ${DEFAULT-VALUE})")
private int bonsaiTrieLogPruningLimit = DEFAULT_BONSAI_TRIE_LOG_PRUNING_LIMIT;
}
/** /**
* Create data storage options. * Create data storage options.
* *
@ -61,21 +92,62 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
return new DataStorageOptions(); return new DataStorageOptions();
} }
/**
* Validates the data storage options
*
* @param commandLine the full commandLine to check all the options specified by the user
*/
public void validate(final CommandLine commandLine) {
if (unstableOptions.bonsaiTrieLogPruningEnabled) {
if (unstableOptions.bonsaiTrieLogRetentionThreshold
< MINIMUM_BONSAI_TRIE_LOG_RETENTION_THRESHOLD) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
"--Xbonsai-trie-log-retention-threshold minimum value is %d",
MINIMUM_BONSAI_TRIE_LOG_RETENTION_THRESHOLD));
}
if (unstableOptions.bonsaiTrieLogPruningLimit <= 0) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
"--Xbonsai-trie-log-pruning-limit=%d must be greater than 0",
unstableOptions.bonsaiTrieLogPruningLimit));
}
}
}
static DataStorageOptions fromConfig(final DataStorageConfiguration domainObject) {
final DataStorageOptions dataStorageOptions = DataStorageOptions.create();
dataStorageOptions.dataStorageFormat = domainObject.getDataStorageFormat();
dataStorageOptions.bonsaiMaxLayersToLoad = domainObject.getBonsaiMaxLayersToLoad();
dataStorageOptions.unstableOptions.bonsaiTrieLogPruningEnabled =
domainObject.getUnstable().getBonsaiTrieLogPruningEnabled();
dataStorageOptions.unstableOptions.bonsaiTrieLogRetentionThreshold =
domainObject.getUnstable().getBonsaiTrieLogRetentionThreshold();
dataStorageOptions.unstableOptions.bonsaiTrieLogPruningLimit =
domainObject.getUnstable().getBonsaiTrieLogPruningLimit();
return dataStorageOptions;
}
@Override @Override
public DataStorageConfiguration toDomainObject() { public DataStorageConfiguration toDomainObject() {
return ImmutableDataStorageConfiguration.builder() return ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(dataStorageFormat) .dataStorageFormat(dataStorageFormat)
.bonsaiMaxLayersToLoad(bonsaiMaxLayersToLoad) .bonsaiMaxLayersToLoad(bonsaiMaxLayersToLoad)
.unstable(
ImmutableDataStorageConfiguration.Unstable.builder()
.bonsaiTrieLogPruningEnabled(unstableOptions.bonsaiTrieLogPruningEnabled)
.bonsaiTrieLogRetentionThreshold(unstableOptions.bonsaiTrieLogRetentionThreshold)
.bonsaiTrieLogPruningLimit(unstableOptions.bonsaiTrieLogPruningLimit)
.build())
.build(); .build();
} }
@Override @Override
public List<String> getCLIOptions() { public List<String> getCLIOptions() {
return List.of( return CommandLineUtils.getCLIOptions(this, new DataStorageOptions());
DATA_STORAGE_FORMAT,
dataStorageFormat.toString(),
BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD,
bonsaiMaxLayersToLoad.toString());
} }
/** /**

@ -19,6 +19,8 @@ package org.hyperledger.besu.components;
import org.hyperledger.besu.cli.BesuCommand; import org.hyperledger.besu.cli.BesuCommand;
import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoaderModule; import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoaderModule;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule;
import org.hyperledger.besu.metrics.MetricsSystemModule; import org.hyperledger.besu.metrics.MetricsSystemModule;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.BesuPluginContextImpl;
@ -36,7 +38,8 @@ import org.slf4j.Logger;
BesuCommandModule.class, BesuCommandModule.class,
MetricsSystemModule.class, MetricsSystemModule.class,
CachedMerkleTrieLoaderModule.class, CachedMerkleTrieLoaderModule.class,
BesuPluginContextModule.class BesuPluginContextModule.class,
BlobCacheModule.class
}) })
public interface BesuComponent { public interface BesuComponent {
@ -72,8 +75,15 @@ public interface BesuComponent {
/** /**
* Besu plugin context for doing plugin service discovery. * Besu plugin context for doing plugin service discovery.
* *
* @return BesuComponent * @return BesuPluginContextImpl
*/ */
@Named("besuPluginContext") @Named("besuPluginContext")
BesuPluginContextImpl getBesuPluginContext(); BesuPluginContextImpl getBesuPluginContext();
/**
* Cache to store blobs in for re-use after reorgs.
*
* @return BlobCache
*/
BlobCache getBlobCache();
} }

@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateProvider; import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateProvider;
import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogPruner;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.BlockchainStorage; import org.hyperledger.besu.ethereum.chain.BlockchainStorage;
import org.hyperledger.besu.ethereum.chain.ChainDataPruner; import org.hyperledger.besu.ethereum.chain.ChainDataPruner;
@ -73,6 +74,7 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.Checkpoint;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.ImmutableCheckpoint; import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.ImmutableCheckpoint;
import org.hyperledger.besu.ethereum.eth.sync.fullsync.SyncTerminationCondition; import org.hyperledger.besu.ethereum.eth.sync.fullsync.SyncTerminationCondition;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; 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;
@ -720,9 +722,9 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
clock, clock,
metricsSystem, metricsSystem,
syncState, syncState,
miningParameters,
transactionPoolConfiguration, transactionPoolConfiguration,
pluginTransactionValidatorFactory); pluginTransactionValidatorFactory,
besuComponent.map(BesuComponent::getBlobCache).orElse(new BlobCache()));
final List<PeerValidator> peerValidators = createPeerValidators(protocolSchedule); final List<PeerValidator> peerValidators = createPeerValidators(protocolSchedule);
@ -1064,14 +1066,30 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
final Blockchain blockchain, final Blockchain blockchain,
final CachedMerkleTrieLoader cachedMerkleTrieLoader) { final CachedMerkleTrieLoader cachedMerkleTrieLoader) {
return switch (dataStorageConfiguration.getDataStorageFormat()) { return switch (dataStorageConfiguration.getDataStorageFormat()) {
case BONSAI -> new BonsaiWorldStateProvider( case BONSAI -> {
(BonsaiWorldStateKeyValueStorage) worldStateStorage, final GenesisConfigOptions genesisConfigOptions = configOptionsSupplier.get();
blockchain, final boolean isProofOfStake =
Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()), genesisConfigOptions.getTerminalTotalDifficulty().isPresent();
cachedMerkleTrieLoader, final TrieLogPruner trieLogPruner =
metricsSystem, dataStorageConfiguration.getUnstable().getBonsaiTrieLogPruningEnabled()
besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null), ? new TrieLogPruner(
evmConfiguration); (BonsaiWorldStateKeyValueStorage) worldStateStorage,
blockchain,
dataStorageConfiguration.getUnstable().getBonsaiTrieLogRetentionThreshold(),
dataStorageConfiguration.getUnstable().getBonsaiTrieLogPruningLimit(),
isProofOfStake)
: TrieLogPruner.noOpTrieLogPruner();
trieLogPruner.initialize();
yield new BonsaiWorldStateProvider(
(BonsaiWorldStateKeyValueStorage) worldStateStorage,
blockchain,
Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()),
cachedMerkleTrieLoader,
metricsSystem,
besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null),
evmConfiguration,
trieLogPruner);
}
case FOREST -> { case FOREST -> {
final WorldStatePreimageStorage preimageStorage = final WorldStatePreimageStorage preimageStorage =
storageProvider.createWorldStatePreimageStorage(); storageProvider.createWorldStatePreimageStorage();

@ -5248,6 +5248,31 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
} }
@Test
public void txpoolWhenNotSetForceTxPoolMinGasPriceToZeroWhenMinGasPriceZero() {
parseCommand("--min-gas-price", "0");
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
final Wei txPoolMinGasPrice = transactionPoolConfigCaptor.getValue().getMinGasPrice();
assertThat(txPoolMinGasPrice).isEqualTo(Wei.ZERO);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
verify(mockLogger, atLeast(1))
.warn(
contains(
"Forcing tx-pool-min-gas-price=0, since it cannot be greater than the value of min-gas-price"));
}
@Test
public void txpoolTxPoolMinGasPriceMustNotBeGreaterThanMinGasPriceZero() {
parseCommand("--min-gas-price", "100", "--tx-pool-min-gas-price", "101");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains("tx-pool-min-gas-price cannot be greater than the value of min-gas-price");
}
@Test @Test
public void snapsyncHealingOptionShouldBeDisabledByDefault() { public void snapsyncHealingOptionShouldBeDisabledByDefault() {
final TestBesuCommand besuCommand = parseCommand(); final TestBesuCommand besuCommand = parseCommand();

@ -33,6 +33,7 @@ import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.config.EthNetworkConfig; import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.options.MiningOptions; import org.hyperledger.besu.cli.options.MiningOptions;
import org.hyperledger.besu.cli.options.TransactionPoolOptions; import org.hyperledger.besu.cli.options.TransactionPoolOptions;
import org.hyperledger.besu.cli.options.stable.DataStorageOptions;
import org.hyperledger.besu.cli.options.stable.EthstatsOptions; import org.hyperledger.besu.cli.options.stable.EthstatsOptions;
import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions;
import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions;
@ -568,6 +569,10 @@ public abstract class CommandTestAbstract {
return transactionPoolOptions; return transactionPoolOptions;
} }
public DataStorageOptions getDataStorageOptions() {
return dataStorageOptions;
}
public MetricsCLIOptions getMetricsCLIOptions() { public MetricsCLIOptions getMetricsCLIOptions() {
return unstableMetricsCLIOptions; return unstableMetricsCLIOptions;
} }

@ -148,6 +148,24 @@ class ConfigurationOverviewBuilderTest {
assertThat(highSpecEnabled).contains("Experimental high spec configuration enabled"); assertThat(highSpecEnabled).contains("Experimental high spec configuration enabled");
} }
@Test
void setTrieLogPruningEnabled() {
final String noTrieLogRetentionThresholdSet = builder.build();
assertThat(noTrieLogRetentionThresholdSet).doesNotContain("Trie log pruning enabled");
builder.setTrieLogPruningEnabled();
builder.setTrieLogRetentionThreshold(42);
String trieLogRetentionThresholdSet = builder.build();
assertThat(trieLogRetentionThresholdSet)
.contains("Trie log pruning enabled")
.contains("retention: 42");
assertThat(trieLogRetentionThresholdSet).doesNotContain("prune limit");
builder.setTrieLogPruningLimit(1000);
trieLogRetentionThresholdSet = builder.build();
assertThat(trieLogRetentionThresholdSet).contains("prune limit: 1000");
}
@Test @Test
void setTxPoolImplementationLayered() { void setTxPoolImplementationLayered() {
builder.setTxPoolImplementation(LAYERED); builder.setTxPoolImplementation(LAYERED);

@ -0,0 +1,111 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.cli.options.stable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.MINIMUM_BONSAI_TRIE_LOG_RETENTION_THRESHOLD;
import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.junit.Test;
public class DataStorageOptionsTest
extends AbstractCLIOptionsTest<DataStorageConfiguration, DataStorageOptions> {
@Test
public void bonsaiTrieLogPruningLimitOption() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(dataStorageConfiguration.getUnstable().getBonsaiTrieLogPruningLimit())
.isEqualTo(1),
"--Xbonsai-trie-log-pruning-enabled",
"--Xbonsai-trie-log-pruning-limit",
"1");
}
@Test
public void bonsaiTrieLogPruningLimitShouldBePositive() {
internalTestFailure(
"--Xbonsai-trie-log-pruning-limit=0 must be greater than 0",
"--Xbonsai-trie-log-pruning-enabled",
"--Xbonsai-trie-log-pruning-limit",
"0");
}
@Test
public void bonsaiTrieLogRetentionThresholdOption() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(dataStorageConfiguration.getUnstable().getBonsaiTrieLogRetentionThreshold())
.isEqualTo(MINIMUM_BONSAI_TRIE_LOG_RETENTION_THRESHOLD + 1),
"--Xbonsai-trie-log-pruning-enabled",
"--Xbonsai-trie-log-retention-threshold",
"513");
}
@Test
public void bonsaiTrieLogRetentionThresholdOption_boundaryTest() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(dataStorageConfiguration.getUnstable().getBonsaiTrieLogRetentionThreshold())
.isEqualTo(MINIMUM_BONSAI_TRIE_LOG_RETENTION_THRESHOLD),
"--Xbonsai-trie-log-pruning-enabled",
"--Xbonsai-trie-log-retention-threshold",
"512");
}
@Test
public void bonsaiTrieLogRetentionThresholdShouldBeAboveMinimum() {
internalTestFailure(
"--Xbonsai-trie-log-retention-threshold minimum value is 512",
"--Xbonsai-trie-log-pruning-enabled",
"--Xbonsai-trie-log-retention-threshold",
"511");
}
@Override
protected DataStorageConfiguration createDefaultDomainObject() {
return DataStorageConfiguration.DEFAULT_CONFIG;
}
@Override
protected DataStorageConfiguration createCustomizedDomainObject() {
return ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(DataStorageFormat.BONSAI)
.bonsaiMaxLayersToLoad(100L)
.unstable(
ImmutableDataStorageConfiguration.Unstable.builder()
.bonsaiTrieLogPruningEnabled(true)
.bonsaiTrieLogRetentionThreshold(1000L)
.bonsaiTrieLogPruningLimit(20)
.build())
.build();
}
@Override
protected DataStorageOptions optionsFromDomainObject(
final DataStorageConfiguration domainObject) {
return DataStorageOptions.fromConfig(domainObject);
}
@Override
protected DataStorageOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getDataStorageOptions();
}
}

@ -33,8 +33,6 @@ import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
@ -45,6 +43,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.sync.BlockBroadcaster; import org.hyperledger.besu.ethereum.eth.sync.BlockBroadcaster;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
@ -146,7 +145,10 @@ public class BesuEventsImplTest {
blockBroadcaster = new BlockBroadcaster(mockEthContext); blockBroadcaster = new BlockBroadcaster(mockEthContext);
syncState = new SyncState(blockchain, mockEthPeers); syncState = new SyncState(blockchain, mockEthPeers);
TransactionPoolConfiguration txPoolConfig = TransactionPoolConfiguration txPoolConfig =
ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(); ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(1)
.minGasPrice(Wei.ZERO)
.build();
transactionPool = transactionPool =
TransactionPoolFactory.createTransactionPool( TransactionPoolFactory.createTransactionPool(
@ -156,12 +158,9 @@ public class BesuEventsImplTest {
TestClock.system(ZoneId.systemDefault()), TestClock.system(ZoneId.systemDefault()),
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
syncState, syncState,
ImmutableMiningParameters.builder()
.mutableInitValues(
MutableInitValues.builder().minTransactionGasPrice(Wei.ZERO).build())
.build(),
txPoolConfig, txPoolConfig,
null); null,
new BlobCache());
serviceImpl = new BesuEventsImpl(blockchain, blockBroadcaster, transactionPool, syncState); serviceImpl = new BesuEventsImpl(blockchain, blockBroadcaster, transactionPool, syncState);
} }

@ -188,6 +188,7 @@ tx-pool-max-future-by-sender=321
tx-pool-retention-hours=999 tx-pool-retention-hours=999
tx-pool-max-size=1234 tx-pool-max-size=1234
tx-pool-limit-by-account-percentage=0.017 tx-pool-limit-by-account-percentage=0.017
tx-pool-min-gas-price=1000
# Revert Reason # Revert Reason
revert-reason-enabled=false revert-reason-enabled=false

@ -1,5 +1,5 @@
/* /*
* Copyright ConsenSys AG. * Copyright Hyperledger Besu contributors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * 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 * the License. You may obtain a copy of the License at

File diff suppressed because it is too large Load Diff

@ -238,7 +238,6 @@ public class CliqueBlockCreatorTest {
protocolContext, protocolContext,
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
conf, conf,
null); null);

@ -222,7 +222,6 @@ public class CliqueMinerExecutorTest {
cliqueProtocolContext, cliqueProtocolContext,
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
cliqueEthContext, cliqueEthContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
conf, conf,
null); null);

@ -362,7 +362,6 @@ public class TestContextBuilder {
protocolContext, protocolContext,
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
miningParams,
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
poolConf, poolConf,
null); null);

@ -146,7 +146,6 @@ public class BftBlockCreatorTest {
protContext, protContext,
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
poolConf, poolConf,
null); null);

@ -491,7 +491,7 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
if (maybeHeadHeader.isPresent()) { if (maybeHeadHeader.isPresent()) {
LOG.atDebug() LOG.atDebug()
.setMessage("BlockHeader {} is already present") .setMessage("BlockHeader {} is already present in blockchain")
.addArgument(maybeHeadHeader.get()::toLogString) .addArgument(maybeHeadHeader.get()::toLogString)
.log(); .log();
} else { } else {

@ -227,7 +227,6 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper {
protocolContext, protocolContext,
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
miningParameters,
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
poolConf, poolConf,
null); null);

@ -450,7 +450,6 @@ public class TestContextBuilder {
protocolContext, protocolContext,
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
miningParams,
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
poolConf, poolConf,
null); null);

@ -17,6 +17,8 @@ package org.hyperledger.besu.datatypes;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.util.Objects;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
/** Arbitrary data for use in the KZG scheme. */ /** Arbitrary data for use in the KZG scheme. */
@ -61,4 +63,17 @@ public class Blob {
public Bytes getData() { public Bytes getData() {
return data; return data;
} }
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Blob blob = (Blob) o;
return Objects.equals(getData(), blob.getData());
}
@Override
public int hashCode() {
return Objects.hash(getData());
}
} }

@ -15,15 +15,18 @@
package org.hyperledger.besu.datatypes; package org.hyperledger.besu.datatypes;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** A class to hold the blobs, commitments, proofs and versioned hashes for a set of blobs. */ /** A class to hold the blobs, commitments, proofs and versioned hashes for a set of blobs. */
public class BlobsWithCommitments { public class BlobsWithCommitments {
private final List<KZGCommitment> kzgCommitments;
private final List<Blob> blobs;
private final List<KZGProof> kzgProofs;
private final List<VersionedHash> versionedHashes; /** A record to hold the blob, commitment, proof and versioned hash for a blob. */
public record BlobQuad(
Blob blob, KZGCommitment kzgCommitment, KZGProof kzgProof, VersionedHash versionedHash) {}
private final List<BlobQuad> blobQuads;
/** /**
* A class to hold the blobs, commitments and proofs for a set of blobs. * A class to hold the blobs, commitments and proofs for a set of blobs.
@ -38,7 +41,7 @@ public class BlobsWithCommitments {
final List<Blob> blobs, final List<Blob> blobs,
final List<KZGProof> kzgProofs, final List<KZGProof> kzgProofs,
final List<VersionedHash> versionedHashes) { final List<VersionedHash> versionedHashes) {
if (blobs.size() == 0) { if (blobs.isEmpty()) {
throw new InvalidParameterException( throw new InvalidParameterException(
"There needs to be a minimum of one blob in a blob transaction with commitments"); "There needs to be a minimum of one blob in a blob transaction with commitments");
} }
@ -48,10 +51,22 @@ public class BlobsWithCommitments {
throw new InvalidParameterException( throw new InvalidParameterException(
"There must be an equal number of blobs, commitments, proofs, and versioned hashes"); "There must be an equal number of blobs, commitments, proofs, and versioned hashes");
} }
this.kzgCommitments = kzgCommitments; List<BlobQuad> toBuild = new ArrayList<>(blobs.size());
this.blobs = blobs; for (int i = 0; i < blobs.size(); i++) {
this.kzgProofs = kzgProofs; toBuild.add(
this.versionedHashes = versionedHashes; new BlobQuad(
blobs.get(i), kzgCommitments.get(i), kzgProofs.get(i), versionedHashes.get(i)));
}
this.blobQuads = toBuild;
}
/**
* Construct the class from a list of BlobQuads.
*
* @param quads the list of blob quads to be attached to the transaction
*/
public BlobsWithCommitments(final List<BlobQuad> quads) {
this.blobQuads = quads;
} }
/** /**
@ -60,7 +75,7 @@ public class BlobsWithCommitments {
* @return the blobs * @return the blobs
*/ */
public List<Blob> getBlobs() { public List<Blob> getBlobs() {
return blobs; return blobQuads.stream().map(BlobQuad::blob).toList();
} }
/** /**
@ -69,7 +84,7 @@ public class BlobsWithCommitments {
* @return the commitments * @return the commitments
*/ */
public List<KZGCommitment> getKzgCommitments() { public List<KZGCommitment> getKzgCommitments() {
return kzgCommitments; return blobQuads.stream().map(BlobQuad::kzgCommitment).toList();
} }
/** /**
@ -78,7 +93,7 @@ public class BlobsWithCommitments {
* @return the proofs * @return the proofs
*/ */
public List<KZGProof> getKzgProofs() { public List<KZGProof> getKzgProofs() {
return kzgProofs; return blobQuads.stream().map(BlobQuad::kzgProof).toList();
} }
/** /**
@ -87,6 +102,28 @@ public class BlobsWithCommitments {
* @return the hashes * @return the hashes
*/ */
public List<VersionedHash> getVersionedHashes() { public List<VersionedHash> getVersionedHashes() {
return versionedHashes; return blobQuads.stream().map(BlobQuad::versionedHash).toList();
}
/**
* Get the list of BlobQuads.
*
* @return blob quads
*/
public List<BlobQuad> getBlobQuads() {
return blobQuads;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BlobsWithCommitments that = (BlobsWithCommitments) o;
return Objects.equals(getBlobQuads(), that.getBlobQuads());
}
@Override
public int hashCode() {
return Objects.hash(getBlobQuads());
} }
} }

@ -17,6 +17,8 @@ package org.hyperledger.besu.datatypes;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.util.Objects;
import org.apache.tuweni.bytes.Bytes48; import org.apache.tuweni.bytes.Bytes48;
/** This class contains the data for a KZG commitment. */ /** This class contains the data for a KZG commitment. */
@ -60,4 +62,17 @@ public class KZGCommitment {
public Bytes48 getData() { public Bytes48 getData() {
return data; return data;
} }
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KZGCommitment that = (KZGCommitment) o;
return Objects.equals(getData(), that.getData());
}
@Override
public int hashCode() {
return Objects.hash(getData());
}
} }

@ -17,6 +17,8 @@ package org.hyperledger.besu.datatypes;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.util.Objects;
import org.apache.tuweni.bytes.Bytes48; import org.apache.tuweni.bytes.Bytes48;
/** This class contains the data for a KZG proof for a KZG commitment. */ /** This class contains the data for a KZG proof for a KZG commitment. */
@ -60,4 +62,17 @@ public class KZGProof {
public Bytes48 getData() { public Bytes48 getData() {
return data; return data;
} }
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KZGProof kzgProof = (KZGProof) o;
return Objects.equals(getData(), kzgProof.getData());
}
@Override
public int hashCode() {
return Objects.hash(getData());
}
} }

@ -44,7 +44,6 @@ 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.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
@ -119,7 +118,6 @@ public class EthGetFilterChangesIntegrationTest {
protocolContext, protocolContext,
batchAddedListener, batchAddedListener,
ethContext, ethContext,
MiningParameters.newDefault(),
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
TransactionPoolConfiguration.DEFAULT, TransactionPoolConfiguration.DEFAULT,
null); null);

@ -44,7 +44,6 @@ 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.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
@ -119,7 +118,6 @@ public class EthGetFilterChangesIntegrationTest {
protocolContext, protocolContext,
batchAddedListener, batchAddedListener,
ethContext, ethContext,
MiningParameters.newDefault(),
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
TransactionPoolConfiguration.DEFAULT, TransactionPoolConfiguration.DEFAULT,
null); null);

@ -71,14 +71,14 @@ public class JsonRpcErrorConverter {
return RpcErrorType.ETH_SEND_TX_REPLACEMENT_UNDERPRICED; return RpcErrorType.ETH_SEND_TX_REPLACEMENT_UNDERPRICED;
case NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER: case NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER:
return RpcErrorType.NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER; return RpcErrorType.NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER;
case LOWER_NONCE_INVALID_TRANSACTION_EXISTS:
return RpcErrorType.LOWER_NONCE_INVALID_TRANSACTION_EXISTS;
case TOTAL_BLOB_GAS_TOO_HIGH: case TOTAL_BLOB_GAS_TOO_HIGH:
return RpcErrorType.TOTAL_BLOB_GAS_TOO_HIGH; return RpcErrorType.TOTAL_BLOB_GAS_TOO_HIGH;
case TX_POOL_DISABLED: case TX_POOL_DISABLED:
return RpcErrorType.TX_POOL_DISABLED; return RpcErrorType.TX_POOL_DISABLED;
case PLUGIN_TX_VALIDATOR: case PLUGIN_TX_VALIDATOR:
return RpcErrorType.PLUGIN_TX_VALIDATOR; return RpcErrorType.PLUGIN_TX_VALIDATOR;
case INVALID_BLOBS:
return RpcErrorType.INVALID_BLOBS;
default: default:
return RpcErrorType.INTERNAL_ERROR; return RpcErrorType.INTERNAL_ERROR;
} }

@ -44,6 +44,7 @@ public enum RpcMethod {
DEBUG_STANDARD_TRACE_BLOCK_TO_FILE("debug_standardTraceBlockToFile"), DEBUG_STANDARD_TRACE_BLOCK_TO_FILE("debug_standardTraceBlockToFile"),
DEBUG_STANDARD_TRACE_BAD_BLOCK_TO_FILE("debug_standardTraceBadBlockToFile"), DEBUG_STANDARD_TRACE_BAD_BLOCK_TO_FILE("debug_standardTraceBadBlockToFile"),
DEBUG_TRACE_TRANSACTION("debug_traceTransaction"), DEBUG_TRACE_TRANSACTION("debug_traceTransaction"),
DEBUG_TRACE_CALL("debug_traceCall"),
DEBUG_BATCH_RAW_TRANSACTION("debug_batchSendRawTransaction"), DEBUG_BATCH_RAW_TRANSACTION("debug_batchSendRawTransaction"),
DEBUG_GET_BAD_BLOCKS("debug_getBadBlocks"), DEBUG_GET_BAD_BLOCKS("debug_getBadBlocks"),
DEBUG_GET_RAW_HEADER("debug_getRawHeader"), DEBUG_GET_RAW_HEADER("debug_getRawHeader"),

@ -0,0 +1,84 @@
/*
* Copyright Hyperledger Besu.
*
* 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;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.debug.TraceOptions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.transaction.PreCloseStateHandler;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractTraceCall extends AbstractTraceByBlock {
private static final Logger LOG = LoggerFactory.getLogger(AbstractTraceCall.class);
public AbstractTraceCall(
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,
final TransactionSimulator transactionSimulator) {
super(blockchainQueries, protocolSchedule, transactionSimulator);
}
@Override
protected Object resultByBlockNumber(
final JsonRpcRequestContext requestContext, final long blockNumber) {
final JsonCallParameter callParams =
JsonCallParameterUtil.validateAndGetCallParams(requestContext);
final TraceOptions traceOptions = getTraceOptions(requestContext);
final String blockNumberString = String.valueOf(blockNumber);
LOG.atTrace()
.setMessage("Received RPC rpcName={} callParams={} block={} traceTypes={}")
.addArgument(this::getName)
.addArgument(callParams)
.addArgument(blockNumberString)
.addArgument(traceOptions)
.log();
final Optional<BlockHeader> maybeBlockHeader =
blockchainQueriesSupplier.get().getBlockHeaderByNumber(blockNumber);
if (maybeBlockHeader.isEmpty()) {
return new JsonRpcErrorResponse(requestContext.getRequest().getId(), BLOCK_NOT_FOUND);
}
final DebugOperationTracer tracer = new DebugOperationTracer(traceOptions);
return transactionSimulator
.process(
callParams,
buildTransactionValidationParams(),
tracer,
getSimulatorResultHandler(requestContext, tracer),
maybeBlockHeader.get())
.orElseGet(
() -> new JsonRpcErrorResponse(requestContext.getRequest().getId(), INTERNAL_ERROR));
}
protected abstract TraceOptions getTraceOptions(final JsonRpcRequestContext requestContext);
protected abstract PreCloseStateHandler<Object> getSimulatorResultHandler(
final JsonRpcRequestContext requestContext, final DebugOperationTracer tracer);
}

@ -0,0 +1,91 @@
/*
* Copyright Hyperledger Besu.
*
* 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;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR;
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.parameters.BlockParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace;
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.results.DebugTraceTransactionResult;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.debug.TraceOptions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.transaction.PreCloseStateHandler;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DebugTraceCall extends AbstractTraceCall {
private static final Logger LOG = LoggerFactory.getLogger(DebugTraceCall.class);
public DebugTraceCall(
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,
final TransactionSimulator transactionSimulator) {
super(blockchainQueries, protocolSchedule, transactionSimulator);
}
@Override
public String getName() {
return RpcMethod.DEBUG_TRACE_CALL.getMethodName();
}
@Override
protected TraceOptions getTraceOptions(final JsonRpcRequestContext requestContext) {
return requestContext
.getOptionalParameter(2, TransactionTraceParams.class)
.map(TransactionTraceParams::traceOptions)
.orElse(TraceOptions.DEFAULT);
}
@Override
protected BlockParameter blockParameter(final JsonRpcRequestContext request) {
final Optional<BlockParameter> maybeBlockParameter =
request.getOptionalParameter(1, BlockParameter.class);
return maybeBlockParameter.orElse(BlockParameter.LATEST);
}
@Override
protected PreCloseStateHandler<Object> getSimulatorResultHandler(
final JsonRpcRequestContext requestContext, final DebugOperationTracer tracer) {
return (mutableWorldState, maybeSimulatorResult) ->
maybeSimulatorResult.map(
result -> {
if (result.isInvalid()) {
LOG.error("Invalid simulator result {}", result);
final JsonRpcError error =
new JsonRpcError(
INTERNAL_ERROR, result.getValidationResult().getErrorMessage());
return new JsonRpcErrorResponse(requestContext.getRequest().getId(), error);
}
final TransactionTrace transactionTrace =
new TransactionTrace(
result.getTransaction(), result.getResult(), tracer.getTraceFrames());
return new DebugTraceTransactionResult(transactionTrace);
});
}
}

@ -47,6 +47,7 @@ import java.util.stream.Stream;
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
public class EthFeeHistory implements JsonRpcMethod { public class EthFeeHistory implements JsonRpcMethod {
@ -187,7 +188,8 @@ public class EthFeeHistory implements JsonRpcMethod {
.build())); .build()));
} }
private List<Wei> computeRewards(final List<Double> rewardPercentiles, final Block block) { @VisibleForTesting
public List<Wei> computeRewards(final List<Double> rewardPercentiles, final Block block) {
final List<Transaction> transactions = block.getBody().getTransactions(); final List<Transaction> transactions = block.getBody().getTransactions();
if (transactions.isEmpty()) { if (transactions.isEmpty()) {
// all 0's for empty block // all 0's for empty block
@ -201,13 +203,11 @@ public class EthFeeHistory implements JsonRpcMethod {
// we need to get the gas used for the individual transactions and can't use the cumulative gas // we need to get the gas used for the individual transactions and can't use the cumulative gas
// used because we're going to be reordering the transactions // used because we're going to be reordering the transactions
final List<Long> transactionsGasUsed = new ArrayList<>(); final List<Long> transactionsGasUsed = new ArrayList<>();
long cumulativeGasUsed = 0L;
for (final TransactionReceipt transactionReceipt : for (final TransactionReceipt transactionReceipt :
blockchain.getTxReceipts(block.getHash()).get()) { blockchain.getTxReceipts(block.getHash()).get()) {
transactionsGasUsed.add( transactionsGasUsed.add(transactionReceipt.getCumulativeGasUsed() - cumulativeGasUsed);
transactionsGasUsed.isEmpty() cumulativeGasUsed = transactionReceipt.getCumulativeGasUsed();
? transactionReceipt.getCumulativeGasUsed()
: transactionReceipt.getCumulativeGasUsed()
- transactionsGasUsed.get(transactionsGasUsed.size() - 1));
} }
record TransactionInfo(Transaction transaction, Long gasUsed, Wei effectivePriorityFeePerGas) {} record TransactionInfo(Transaction transaction, Long gasUsed, Wei effectivePriorityFeePerGas) {}
@ -226,23 +226,26 @@ public class EthFeeHistory implements JsonRpcMethod {
.sorted(Comparator.comparing(TransactionInfo::effectivePriorityFeePerGas)) .sorted(Comparator.comparing(TransactionInfo::effectivePriorityFeePerGas))
.collect(toUnmodifiableList()); .collect(toUnmodifiableList());
// We need to weight the percentile of rewards by the gas used in the transaction.
// That's why we're keeping track of the cumulative gas used and checking to see which
// percentile markers we've passed
final ArrayList<Wei> rewards = new ArrayList<>(); final ArrayList<Wei> rewards = new ArrayList<>();
int rewardPercentileIndex = 0; // Start with the gas used by the first transaction
long gasUsed = 0; double totalGasUsed = transactionsAndGasUsedAscendingEffectiveGasFee.get(0).gasUsed();
for (final TransactionInfo transactionAndGasUsed : var transactionIndex = 0;
transactionsAndGasUsedAscendingEffectiveGasFee) { for (var rewardPercentile : rewardPercentiles) {
// Calculate the threshold gas used for the current reward percentile. This is the amount of
gasUsed += transactionAndGasUsed.gasUsed(); // gas that needs to be used to reach this percentile
var thresholdGasUsed = rewardPercentile * block.getHeader().getGasUsed() / 100;
while (rewardPercentileIndex < rewardPercentiles.size()
&& 100.0 * gasUsed / block.getHeader().getGasUsed() // Stop when totalGasUsed reaches the threshold or there are no more transactions
>= rewardPercentiles.get(rewardPercentileIndex)) { while (totalGasUsed < thresholdGasUsed
rewards.add(transactionAndGasUsed.effectivePriorityFeePerGas); && transactionIndex < transactionsAndGasUsedAscendingEffectiveGasFee.size() - 1) {
rewardPercentileIndex++; transactionIndex++;
totalGasUsed +=
transactionsAndGasUsedAscendingEffectiveGasFee.get(transactionIndex).gasUsed();
} }
// Add the effective priority fee per gas of the transaction that reached the percentile value
rewards.add(
transactionsAndGasUsedAscendingEffectiveGasFee.get(transactionIndex)
.effectivePriorityFeePerGas);
} }
// Put the computed rewards in the cache // Put the computed rewards in the cache
cache.put(new RewardCacheKey(block.getHeader().getBlockHash(), rewardPercentiles), rewards); cache.put(new RewardCacheKey(block.getHeader().getBlockHash(), rewardPercentiles), rewards);

@ -14,29 +14,27 @@
*/ */
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR;
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.parameters.JsonCallParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TraceTypeParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TraceTypeParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace;
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.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.debug.TraceOptions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.transaction.PreCloseStateHandler;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class TraceCall extends AbstractTraceByBlock implements JsonRpcMethod { public class TraceCall extends AbstractTraceCall {
private static final Logger LOG = LoggerFactory.getLogger(TraceCall.class); private static final Logger LOG = LoggerFactory.getLogger(TraceCall.class);
public TraceCall( public TraceCall(
@ -52,56 +50,35 @@ public class TraceCall extends AbstractTraceByBlock implements JsonRpcMethod {
} }
@Override @Override
protected Object resultByBlockNumber( protected TraceOptions getTraceOptions(final JsonRpcRequestContext requestContext) {
final JsonRpcRequestContext requestContext, final long blockNumber) { return buildTraceOptions(getTraceTypes(requestContext));
final JsonCallParameter callParams = }
JsonCallParameterUtil.validateAndGetCallParams(requestContext);
final TraceTypeParameter traceTypeParameter =
requestContext.getRequiredParameter(1, TraceTypeParameter.class);
final String blockNumberString = String.valueOf(blockNumber);
LOG.atTrace()
.setMessage("Received RPC rpcName={} callParams={} block={} traceTypes={}")
.addArgument(this::getName)
.addArgument(callParams)
.addArgument(blockNumberString)
.addArgument(traceTypeParameter)
.log();
final Optional<BlockHeader> maybeBlockHeader =
blockchainQueriesSupplier.get().getBlockHeaderByNumber(blockNumber);
if (maybeBlockHeader.isEmpty()) {
return new JsonRpcErrorResponse(requestContext.getRequest().getId(), BLOCK_NOT_FOUND);
}
final Set<TraceTypeParameter.TraceType> traceTypes = traceTypeParameter.getTraceTypes();
final DebugOperationTracer tracer = new DebugOperationTracer(buildTraceOptions(traceTypes)); private Set<TraceTypeParameter.TraceType> getTraceTypes(
return transactionSimulator final JsonRpcRequestContext requestContext) {
.process( return requestContext.getRequiredParameter(1, TraceTypeParameter.class).getTraceTypes();
callParams, }
buildTransactionValidationParams(),
tracer,
(mutableWorldState, maybeSimulatorResult) ->
maybeSimulatorResult.map(
result -> {
if (result.isInvalid()) {
LOG.error(String.format("Invalid simulator result %s", result));
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), INTERNAL_ERROR);
}
final TransactionTrace transactionTrace = @Override
new TransactionTrace( protected PreCloseStateHandler<Object> getSimulatorResultHandler(
result.getTransaction(), result.getResult(), tracer.getTraceFrames()); final JsonRpcRequestContext requestContext, final DebugOperationTracer tracer) {
return (mutableWorldState, maybeSimulatorResult) ->
maybeSimulatorResult.map(
result -> {
if (result.isInvalid()) {
LOG.error("Invalid simulator result {}", result);
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), INTERNAL_ERROR);
}
final Block block = final TransactionTrace transactionTrace =
blockchainQueriesSupplier.get().getBlockchain().getChainHeadBlock(); new TransactionTrace(
result.getTransaction(), result.getResult(), tracer.getTraceFrames());
return getTraceCallResult( final Block block =
protocolSchedule, traceTypes, result, transactionTrace, block); blockchainQueriesSupplier.get().getBlockchain().getChainHeadBlock();
}), return getTraceCallResult(
maybeBlockHeader.get()) protocolSchedule, getTraceTypes(requestContext), result, transactionTrace, block);
.orElse(new JsonRpcErrorResponse(requestContext.getRequest().getId(), INTERNAL_ERROR)); });
} }
} }

@ -213,7 +213,9 @@ public enum RpcErrorType {
BLOCK_RLP_IMPORT_ERROR(-32000, "Could not decode RLP for Block"), BLOCK_RLP_IMPORT_ERROR(-32000, "Could not decode RLP for Block"),
BLOCK_IMPORT_ERROR(-32000, "Could not import Block"), BLOCK_IMPORT_ERROR(-32000, "Could not import Block"),
UNKNOWN(-32603, "Unknown internal error"); UNKNOWN(-32603, "Unknown internal error"),
INVALID_BLOBS(-32603, "blobs failed kzg validation");
private final int code; private final int code;
private final String message; private final String message;

@ -24,6 +24,7 @@ import java.util.TreeMap;
import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
@JsonPropertyOrder({"pc", "op", "gas", "gasCost", "depth", "stack", "memory", "storage"}) @JsonPropertyOrder({"pc", "op", "gas", "gasCost", "depth", "stack", "memory", "storage"})
@ -38,6 +39,7 @@ public class StructLog {
private final String[] stack; private final String[] stack;
private final Object storage; private final Object storage;
private final String reason; private final String reason;
static final String bytes32ZeroString = Bytes32.ZERO.toUnprefixedHexString();
public StructLog(final TraceFrame traceFrame) { public StructLog(final TraceFrame traceFrame) {
depth = traceFrame.getDepth() + 1; depth = traceFrame.getDepth() + 1;
@ -53,12 +55,25 @@ public class StructLog {
stack = stack =
traceFrame traceFrame
.getStack() .getStack()
.map(a -> Arrays.stream(a).map(Bytes::toUnprefixedHexString).toArray(String[]::new)) .map(
a ->
Arrays.stream(a)
.map(Bytes::toUnprefixedHexString)
.map(this::stringLeftPadTo64)
.toArray(String[]::new))
.orElse(null); .orElse(null);
storage = traceFrame.getStorage().map(StructLog::formatStorage).orElse(null); storage = traceFrame.getStorage().map(StructLog::formatStorage).orElse(null);
reason = traceFrame.getRevertReason().map(Bytes::toShortHexString).orElse(null); reason = traceFrame.getRevertReason().map(Bytes::toShortHexString).orElse(null);
} }
private String stringLeftPadTo64(final String unPaddedHexString) {
StringBuilder sb = new StringBuilder(64);
sb.append(bytes32ZeroString, 0, 64 - unPaddedHexString.length());
sb.append(unPaddedHexString);
return sb.toString();
}
private static Map<String, String> formatStorage(final Map<UInt256, UInt256> storage) { private static Map<String, String> formatStorage(final Map<UInt256, UInt256> storage) {
final Map<String, String> formattedStorage = new TreeMap<>(); final Map<String, String> formattedStorage = new TreeMap<>();
storage.forEach( storage.forEach(

@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugStorageRa
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlock; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlock;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlockByHash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlockByHash;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlockByNumber; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceBlockByNumber;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceCall;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceTransaction; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugTraceTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay;
@ -45,6 +46,7 @@ import org.hyperledger.besu.ethereum.core.Synchronizer;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import java.nio.file.Path; import java.nio.file.Path;
@ -113,6 +115,13 @@ public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
new DebugGetRawHeader(blockchainQueries), new DebugGetRawHeader(blockchainQueries),
new DebugGetRawBlock(blockchainQueries), new DebugGetRawBlock(blockchainQueries),
new DebugGetRawReceipts(blockchainQueries), new DebugGetRawReceipts(blockchainQueries),
new DebugGetRawTransaction(blockchainQueries)); new DebugGetRawTransaction(blockchainQueries),
new DebugTraceCall(
blockchainQueries,
protocolSchedule,
new TransactionSimulator(
blockchainQueries.getBlockchain(),
blockchainQueries.getWorldStateArchive(),
protocolSchedule)));
} }
} }

@ -28,9 +28,9 @@ public class DebugJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest {
} }
public static Object[][] specs() { public static Object[][] specs() {
return findSpecFiles( return AbstractJsonRpcHttpBySpecTest.findSpecFiles(
new String[] {"debug"}, new String[] {
"storageRange", "debug/account-at", "debug/batch-send-raw-transaction", "debug/trace-transaction"
"accountRange"); // storageRange and accountRange are not working with bonsai trie }); // storageRange and accountRange are not working with bonsai trie
} }
} }

@ -0,0 +1,41 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.bonsai;
import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.junit.jupiter.api.BeforeEach;
public class DebugTraceJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest {
@Override
@BeforeEach
public void setup() throws Exception {
setupBonsaiBlockchain();
startService();
}
@Override
protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat storageFormat) {
return createBlockchainSetupUtil(
"trace/chain-data/genesis.json", "trace/chain-data/blocks.bin", storageFormat);
}
public static Object[][] specs() {
return AbstractJsonRpcHttpBySpecTest.findSpecFiles(new String[] {"debug/trace-call"});
}
}

@ -28,6 +28,13 @@ public class DebugJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest {
} }
public static Object[][] specs() { public static Object[][] specs() {
return findSpecFiles(new String[] {"debug"}); return AbstractJsonRpcHttpBySpecTest.findSpecFiles(
new String[] {
"debug/account-at",
"debug/batch-send-raw-transaction",
"debug/trace-transaction",
"debug/account-range",
"debug/storage-range"
});
} }
} }

@ -0,0 +1,41 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.forest;
import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.junit.jupiter.api.BeforeEach;
public class DebugTraceJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest {
@Override
@BeforeEach
public void setup() throws Exception {
setupBlockchain();
startService();
}
@Override
protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat storageFormat) {
return createBlockchainSetupUtil(
"trace/chain-data/genesis.json", "trace/chain-data/blocks.bin", storageFormat);
}
public static Object[][] specs() {
return AbstractJsonRpcHttpBySpecTest.findSpecFiles(new String[] {"debug/trace-call"});
}
}

@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
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.JsonRpcRequest; 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.JsonRpcRequestContext;
@ -34,15 +35,27 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.FeeHistory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.FeeHistory;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistory;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistoryResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistoryResult;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
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.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
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.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -104,6 +117,68 @@ public class EthFeeHistoryTest {
.build())); .build()));
} }
@Test
public void shouldComputeRewardsCorrectly() {
// Define the percentiles of rewards we want to compute
List<Double> rewardPercentiles =
Arrays.asList(0.0, 5.0, 10.0, 30.0, 31.0, 59.0, 60.0, 61.0, 100.0);
// Define the expected rewards for each percentile
// The expected rewards match the fees of the transactions at each percentile in the
// rewardPercentiles list
List<Wei> expectedRewards = Stream.of(1, 1, 2, 5, 5, 6, 6, 7, 7).map(Wei::of).toList();
// Define a list of gas used and fee pairs. Each pair represents a transaction in the block.
// The first number is the gas used by the transaction, and the second number the fee.
// The comments indicate the cumulative gas used up as a percentage of the total gas limit.
List<Object[]> gasUsedAndFee = new ArrayList<>();
gasUsedAndFee.add(new Object[] {100, 1L}); // 5%
gasUsedAndFee.add(new Object[] {150, 2L}); // 12.5%
gasUsedAndFee.add(new Object[] {200, 3L}); // 22.5%
gasUsedAndFee.add(new Object[] {100, 4L}); // 27.5%
gasUsedAndFee.add(new Object[] {200, 5L}); // 37.5%
gasUsedAndFee.add(new Object[] {450, 6L}); // 60.0%
gasUsedAndFee.add(new Object[] {800, 7L}); // 100.0%
Collections.shuffle(gasUsedAndFee);
Block block = mock(Block.class);
Blockchain blockchain = mockBlockchainTransactionsWithPriorityFee(gasUsedAndFee, block);
EthFeeHistory ethFeeHistory = new EthFeeHistory(null, blockchain);
List<Wei> rewards = ethFeeHistory.computeRewards(rewardPercentiles, block);
// Check that the number of computed rewards is equal to the number of requested percentiles
assertThat(rewards.size()).isEqualTo(rewardPercentiles.size());
assertThat(rewards).isEqualTo(expectedRewards);
}
private Blockchain mockBlockchainTransactionsWithPriorityFee(
final List<Object[]> gasUsedAndFee, final Block block) {
final Blockchain blockchain = mock(Blockchain.class);
when(block.getHash()).thenReturn(Hash.wrap(Bytes32.wrap(Bytes.random(32))));
BlockBody body = mock(BlockBody.class);
BlockHeader blockHeader = mock(BlockHeader.class);
when(block.getHeader()).thenReturn(blockHeader);
when(block.getBody()).thenReturn(body);
long cumulativeGasUsed = 0;
List<Transaction> transactions = new ArrayList<>();
List<TransactionReceipt> receipts = new ArrayList<>();
for (Object[] objects : gasUsedAndFee) {
Transaction transaction = mock(Transaction.class);
when(transaction.getEffectivePriorityFeePerGas(any())).thenReturn(Wei.of((Long) objects[1]));
cumulativeGasUsed += (int) objects[0];
transactions.add(transaction);
TransactionReceipt receipt = mock(TransactionReceipt.class);
when(receipt.getCumulativeGasUsed()).thenReturn(cumulativeGasUsed);
receipts.add(receipt);
}
when(blockHeader.getGasUsed()).thenReturn(cumulativeGasUsed);
when(blockchain.getTxReceipts(any())).thenReturn(Optional.of(receipts));
when(body.getTransactions()).thenReturn(transactions);
return blockchain;
}
@Test @Test
public void cantGetBlockHigherThanChainHead() { public void cantGetBlockHigherThanChainHead() {
assertThat( assertThat(

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -71,7 +72,8 @@ class EthGetTransactionByHashTest {
@Test @Test
void shouldReturnErrorResponseIfMissingRequiredParameter() { void shouldReturnErrorResponseIfMissingRequiredParameter() {
final JsonRpcRequest request = new JsonRpcRequest("2.0", method.getName(), new Object[] {}); final JsonRpcRequest request =
new JsonRpcRequest(JSON_RPC_VERSION, method.getName(), new Object[] {});
final JsonRpcRequestContext context = new JsonRpcRequestContext(request); final JsonRpcRequestContext context = new JsonRpcRequestContext(request);
final JsonRpcErrorResponse expectedResponse = final JsonRpcErrorResponse expectedResponse =
@ -92,7 +94,7 @@ class EthGetTransactionByHashTest {
.thenReturn(Optional.empty()); .thenReturn(Optional.empty());
final JsonRpcRequest request = final JsonRpcRequest request =
new JsonRpcRequest("2.0", method.getName(), new Object[] {transactionHash}); new JsonRpcRequest(JSON_RPC_VERSION, method.getName(), new Object[] {transactionHash});
final JsonRpcRequestContext context = new JsonRpcRequestContext(request); final JsonRpcRequestContext context = new JsonRpcRequestContext(request);
final JsonRpcSuccessResponse expectedResponse = final JsonRpcSuccessResponse expectedResponse =
@ -115,7 +117,7 @@ class EthGetTransactionByHashTest {
final JsonRpcRequest request = final JsonRpcRequest request =
new JsonRpcRequest( new JsonRpcRequest(
"2.0", method.getName(), new Object[] {transaction.getHash().toHexString()}); JSON_RPC_VERSION, method.getName(), new Object[] {transaction.getHash().toHexString()});
final JsonRpcRequestContext context = new JsonRpcRequestContext(request); final JsonRpcRequestContext context = new JsonRpcRequestContext(request);
final JsonRpcSuccessResponse expectedResponse = final JsonRpcSuccessResponse expectedResponse =
@ -141,7 +143,7 @@ class EthGetTransactionByHashTest {
final JsonRpcRequest request = final JsonRpcRequest request =
new JsonRpcRequest( new JsonRpcRequest(
"2.0", method.getName(), new Object[] {transaction.getHash().toHexString()}); JSON_RPC_VERSION, method.getName(), new Object[] {transaction.getHash().toHexString()});
final JsonRpcRequestContext context = new JsonRpcRequestContext(request); final JsonRpcRequestContext context = new JsonRpcRequestContext(request);
final JsonRpcSuccessResponse expectedResponse = final JsonRpcSuccessResponse expectedResponse =
@ -181,8 +183,23 @@ class EthGetTransactionByHashTest {
assertThat(result.getRaw()).isNotNull(); assertThat(result.getRaw()).isNotNull();
assertThat(result.getTo()).isNotNull(); assertThat(result.getTo()).isNotNull();
assertThat(result.getValue()).isNotNull(); assertThat(result.getValue()).isNotNull();
assertThat(result.getYParity()).isNotNull(); switch (result.getType()) {
assertThat(result.getV()).isNotNull(); case "0x0":
assertThat(result.getYParity()).isNull();
assertThat(result.getV()).isNotNull();
break;
case "0x1":
case "0x2":
assertThat(result.getYParity()).isNotNull();
assertThat(result.getV()).isNotNull();
break;
case "0x3":
assertThat(result.getYParity()).isNotNull();
assertThat(result.getV()).isNull();
break;
default:
fail("unknownType " + result.getType());
}
assertThat(result.getR()).isNotNull(); assertThat(result.getR()).isNotNull();
assertThat(result.getS()).isNotNull(); assertThat(result.getS()).isNotNull();
} }

@ -0,0 +1,300 @@
{
"request" : {
"jsonrpc" : "2.0",
"method" : "debug_traceCall",
"params" : [ {
"from" : "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
"to" : "0x0050000000000000000000000000000000000000",
"gas" : "0xfffff2",
"gasPrice" : "0xef",
"value" : "0x0",
"data" : "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001",
"nonce" : "0x0"
}, "latest",
{
"disableMemory": true, "disableStack": true, "disableStorage": true
} ],
"id" : 1
},
"response": {
"jsonrpc": "2.0",
"id": 1,
"result": {
"gas" : 22070,
"failed" : false,
"returnValue" : "f000000000000000000000000000000000000000000000000000000000000002",
"structLogs" : [ {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16755910,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 2,
"op" : "PUSH1",
"gas" : 16755907,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 4,
"op" : "PUSH1",
"gas" : 16755904,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 6,
"op" : "CALLDATASIZE",
"gas" : 16755901,
"gasCost" : 2,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 7,
"op" : "SUB",
"gas" : 16755899,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 8,
"op" : "DUP1",
"gas" : 16755896,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16755893,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16755890,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 13,
"op" : "CALLDATACOPY",
"gas" : 16755887,
"gasCost" : 9,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 14,
"op" : "PUSH1",
"gas" : 16755878,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 16,
"op" : "CALLVALUE",
"gas" : 16755875,
"gasCost" : 2,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 17,
"op" : "PUSH1",
"gas" : 16755873,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 19,
"op" : "CALLDATALOAD",
"gas" : 16755870,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 20,
"op" : "GAS",
"gas" : 16755867,
"gasCost" : 2,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16493366,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 2,
"op" : "CALLDATALOAD",
"gas" : 16493363,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 3,
"op" : "PUSH1",
"gas" : 16493360,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 5,
"op" : "ADD",
"gas" : 16493357,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 6,
"op" : "PUSH1",
"gas" : 16493354,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 8,
"op" : "MSTORE",
"gas" : 16493351,
"gasCost" : 6,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16493345,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16493342,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 13,
"op" : "RETURN",
"gas" : 16493339,
"gasCost" : 0,
"depth" : 2,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 22,
"op" : "PUSH1",
"gas" : 16755138,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 24,
"op" : "PUSH1",
"gas" : 16755135,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
}, {
"pc" : 26,
"op" : "RETURN",
"gas" : 16755132,
"gasCost" : 0,
"depth" : 1,
"stack" : null,
"memory" : null,
"storage" : null,
"reason" : null
} ]
}
},
"statusCode": 200
}

@ -0,0 +1,297 @@
{
"request" : {
"jsonrpc" : "2.0",
"method" : "debug_traceCall",
"params" : [ {
"from" : "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
"to" : "0x0050000000000000000000000000000000000000",
"gas" : "0xfffff2",
"gasPrice" : "0xef",
"value" : "0x0",
"data" : "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001",
"nonce" : "0x0"
}, "latest" ],
"id" : 1
},
"response": {
"jsonrpc": "2.0",
"id": 1,
"result": {
"gas" : 22070,
"failed" : false,
"returnValue" : "f000000000000000000000000000000000000000000000000000000000000002",
"structLogs" : [ {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16755910,
"gasCost" : 3,
"depth" : 1,
"stack" : [ ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 2,
"op" : "PUSH1",
"gas" : 16755907,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 4,
"op" : "PUSH1",
"gas" : 16755904,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 6,
"op" : "CALLDATASIZE",
"gas" : 16755901,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 7,
"op" : "SUB",
"gas" : 16755899,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000040" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 8,
"op" : "DUP1",
"gas" : 16755896,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16755893,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16755890,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 13,
"op" : "CALLDATACOPY",
"gas" : 16755887,
"gasCost" : 9,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 14,
"op" : "PUSH1",
"gas" : 16755878,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 16,
"op" : "CALLVALUE",
"gas" : 16755875,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 17,
"op" : "PUSH1",
"gas" : 16755873,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 19,
"op" : "CALLDATALOAD",
"gas" : 16755870,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 20,
"op" : "GAS",
"gas" : 16755867,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000ffac99" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16493366,
"gasCost" : 3,
"depth" : 2,
"stack" : [ ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 2,
"op" : "CALLDATALOAD",
"gas" : 16493363,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 3,
"op" : "PUSH1",
"gas" : 16493360,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 5,
"op" : "ADD",
"gas" : 16493357,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 6,
"op" : "PUSH1",
"gas" : 16493354,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 8,
"op" : "MSTORE",
"gas" : 16493351,
"gasCost" : 6,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000002", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16493345,
"gasCost" : 3,
"depth" : 2,
"stack" : [ ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16493342,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 13,
"op" : "RETURN",
"gas" : 16493339,
"gasCost" : 0,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 22,
"op" : "PUSH1",
"gas" : 16755138,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 24,
"op" : "PUSH1",
"gas" : 16755135,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 26,
"op" : "RETURN",
"gas" : 16755132,
"gasCost" : 0,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
} ]
}
},
"statusCode": 200
}

@ -0,0 +1,300 @@
{
"request" : {
"jsonrpc" : "2.0",
"method" : "debug_traceCall",
"params" : [ {
"from" : "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
"to" : "0x0050000000000000000000000000000000000000",
"gas" : "0xfffff2",
"gasPrice" : "0xef",
"value" : "0x0",
"data" : "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001",
"nonce" : "0x0"
}, "latest",
{
"disableMemory":true
} ],
"id" : 1
},
"response": {
"jsonrpc": "2.0",
"id": 1,
"result": {
"gas" : 22070,
"failed" : false,
"returnValue" : "f000000000000000000000000000000000000000000000000000000000000002",
"structLogs" : [ {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16755910,
"gasCost" : 3,
"depth" : 1,
"stack" : [ ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 2,
"op" : "PUSH1",
"gas" : 16755907,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 4,
"op" : "PUSH1",
"gas" : 16755904,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 6,
"op" : "CALLDATASIZE",
"gas" : 16755901,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 7,
"op" : "SUB",
"gas" : 16755899,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000040" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 8,
"op" : "DUP1",
"gas" : 16755896,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16755893,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16755890,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 13,
"op" : "CALLDATACOPY",
"gas" : 16755887,
"gasCost" : 9,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 14,
"op" : "PUSH1",
"gas" : 16755878,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 16,
"op" : "CALLVALUE",
"gas" : 16755875,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 17,
"op" : "PUSH1",
"gas" : 16755873,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 19,
"op" : "CALLDATALOAD",
"gas" : 16755870,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 20,
"op" : "GAS",
"gas" : 16755867,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000ffac99" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16493366,
"gasCost" : 3,
"depth" : 2,
"stack" : [ ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 2,
"op" : "CALLDATALOAD",
"gas" : 16493363,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 3,
"op" : "PUSH1",
"gas" : 16493360,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 5,
"op" : "ADD",
"gas" : 16493357,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 6,
"op" : "PUSH1",
"gas" : 16493354,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 8,
"op" : "MSTORE",
"gas" : 16493351,
"gasCost" : 6,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000002", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16493345,
"gasCost" : 3,
"depth" : 2,
"stack" : [ ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16493342,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 13,
"op" : "RETURN",
"gas" : 16493339,
"gasCost" : 0,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 22,
"op" : "PUSH1",
"gas" : 16755138,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 24,
"op" : "PUSH1",
"gas" : 16755135,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : null,
"storage" : { },
"reason" : null
}, {
"pc" : 26,
"op" : "RETURN",
"gas" : 16755132,
"gasCost" : 0,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : null,
"storage" : { },
"reason" : null
} ]
}
},
"statusCode": 200
}

@ -0,0 +1,300 @@
{
"request" : {
"jsonrpc" : "2.0",
"method" : "debug_traceCall",
"params" : [ {
"from" : "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
"to" : "0x0050000000000000000000000000000000000000",
"gas" : "0xfffff2",
"gasPrice" : "0xef",
"value" : "0x0",
"data" : "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001",
"nonce" : "0x0"
}, "latest",
{
"disableStack": true
} ],
"id" : 1
},
"response": {
"jsonrpc": "2.0",
"id": 1,
"result": {
"gas" : 22070,
"failed" : false,
"returnValue" : "f000000000000000000000000000000000000000000000000000000000000002",
"structLogs" : [ {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16755910,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 2,
"op" : "PUSH1",
"gas" : 16755907,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 4,
"op" : "PUSH1",
"gas" : 16755904,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 6,
"op" : "CALLDATASIZE",
"gas" : 16755901,
"gasCost" : 2,
"depth" : 1,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 7,
"op" : "SUB",
"gas" : 16755899,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 8,
"op" : "DUP1",
"gas" : 16755896,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16755893,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16755890,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 13,
"op" : "CALLDATACOPY",
"gas" : 16755887,
"gasCost" : 9,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 14,
"op" : "PUSH1",
"gas" : 16755878,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 16,
"op" : "CALLVALUE",
"gas" : 16755875,
"gasCost" : 2,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 17,
"op" : "PUSH1",
"gas" : 16755873,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 19,
"op" : "CALLDATALOAD",
"gas" : 16755870,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 20,
"op" : "GAS",
"gas" : 16755867,
"gasCost" : 2,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : { },
"reason" : null
}, {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16493366,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 2,
"op" : "CALLDATALOAD",
"gas" : 16493363,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 3,
"op" : "PUSH1",
"gas" : 16493360,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 5,
"op" : "ADD",
"gas" : 16493357,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 6,
"op" : "PUSH1",
"gas" : 16493354,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : [ ],
"storage" : { },
"reason" : null
}, {
"pc" : 8,
"op" : "MSTORE",
"gas" : 16493351,
"gasCost" : 6,
"depth" : 2,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16493345,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16493342,
"gasCost" : 3,
"depth" : 2,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 13,
"op" : "RETURN",
"gas" : 16493339,
"gasCost" : 0,
"depth" : 2,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 22,
"op" : "PUSH1",
"gas" : 16755138,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 24,
"op" : "PUSH1",
"gas" : 16755135,
"gasCost" : 3,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
}, {
"pc" : 26,
"op" : "RETURN",
"gas" : 16755132,
"gasCost" : 0,
"depth" : 1,
"stack" : null,
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : { },
"reason" : null
} ]
}
},
"statusCode": 200
}

@ -0,0 +1,300 @@
{
"request" : {
"jsonrpc" : "2.0",
"method" : "debug_traceCall",
"params" : [ {
"from" : "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
"to" : "0x0050000000000000000000000000000000000000",
"gas" : "0xfffff2",
"gasPrice" : "0xef",
"value" : "0x0",
"data" : "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001",
"nonce" : "0x0"
}, "latest",
{
"disableStorage": true
} ],
"id" : 1
},
"response": {
"jsonrpc": "2.0",
"id": 1,
"result": {
"gas" : 22070,
"failed" : false,
"returnValue" : "f000000000000000000000000000000000000000000000000000000000000002",
"structLogs" : [ {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16755910,
"gasCost" : 3,
"depth" : 1,
"stack" : [ ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 2,
"op" : "PUSH1",
"gas" : 16755907,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 4,
"op" : "PUSH1",
"gas" : 16755904,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 6,
"op" : "CALLDATASIZE",
"gas" : 16755901,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 7,
"op" : "SUB",
"gas" : 16755899,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000040" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 8,
"op" : "DUP1",
"gas" : 16755896,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16755893,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16755890,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 13,
"op" : "CALLDATACOPY",
"gas" : 16755887,
"gasCost" : 9,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : null,
"reason" : null
}, {
"pc" : 14,
"op" : "PUSH1",
"gas" : 16755878,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : null,
"reason" : null
}, {
"pc" : 16,
"op" : "CALLVALUE",
"gas" : 16755875,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : null,
"reason" : null
}, {
"pc" : 17,
"op" : "PUSH1",
"gas" : 16755873,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : null,
"reason" : null
}, {
"pc" : 19,
"op" : "CALLDATALOAD",
"gas" : 16755870,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : null,
"reason" : null
}, {
"pc" : 20,
"op" : "GAS",
"gas" : 16755867,
"gasCost" : 2,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : null,
"reason" : null
}, {
"pc" : 21,
"op" : "CALLCODE",
"gas" : 16755865,
"gasCost" : 700,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000030000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000ffac99" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"storage" : null,
"reason" : null
}, {
"pc" : 0,
"op" : "PUSH1",
"gas" : 16493366,
"gasCost" : 3,
"depth" : 2,
"stack" : [ ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 2,
"op" : "CALLDATALOAD",
"gas" : 16493363,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 3,
"op" : "PUSH1",
"gas" : 16493360,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 5,
"op" : "ADD",
"gas" : 16493357,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 6,
"op" : "PUSH1",
"gas" : 16493354,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"memory" : [ ],
"storage" : null,
"reason" : null
}, {
"pc" : 8,
"op" : "MSTORE",
"gas" : 16493351,
"gasCost" : 6,
"depth" : 2,
"stack" : [ "f000000000000000000000000000000000000000000000000000000000000002", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : null,
"reason" : null
}, {
"pc" : 9,
"op" : "PUSH1",
"gas" : 16493345,
"gasCost" : 3,
"depth" : 2,
"stack" : [ ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : null,
"reason" : null
}, {
"pc" : 11,
"op" : "PUSH1",
"gas" : 16493342,
"gasCost" : 3,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : null,
"reason" : null
}, {
"pc" : 13,
"op" : "RETURN",
"gas" : 16493339,
"gasCost" : 0,
"depth" : 2,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : null,
"reason" : null
}, {
"pc" : 22,
"op" : "PUSH1",
"gas" : 16755138,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : null,
"reason" : null
}, {
"pc" : 24,
"op" : "PUSH1",
"gas" : 16755135,
"gasCost" : 3,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000020" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : null,
"reason" : null
}, {
"pc" : 26,
"op" : "RETURN",
"gas" : 16755132,
"gasCost" : 0,
"depth" : 1,
"stack" : [ "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000020", "0000000000000000000000000000000000000000000000000000000000000000" ],
"memory" : [ "f000000000000000000000000000000000000000000000000000000000000002" ],
"storage" : null,
"reason" : null
} ]
}
},
"statusCode": 200
}

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.blockcreation.txselection;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.TX_EVALUATION_TOO_LONG;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
@ -95,6 +96,7 @@ public class BlockTransactionSelector {
private final BlockAwareOperationTracer pluginOperationTracer; private final BlockAwareOperationTracer pluginOperationTracer;
private final EthScheduler ethScheduler; private final EthScheduler ethScheduler;
private final AtomicBoolean isTimeout = new AtomicBoolean(false); private final AtomicBoolean isTimeout = new AtomicBoolean(false);
private final long blockTxsSelectionMaxTime;
private WorldUpdater blockWorldStateUpdater; private WorldUpdater blockWorldStateUpdater;
public BlockTransactionSelector( public BlockTransactionSelector(
@ -133,6 +135,7 @@ public class BlockTransactionSelector {
this.pluginTransactionSelector = pluginTransactionSelector; this.pluginTransactionSelector = pluginTransactionSelector;
this.pluginOperationTracer = pluginTransactionSelector.getOperationTracer(); this.pluginOperationTracer = pluginTransactionSelector.getOperationTracer();
blockWorldStateUpdater = worldState.updater(); blockWorldStateUpdater = worldState.updater();
blockTxsSelectionMaxTime = miningParameters.getUnstable().getBlockTxsSelectionMaxTime();
} }
private List<AbstractTransactionSelector> createTransactionSelectors( private List<AbstractTransactionSelector> createTransactionSelectors(
@ -168,8 +171,6 @@ public class BlockTransactionSelector {
} }
private void timeLimitedSelection() { private void timeLimitedSelection() {
final long blockTxsSelectionMaxTime =
blockSelectionContext.miningParameters().getUnstable().getBlockTxsSelectionMaxTime();
final var txSelection = final var txSelection =
ethScheduler.scheduleBlockCreationTask( ethScheduler.scheduleBlockCreationTask(
() -> () ->
@ -226,9 +227,11 @@ public class BlockTransactionSelector {
final PendingTransaction pendingTransaction) { final PendingTransaction pendingTransaction) {
checkCancellation(); checkCancellation();
final long evaluationStartedAt = System.currentTimeMillis();
TransactionSelectionResult selectionResult = evaluatePreProcessing(pendingTransaction); TransactionSelectionResult selectionResult = evaluatePreProcessing(pendingTransaction);
if (!selectionResult.selected()) { if (!selectionResult.selected()) {
return handleTransactionNotSelected(pendingTransaction, selectionResult); return handleTransactionNotSelected(pendingTransaction, selectionResult, evaluationStartedAt);
} }
final WorldUpdater txWorldStateUpdater = blockWorldStateUpdater.updater(); final WorldUpdater txWorldStateUpdater = blockWorldStateUpdater.updater();
@ -239,10 +242,14 @@ public class BlockTransactionSelector {
evaluatePostProcessing(pendingTransaction, processingResult); evaluatePostProcessing(pendingTransaction, processingResult);
if (postProcessingSelectionResult.selected()) { if (postProcessingSelectionResult.selected()) {
return handleTransactionSelected(pendingTransaction, processingResult, txWorldStateUpdater); return handleTransactionSelected(
pendingTransaction, processingResult, txWorldStateUpdater, evaluationStartedAt);
} }
return handleTransactionNotSelected( return handleTransactionNotSelected(
pendingTransaction, postProcessingSelectionResult, txWorldStateUpdater); pendingTransaction,
postProcessingSelectionResult,
txWorldStateUpdater,
evaluationStartedAt);
} }
/** /**
@ -326,12 +333,14 @@ public class BlockTransactionSelector {
* @param pendingTransaction The pending transaction. * @param pendingTransaction The pending transaction.
* @param processingResult The result of the transaction processing. * @param processingResult The result of the transaction processing.
* @param txWorldStateUpdater The world state updater. * @param txWorldStateUpdater The world state updater.
* @param evaluationStartedAt when the evaluation of this tx started
* @return The result of the transaction selection process. * @return The result of the transaction selection process.
*/ */
private TransactionSelectionResult handleTransactionSelected( private TransactionSelectionResult handleTransactionSelected(
final PendingTransaction pendingTransaction, final PendingTransaction pendingTransaction,
final TransactionProcessingResult processingResult, final TransactionProcessingResult processingResult,
final WorldUpdater txWorldStateUpdater) { final WorldUpdater txWorldStateUpdater,
final long evaluationStartedAt) {
final Transaction transaction = pendingTransaction.getTransaction(); final Transaction transaction = pendingTransaction.getTransaction();
final long gasUsedByTransaction = final long gasUsedByTransaction =
@ -347,7 +356,8 @@ public class BlockTransactionSelector {
// this need to be done synchronously to avoid that a concurrent timeout // this need to be done synchronously to avoid that a concurrent timeout
// could start packing a block while we are updating the state here // could start packing a block while we are updating the state here
synchronized (isTimeout) { synchronized (isTimeout) {
if (!isTimeout.get()) { tooLate = isTimeout.get();
if (!tooLate) {
txWorldStateUpdater.commit(); txWorldStateUpdater.commit();
blockWorldStateUpdater.commit(); blockWorldStateUpdater.commit();
final TransactionReceipt receipt = final TransactionReceipt receipt =
@ -356,30 +366,47 @@ public class BlockTransactionSelector {
transactionSelectionResults.updateSelected( transactionSelectionResults.updateSelected(
pendingTransaction.getTransaction(), receipt, gasUsedByTransaction, blobGasUsed); pendingTransaction.getTransaction(), receipt, gasUsedByTransaction, blobGasUsed);
tooLate = false;
} else {
tooLate = true;
} }
} }
final long evaluationTime = System.currentTimeMillis() - evaluationStartedAt;
if (tooLate) { if (tooLate) {
// even if this tx passed all the checks, it is too late to include it in this block, // even if this tx passed all the checks, it is too late to include it in this block,
// so we need to treat it as not selected // so we need to treat it as not selected
LOG.atTrace()
.setMessage("{} processed too late for block creation") // check if this tx took too much to evaluate, and in case remove it from the pool
.addArgument(transaction::toTraceLog) final TransactionSelectionResult timeoutSelectionResult;
.log(); if (evaluationTime > blockTxsSelectionMaxTime) {
LOG.atWarn()
.setMessage(
"Transaction {} is too late for inclusion, evaluated in {}ms that is over the max limit of {}"
+ ", removing it from the pool")
.addArgument(transaction::toTraceLog)
.addArgument(evaluationTime)
.addArgument(blockTxsSelectionMaxTime)
.log();
timeoutSelectionResult = TX_EVALUATION_TOO_LONG;
} else {
LOG.atTrace()
.setMessage("Transaction {} is too late for inclusion")
.addArgument(transaction::toTraceLog)
.addArgument(evaluationTime)
.log();
timeoutSelectionResult = BLOCK_SELECTION_TIMEOUT;
}
// do not rely on the presence of this result, since by the time it is added, the code // do not rely on the presence of this result, since by the time it is added, the code
// reading it could have been already executed by another thread // reading it could have been already executed by another thread
return handleTransactionNotSelected( return handleTransactionNotSelected(
pendingTransaction, BLOCK_SELECTION_TIMEOUT, txWorldStateUpdater); pendingTransaction, timeoutSelectionResult, txWorldStateUpdater, evaluationStartedAt);
} }
pluginTransactionSelector.onTransactionSelected(pendingTransaction, processingResult); pluginTransactionSelector.onTransactionSelected(pendingTransaction, processingResult);
blockWorldStateUpdater = worldState.updater(); blockWorldStateUpdater = worldState.updater();
LOG.atTrace() LOG.atTrace()
.setMessage("Selected {} for block creation") .setMessage("Selected {} for block creation, evaluated in {}ms")
.addArgument(transaction::toTraceLog) .addArgument(transaction::toTraceLog)
.addArgument(evaluationTime)
.log(); .log();
return SELECTED; return SELECTED;
} }
@ -391,24 +418,34 @@ public class BlockTransactionSelector {
* *
* @param pendingTransaction The unselected pending transaction. * @param pendingTransaction The unselected pending transaction.
* @param selectionResult The result of the transaction selection process. * @param selectionResult The result of the transaction selection process.
* @param evaluationStartedAt when the evaluation of this tx started
* @return The result of the transaction selection process. * @return The result of the transaction selection process.
*/ */
private TransactionSelectionResult handleTransactionNotSelected( private TransactionSelectionResult handleTransactionNotSelected(
final PendingTransaction pendingTransaction, final PendingTransaction pendingTransaction,
final TransactionSelectionResult selectionResult) { final TransactionSelectionResult selectionResult,
final long evaluationStartedAt) {
transactionSelectionResults.updateNotSelected( transactionSelectionResults.updateNotSelected(
pendingTransaction.getTransaction(), selectionResult); pendingTransaction.getTransaction(), selectionResult);
pluginTransactionSelector.onTransactionNotSelected(pendingTransaction, selectionResult); pluginTransactionSelector.onTransactionNotSelected(pendingTransaction, selectionResult);
LOG.atTrace()
.setMessage("Not selected {} for block creation with result {}, evaluated in {}ms")
.addArgument(pendingTransaction::toTraceLog)
.addArgument(selectionResult)
.addArgument(() -> System.currentTimeMillis() - evaluationStartedAt)
.log();
return selectionResult; return selectionResult;
} }
private TransactionSelectionResult handleTransactionNotSelected( private TransactionSelectionResult handleTransactionNotSelected(
final PendingTransaction pendingTransaction, final PendingTransaction pendingTransaction,
final TransactionSelectionResult selectionResult, final TransactionSelectionResult selectionResult,
final WorldUpdater txWorldStateUpdater) { final WorldUpdater txWorldStateUpdater,
final long evaluationStartedAt) {
txWorldStateUpdater.revert(); txWorldStateUpdater.revert();
return handleTransactionNotSelected(pendingTransaction, selectionResult); return handleTransactionNotSelected(pendingTransaction, selectionResult, evaluationStartedAt);
} }
private void checkCancellation() { private void checkCancellation() {

@ -383,7 +383,6 @@ abstract class AbstractBlockCreatorTest {
executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolContext(),
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(new NoOpMetricsSystem()), new TransactionPoolMetrics(new NoOpMetricsSystem()),
poolConf, poolConf,
null); null);

@ -18,6 +18,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry; import static org.assertj.core.api.Assertions.entry;
import static org.awaitility.Awaitility.await; import static org.awaitility.Awaitility.await;
import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME; import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.TX_EVALUATION_TOO_LONG;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
@ -177,7 +181,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
protected abstract ProtocolSchedule createProtocolSchedule(); protected abstract ProtocolSchedule createProtocolSchedule();
protected abstract TransactionPool createTransactionPool(final MiningParameters miningParameters); protected abstract TransactionPool createTransactionPool();
private Boolean isCancelled() { private Boolean isCancelled() {
return false; return false;
@ -582,7 +586,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
return TransactionSelectionResult.invalidTransient("transient"); return TransactionSelectionResult.invalidTransient("transient");
if (pendingTransaction.getTransaction().equals(notSelectedInvalid)) if (pendingTransaction.getTransaction().equals(notSelectedInvalid))
return TransactionSelectionResult.invalid("invalid"); return TransactionSelectionResult.invalid("invalid");
return TransactionSelectionResult.SELECTED; return SELECTED;
} }
@Override @Override
@ -590,7 +594,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
final PendingTransaction pendingTransaction, final PendingTransaction pendingTransaction,
final org.hyperledger.besu.plugin.data.TransactionProcessingResult final org.hyperledger.besu.plugin.data.TransactionProcessingResult
processingResult) { processingResult) {
return TransactionSelectionResult.SELECTED; return SELECTED;
} }
}; };
@ -640,7 +644,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
@Override @Override
public TransactionSelectionResult evaluateTransactionPreProcessing( public TransactionSelectionResult evaluateTransactionPreProcessing(
final PendingTransaction pendingTransaction) { final PendingTransaction pendingTransaction) {
return TransactionSelectionResult.SELECTED; return SELECTED;
} }
@Override @Override
@ -652,7 +656,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
if (processingResult.getEstimateGasUsedByTransaction() > maxGasUsedByTransaction) { if (processingResult.getEstimateGasUsedByTransaction() > maxGasUsedByTransaction) {
return TransactionSelectionResult.invalidTransient("Invalid"); return TransactionSelectionResult.invalidTransient("Invalid");
} }
return TransactionSelectionResult.SELECTED; return SELECTED;
} }
}; };
@ -869,9 +873,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
assertThat(results.getSelectedTransactions()).containsOnly(txSelected); assertThat(results.getSelectedTransactions()).containsOnly(txSelected);
assertThat(results.getNotSelectedTransactions()) assertThat(results.getNotSelectedTransactions())
.containsOnly( .containsOnly(entry(txNotSelected, PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN));
entry(
txNotSelected, TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN));
} }
@ParameterizedTest @ParameterizedTest
@ -882,47 +884,84 @@ public abstract class AbstractBlockTransactionSelectorTest {
final boolean processingTooLate, final boolean processingTooLate,
final boolean postProcessingTooLate) { final boolean postProcessingTooLate) {
final Supplier<Answer<TransactionSelectionResult>> inTime = internalBlockSelectionTimeoutSimulation(
() -> invocation -> TransactionSelectionResult.SELECTED; isPoa,
preProcessingTooLate,
processingTooLate,
postProcessingTooLate,
500,
BLOCK_SELECTION_TIMEOUT,
false);
}
@ParameterizedTest
@MethodSource("subsetOfPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOver")
public void pendingTransactionsThatTakesTooLongToEvaluateIsDroppedFromThePool(
final boolean isPoa,
final boolean preProcessingTooLate,
final boolean processingTooLate,
final boolean postProcessingTooLate) {
internalBlockSelectionTimeoutSimulation(
isPoa,
preProcessingTooLate,
processingTooLate,
postProcessingTooLate,
900,
TX_EVALUATION_TOO_LONG,
true);
}
private void internalBlockSelectionTimeoutSimulation(
final boolean isPoa,
final boolean preProcessingTooLate,
final boolean processingTooLate,
final boolean postProcessingTooLate,
final long longProcessingTxTime,
final TransactionSelectionResult longProcessingTxResult,
final boolean isLongProcessingTxDropped) {
final long fastProcessingTxTime = 200;
final Supplier<Answer<TransactionSelectionResult>> inTime = () -> invocation -> SELECTED;
final BiFunction<Transaction, Long, Answer<TransactionSelectionResult>> tooLate = final BiFunction<Transaction, Long, Answer<TransactionSelectionResult>> tooLate =
(p, t) -> (p, t) ->
invocation -> { invocation -> {
if (((PendingTransaction) invocation.getArgument(0)).getTransaction().equals(p)) { final org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction ptx =
invocation.getArgument(0);
if (ptx.getTransaction().equals(p)) {
Thread.sleep(t); Thread.sleep(t);
} else {
Thread.sleep(fastProcessingTxTime);
} }
return TransactionSelectionResult.SELECTED; return SELECTED;
}; };
final ProcessableBlockHeader blockHeader = createBlock(301_000); final ProcessableBlockHeader blockHeader = createBlock(301_000);
final Address miningBeneficiary = AddressHelpers.ofValue(1); final Address miningBeneficiary = AddressHelpers.ofValue(1);
final int poaMinBlockTime = 1; final int poaMinBlockTime = 1;
final long blockTxsSelectionMaxTime = 750; final long blockTxsSelectionMaxTime = 750;
final long longProcessingTxTime = 500;
final List<Transaction> transactionsToInject = new ArrayList<>(3); final List<Transaction> transactionsToInject = new ArrayList<>(3);
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
final Transaction tx = createTransaction(i, Wei.of(7), 100_000); final Transaction tx = createTransaction(i, Wei.of(7), 100_000);
transactionsToInject.add(tx); transactionsToInject.add(tx);
ensureTransactionIsValid(tx); ensureTransactionIsValid(tx, 0, 0, processingTooLate ? fastProcessingTxTime : 0);
} }
final Transaction lateTx = createTransaction(2, Wei.of(7), 100_000); final Transaction lateTx = createTransaction(2, Wei.of(7), 100_000);
transactionsToInject.add(lateTx); transactionsToInject.add(lateTx);
ensureTransactionIsValid( ensureTransactionIsValid(lateTx, 0, 0, processingTooLate ? longProcessingTxTime : 0);
lateTx, 0, 0, processingTooLate ? blockTxsSelectionMaxTime + longProcessingTxTime : 0);
PluginTransactionSelector transactionSelector = mock(PluginTransactionSelector.class); PluginTransactionSelector transactionSelector = mock(PluginTransactionSelector.class);
when(transactionSelector.evaluateTransactionPreProcessing(any())) when(transactionSelector.evaluateTransactionPreProcessing(any()))
.thenAnswer( .thenAnswer(
preProcessingTooLate preProcessingTooLate ? tooLate.apply(lateTx, longProcessingTxTime) : inTime.get());
? inTime.get()
: tooLate.apply(lateTx, blockTxsSelectionMaxTime + longProcessingTxTime));
when(transactionSelector.evaluateTransactionPostProcessing(any(), any())) when(transactionSelector.evaluateTransactionPostProcessing(any(), any()))
.thenAnswer( .thenAnswer(
postProcessingTooLate postProcessingTooLate ? tooLate.apply(lateTx, longProcessingTxTime) : inTime.get());
? inTime.get()
: tooLate.apply(lateTx, blockTxsSelectionMaxTime + longProcessingTxTime));
final PluginTransactionSelectorFactory transactionSelectorFactory = final PluginTransactionSelectorFactory transactionSelectorFactory =
mock(PluginTransactionSelectorFactory.class); mock(PluginTransactionSelectorFactory.class);
@ -962,7 +1001,9 @@ public abstract class AbstractBlockTransactionSelectorTest {
// given enough time we can check the not selected tx // given enough time we can check the not selected tx
await().until(() -> !results.getNotSelectedTransactions().isEmpty()); await().until(() -> !results.getNotSelectedTransactions().isEmpty());
assertThat(results.getNotSelectedTransactions()) assertThat(results.getNotSelectedTransactions())
.containsOnly(entry(lateTx, TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT)); .containsOnly(entry(lateTx, longProcessingTxResult));
assertThat(transactionPool.getTransactionByHash(lateTx.getHash()).isEmpty())
.isEqualTo(isLongProcessingTxDropped ? true : false);
} }
private static Stream<Arguments> private static Stream<Arguments>
@ -985,7 +1026,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
final Wei blobGasPrice, final Wei blobGasPrice,
final PluginTransactionSelectorFactory transactionSelectorFactory) { final PluginTransactionSelectorFactory transactionSelectorFactory) {
transactionPool = createTransactionPool(miningParameters); transactionPool = createTransactionPool();
return createBlockSelector( return createBlockSelector(
miningParameters, miningParameters,

@ -20,7 +20,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
@ -62,11 +62,12 @@ public class LegacyFeeMarketBlockTransactionSelectorTest
} }
@Override @Override
protected TransactionPool createTransactionPool(final MiningParameters miningParameters) { protected TransactionPool createTransactionPool() {
final TransactionPoolConfiguration poolConf = final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder() ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(5) .txPoolMaxSize(5)
.txPoolLimitByAccountPercentage(Fraction.fromFloat(1f)) .txPoolLimitByAccountPercentage(Fraction.fromFloat(1f))
.minGasPrice(Wei.ONE)
.build(); .build();
final PendingTransactions pendingTransactions = final PendingTransactions pendingTransactions =
@ -86,7 +87,6 @@ public class LegacyFeeMarketBlockTransactionSelectorTest
protocolContext, protocolContext,
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
miningParameters,
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
poolConf, poolConf,
null); null);

@ -74,11 +74,12 @@ public class LondonFeeMarketBlockTransactionSelectorTest
} }
@Override @Override
protected TransactionPool createTransactionPool(final MiningParameters miningParameters) { protected TransactionPool createTransactionPool() {
final TransactionPoolConfiguration poolConf = final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder() ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(5) .txPoolMaxSize(5)
.txPoolLimitByAccountPercentage(Fraction.fromFloat(1f)) .txPoolLimitByAccountPercentage(Fraction.fromFloat(1f))
.minGasPrice(Wei.ONE)
.build(); .build();
final PendingTransactions pendingTransactions = final PendingTransactions pendingTransactions =
new BaseFeePendingTransactionsSorter( new BaseFeePendingTransactionsSorter(
@ -94,7 +95,6 @@ public class LondonFeeMarketBlockTransactionSelectorTest
protocolContext, protocolContext,
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
miningParameters,
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
poolConf, poolConf,
null); null);

@ -332,7 +332,6 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest {
executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolContext(),
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
mock(MiningParameters.class),
new TransactionPoolMetrics(metricsSystem), new TransactionPoolMetrics(metricsSystem),
poolConf, poolConf,
null); null);

@ -52,7 +52,7 @@ public class PoWMinerExecutorTest {
public void startingMiningWithoutCoinbaseThrowsException() { public void startingMiningWithoutCoinbaseThrowsException() {
final MiningParameters miningParameters = MiningParameters.newDefault(); final MiningParameters miningParameters = MiningParameters.newDefault();
final TransactionPool transactionPool = createTransactionPool(miningParameters); final TransactionPool transactionPool = createTransactionPool();
final PoWMinerExecutor executor = final PoWMinerExecutor executor =
new PoWMinerExecutor( new PoWMinerExecutor(
@ -73,7 +73,7 @@ public class PoWMinerExecutorTest {
public void settingCoinbaseToNullThrowsException() { public void settingCoinbaseToNullThrowsException() {
final MiningParameters miningParameters = MiningParameters.newDefault(); final MiningParameters miningParameters = MiningParameters.newDefault();
final TransactionPool transactionPool = createTransactionPool(miningParameters); final TransactionPool transactionPool = createTransactionPool();
final PoWMinerExecutor executor = final PoWMinerExecutor executor =
new PoWMinerExecutor( new PoWMinerExecutor(
@ -96,7 +96,7 @@ public class PoWMinerExecutorTest {
return blockHeader; return blockHeader;
} }
private TransactionPool createTransactionPool(final MiningParameters miningParameters) { private TransactionPool createTransactionPool() {
final TransactionPoolConfiguration poolConf = final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build(); ImmutableTransactionPoolConfiguration.builder().txPoolMaxSize(1).build();
final GasPricePendingTransactionsSorter pendingTransactions = final GasPricePendingTransactionsSorter pendingTransactions =
@ -116,7 +116,6 @@ public class PoWMinerExecutorTest {
mock(ProtocolContext.class), mock(ProtocolContext.class),
mock(TransactionBroadcaster.class), mock(TransactionBroadcaster.class),
ethContext, ethContext,
miningParameters,
new TransactionPoolMetrics(new NoOpMetricsSystem()), new TransactionPoolMetrics(new NoOpMetricsSystem()),
poolConf, poolConf,
null); null);

@ -206,8 +206,7 @@ public class TraceTransactionIntegrationTest {
assertThat(frame.getGasCost()).isEqualTo(OptionalLong.of(3L)); assertThat(frame.getGasCost()).isEqualTo(OptionalLong.of(3L));
assertThat(frame.getOpcode()).isEqualTo("PUSH1"); assertThat(frame.getOpcode()).isEqualTo("PUSH1");
assertThat(frame.getPc()).isEqualTo(2); assertThat(frame.getPc()).isEqualTo(2);
assertStackContainsExactly( assertStackContainsExactly(frame, "0x80");
frame, "0000000000000000000000000000000000000000000000000000000000000080");
assertMemoryContainsExactly(frame); assertMemoryContainsExactly(frame);
assertStorageContainsExactly(frame); assertStorageContainsExactly(frame);
@ -217,10 +216,7 @@ public class TraceTransactionIntegrationTest {
assertThat(frame.getGasCost()).isEqualTo(OptionalLong.of(12L)); assertThat(frame.getGasCost()).isEqualTo(OptionalLong.of(12L));
assertThat(frame.getOpcode()).isEqualTo("MSTORE"); assertThat(frame.getOpcode()).isEqualTo("MSTORE");
assertThat(frame.getPc()).isEqualTo(4); assertThat(frame.getPc()).isEqualTo(4);
assertStackContainsExactly( assertStackContainsExactly(frame, "80", "40");
frame,
"0000000000000000000000000000000000000000000000000000000000000080",
"0000000000000000000000000000000000000000000000000000000000000040");
assertMemoryContainsExactly( assertMemoryContainsExactly(
frame, frame,
"0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -251,8 +247,8 @@ public class TraceTransactionIntegrationTest {
private void assertStackContainsExactly( private void assertStackContainsExactly(
final TraceFrame frame, final String... stackEntriesAsHex) { final TraceFrame frame, final String... stackEntriesAsHex) {
assertThat(frame.getStack()).isPresent(); assertThat(frame.getStack()).isPresent();
final Bytes32[] stackEntries = final Bytes[] stackEntries =
Stream.of(stackEntriesAsHex).map(Bytes32::fromHexString).toArray(Bytes32[]::new); Stream.of(stackEntriesAsHex).map(Bytes::fromHexString).toArray(Bytes[]::new);
assertThat(frame.getStack().get()).containsExactly(stackEntries); assertThat(frame.getStack().get()).containsExactly(stackEntries);
} }

@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.bonsai.cache.CachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.bonsai.cache.CachedWorldStorageManager; import org.hyperledger.besu.ethereum.bonsai.cache.CachedWorldStorageManager;
import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogManager;
import org.hyperledger.besu.ethereum.bonsai.trielog.TrieLogPruner;
import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
@ -74,14 +75,19 @@ public class BonsaiWorldStateProvider implements WorldStateArchive {
final CachedMerkleTrieLoader cachedMerkleTrieLoader, final CachedMerkleTrieLoader cachedMerkleTrieLoader,
final ObservableMetricsSystem metricsSystem, final ObservableMetricsSystem metricsSystem,
final BesuContext pluginContext, final BesuContext pluginContext,
final EvmConfiguration evmConfiguration) { final EvmConfiguration evmConfiguration,
final TrieLogPruner trieLogPruner) {
this.cachedWorldStorageManager = this.cachedWorldStorageManager =
new CachedWorldStorageManager(this, worldStateStorage, metricsSystem); new CachedWorldStorageManager(this, worldStateStorage, metricsSystem);
// TODO: de-dup constructors // TODO: de-dup constructors
this.trieLogManager = this.trieLogManager =
new TrieLogManager( new TrieLogManager(
blockchain, worldStateStorage, maxLayersToLoad.orElse(RETAINED_LAYERS), pluginContext); blockchain,
worldStateStorage,
maxLayersToLoad.orElse(RETAINED_LAYERS),
pluginContext,
trieLogPruner);
this.blockchain = blockchain; this.blockchain = blockchain;
this.worldStateStorage = worldStateStorage; this.worldStateStorage = worldStateStorage;
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; this.cachedMerkleTrieLoader = cachedMerkleTrieLoader;

@ -47,6 +47,7 @@ import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
@ -203,6 +204,10 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoC
return trieLogStorage.get(blockHash.toArrayUnsafe()); return trieLogStorage.get(blockHash.toArrayUnsafe());
} }
public Stream<byte[]> streamTrieLogKeys(final int limit) {
return trieLogStorage.streamKeys().limit(limit);
}
public Optional<Bytes> getStateTrieNode(final Bytes location) { public Optional<Bytes> getStateTrieNode(final Bytes location) {
return composedWorldStateStorage return composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, location.toArrayUnsafe()) .get(TRIE_BRANCH_STORAGE, location.toArrayUnsafe())
@ -335,6 +340,15 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoC
throw new RuntimeException("Bonsai Tries do not work with pruning."); throw new RuntimeException("Bonsai Tries do not work with pruning.");
} }
public boolean pruneTrieLog(final Hash blockHash) {
try {
return trieLogStorage.tryDelete(blockHash.toArrayUnsafe());
} catch (Exception e) {
LOG.error("Error pruning trie log for block hash {}", blockHash, e);
return false;
}
}
@Override @Override
public long addNodeAddedListener(final NodesAddedListener listener) { public long addNodeAddedListener(final NodesAddedListener listener) {
throw new RuntimeException("addNodeAddedListener not available"); throw new RuntimeException("addNodeAddedListener not available");

@ -47,16 +47,19 @@ public class TrieLogManager {
protected final Subscribers<TrieLogEvent.TrieLogObserver> trieLogObservers = Subscribers.create(); protected final Subscribers<TrieLogEvent.TrieLogObserver> trieLogObservers = Subscribers.create();
protected final TrieLogFactory trieLogFactory; protected final TrieLogFactory trieLogFactory;
private final TrieLogPruner trieLogPruner;
public TrieLogManager( public TrieLogManager(
final Blockchain blockchain, final Blockchain blockchain,
final BonsaiWorldStateKeyValueStorage worldStateStorage, final BonsaiWorldStateKeyValueStorage worldStateStorage,
final long maxLayersToLoad, final long maxLayersToLoad,
final BesuContext pluginContext) { final BesuContext pluginContext,
final TrieLogPruner trieLogPruner) {
this.blockchain = blockchain; this.blockchain = blockchain;
this.rootWorldStateStorage = worldStateStorage; this.rootWorldStateStorage = worldStateStorage;
this.maxLayersToLoad = maxLayersToLoad; this.maxLayersToLoad = maxLayersToLoad;
this.trieLogFactory = setupTrieLogFactory(pluginContext); this.trieLogFactory = setupTrieLogFactory(pluginContext);
this.trieLogPruner = trieLogPruner;
} }
public synchronized void saveTrieLog( public synchronized void saveTrieLog(
@ -82,6 +85,8 @@ public class TrieLogManager {
} finally { } finally {
if (success) { if (success) {
stateUpdater.commit(); stateUpdater.commit();
trieLogPruner.addToPruneQueue(forBlockHeader.getNumber(), forBlockHeader.getBlockHash());
trieLogPruner.pruneFromQueue();
} else { } else {
stateUpdater.rollback(); stateUpdater.rollback();
} }

@ -0,0 +1,194 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.bonsai.trielog;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;
import org.apache.tuweni.bytes.Bytes32;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TrieLogPruner {
private static final Logger LOG = LoggerFactory.getLogger(TrieLogPruner.class);
private final int pruningLimit;
private final int loadingLimit;
private final BonsaiWorldStateKeyValueStorage rootWorldStateStorage;
private final Blockchain blockchain;
private final long numBlocksToRetain;
private final boolean requireFinalizedBlock;
private final Multimap<Long, Hash> trieLogBlocksAndForksByDescendingBlockNumber =
TreeMultimap.create(Comparator.reverseOrder(), Comparator.naturalOrder());
public TrieLogPruner(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final Blockchain blockchain,
final long numBlocksToRetain,
final int pruningLimit,
final boolean requireFinalizedBlock) {
this.rootWorldStateStorage = rootWorldStateStorage;
this.blockchain = blockchain;
this.numBlocksToRetain = numBlocksToRetain;
this.pruningLimit = pruningLimit;
this.loadingLimit = pruningLimit; // same as pruningLimit for now
this.requireFinalizedBlock = requireFinalizedBlock;
}
public void initialize() {
preloadQueue();
}
private void preloadQueue() {
LOG.atInfo()
.setMessage("Loading first {} trie logs from database...")
.addArgument(loadingLimit)
.log();
try (final Stream<byte[]> trieLogKeys = rootWorldStateStorage.streamTrieLogKeys(loadingLimit)) {
final AtomicLong count = new AtomicLong();
trieLogKeys.forEach(
blockHashAsBytes -> {
final Hash blockHash = Hash.wrap(Bytes32.wrap(blockHashAsBytes));
final Optional<BlockHeader> header = blockchain.getBlockHeader(blockHash);
if (header.isPresent()) {
trieLogBlocksAndForksByDescendingBlockNumber.put(header.get().getNumber(), blockHash);
count.getAndIncrement();
} else {
// prune orphaned blocks (sometimes created during block production)
rootWorldStateStorage.pruneTrieLog(blockHash);
}
});
LOG.atInfo().log("Loaded {} trie logs from database", count);
pruneFromQueue();
} catch (Exception e) {
LOG.error("Error loading trie logs from database, nothing pruned", e);
}
}
void addToPruneQueue(final long blockNumber, final Hash blockHash) {
LOG.atTrace()
.setMessage("adding trie log to queue for later pruning blockNumber {}; blockHash {}")
.addArgument(blockNumber)
.addArgument(blockHash)
.log();
trieLogBlocksAndForksByDescendingBlockNumber.put(blockNumber, blockHash);
}
int pruneFromQueue() {
final long retainAboveThisBlock = blockchain.getChainHeadBlockNumber() - numBlocksToRetain;
final Optional<Hash> finalized = blockchain.getFinalized();
if (requireFinalizedBlock && finalized.isEmpty()) {
LOG.debug("No finalized block present, skipping pruning");
return 0;
}
final long retainAboveThisBlockOrFinalized =
finalized
.flatMap(blockchain::getBlockHeader)
.map(ProcessableBlockHeader::getNumber)
.map(finalizedBlock -> Math.min(finalizedBlock, retainAboveThisBlock))
.orElse(retainAboveThisBlock);
LOG.atTrace()
.setMessage(
"min((chainHeadNumber: {} - numBlocksToRetain: {}) = {}, finalized: {})) = retainAboveThisBlockOrFinalized: {}")
.addArgument(blockchain::getChainHeadBlockNumber)
.addArgument(numBlocksToRetain)
.addArgument(retainAboveThisBlock)
.addArgument(
() ->
finalized
.flatMap(blockchain::getBlockHeader)
.map(ProcessableBlockHeader::getNumber)
.orElse(null))
.addArgument(retainAboveThisBlockOrFinalized)
.log();
final var pruneWindowEntries =
trieLogBlocksAndForksByDescendingBlockNumber.asMap().entrySet().stream()
.dropWhile((e) -> e.getKey() > retainAboveThisBlockOrFinalized)
.limit(pruningLimit);
final Multimap<Long, Hash> wasPruned = ArrayListMultimap.create();
pruneWindowEntries.forEach(
(e) -> {
for (Hash blockHash : e.getValue()) {
if (rootWorldStateStorage.pruneTrieLog(blockHash)) {
wasPruned.put(e.getKey(), blockHash);
}
}
});
wasPruned.keySet().forEach(trieLogBlocksAndForksByDescendingBlockNumber::removeAll);
LOG.atTrace()
.setMessage("pruned {} trie logs for blocks {}")
.addArgument(wasPruned::size)
.addArgument(wasPruned)
.log();
LOG.atDebug()
.setMessage("pruned {} trie logs from {} blocks")
.addArgument(wasPruned::size)
.addArgument(() -> wasPruned.keySet().size())
.log();
return wasPruned.size();
}
public static TrieLogPruner noOpTrieLogPruner() {
return new NoOpTrieLogPruner(null, null, 0, 0);
}
public static class NoOpTrieLogPruner extends TrieLogPruner {
private NoOpTrieLogPruner(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final Blockchain blockchain,
final long numBlocksToRetain,
final int pruningLimit) {
super(rootWorldStateStorage, blockchain, numBlocksToRetain, pruningLimit, true);
}
@Override
public void initialize() {
// no-op
}
@Override
void addToPruneQueue(final long blockNumber, final Hash blockHash) {
// no-op
}
@Override
int pruneFromQueue() {
// no-op
return -1;
}
}
}

@ -148,6 +148,15 @@ public interface Blockchain {
*/ */
Optional<BlockHeader> getBlockHeader(Hash blockHeaderHash); Optional<BlockHeader> getBlockHeader(Hash blockHeaderHash);
/**
* Safe version of {@code getBlockHeader} (it should take any locks necessary to ensure any block
* updates that might be taking place have been completed first)
*
* @param blockHeaderHash The hash of the block whose header we want to retrieve.
* @return The block header corresponding to this block hash.
*/
Optional<BlockHeader> getBlockHeaderSafe(Hash blockHeaderHash);
/** /**
* Returns the block body corresponding to the given block header hash. Associated block is not * Returns the block body corresponding to the given block header hash. Associated block is not
* necessarily on the canonical chain. * necessarily on the canonical chain.

@ -302,6 +302,16 @@ public class DefaultBlockchain implements MutableBlockchain {
.orElseGet(() -> blockchainStorage.getBlockHeader(blockHeaderHash)); .orElseGet(() -> blockchainStorage.getBlockHeader(blockHeaderHash));
} }
@Override
public synchronized Optional<BlockHeader> getBlockHeaderSafe(final Hash blockHeaderHash) {
return blockHeadersCache
.map(
cache ->
Optional.ofNullable(cache.getIfPresent(blockHeaderHash))
.or(() -> blockchainStorage.getBlockHeader(blockHeaderHash)))
.orElseGet(() -> blockchainStorage.getBlockHeader(blockHeaderHash));
}
@Override @Override
public Optional<BlockBody> getBlockBody(final Hash blockHeaderHash) { public Optional<BlockBody> getBlockBody(final Hash blockHeaderHash) {
return blockBodiesCache return blockBodiesCache

@ -1096,6 +1096,26 @@ public class Transaction
protected List<VersionedHash> versionedHashes = null; protected List<VersionedHash> versionedHashes = null;
private BlobsWithCommitments blobsWithCommitments; private BlobsWithCommitments blobsWithCommitments;
public Builder copiedFrom(final Transaction toCopy) {
this.transactionType = toCopy.transactionType;
this.nonce = toCopy.nonce;
this.gasPrice = toCopy.gasPrice.orElse(null);
this.maxPriorityFeePerGas = toCopy.maxPriorityFeePerGas.orElse(null);
this.maxFeePerGas = toCopy.maxFeePerGas.orElse(null);
this.maxFeePerBlobGas = toCopy.maxFeePerBlobGas.orElse(null);
this.gasLimit = toCopy.gasLimit;
this.to = toCopy.to;
this.value = toCopy.value;
this.signature = toCopy.signature;
this.payload = toCopy.payload;
this.accessList = toCopy.maybeAccessList;
this.sender = toCopy.sender;
this.chainId = toCopy.chainId;
this.versionedHashes = toCopy.versionedHashes.orElse(null);
this.blobsWithCommitments = toCopy.blobsWithCommitments.orElse(null);
return this;
}
public Builder type(final TransactionType transactionType) { public Builder type(final TransactionType transactionType) {
this.transactionType = transactionType; this.transactionType = transactionType;
return this; return this;
@ -1260,5 +1280,10 @@ public class Transaction
new BlobsWithCommitments(kzgCommitments, blobs, kzgProofs, versionedHashes); new BlobsWithCommitments(kzgCommitments, blobs, kzgProofs, versionedHashes);
return this; return this;
} }
public Builder blobsWithCommitments(final BlobsWithCommitments blobsWithCommitments) {
this.blobsWithCommitments = blobsWithCommitments;
return this;
}
} }
} }

@ -30,6 +30,10 @@ import java.util.List;
*/ */
public class BlobPooledTransactionDecoder { public class BlobPooledTransactionDecoder {
private BlobPooledTransactionDecoder() {
// no instances
}
/** /**
* Decodes a blob transaction from the provided RLP input. * Decodes a blob transaction from the provided RLP input.
* *
@ -44,7 +48,6 @@ public class BlobPooledTransactionDecoder {
List<KZGCommitment> commitments = input.readList(KZGCommitment::readFrom); List<KZGCommitment> commitments = input.readList(KZGCommitment::readFrom);
List<KZGProof> proofs = input.readList(KZGProof::readFrom); List<KZGProof> proofs = input.readList(KZGProof::readFrom);
input.leaveList(); input.leaveList();
builder.kzgBlobs(commitments, blobs, proofs); return builder.kzgBlobs(commitments, blobs, proofs).build();
return builder.build();
} }
} }

@ -28,7 +28,6 @@ import java.util.OptionalLong;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
public class TraceFrame { public class TraceFrame {
@ -44,7 +43,7 @@ public class TraceFrame {
private final Wei value; private final Wei value;
private final Bytes inputData; private final Bytes inputData;
private final Bytes outputData; private final Bytes outputData;
private final Optional<Bytes32[]> stack; private final Optional<Bytes[]> stack;
private final Optional<Bytes[]> memory; private final Optional<Bytes[]> memory;
private final Optional<Map<UInt256, UInt256>> storage; private final Optional<Map<UInt256, UInt256>> storage;
@ -53,7 +52,7 @@ public class TraceFrame {
private final Optional<Map<Address, Wei>> maybeRefunds; private final Optional<Map<Address, Wei>> maybeRefunds;
private final Optional<Code> maybeCode; private final Optional<Code> maybeCode;
private final int stackItemsProduced; private final int stackItemsProduced;
private final Optional<Bytes32[]> stackPostExecution; private final Optional<Bytes[]> stackPostExecution;
private long gasRemainingPostExecution; private long gasRemainingPostExecution;
private final boolean virtualOperation; private final boolean virtualOperation;
@ -73,7 +72,7 @@ public class TraceFrame {
final Wei value, final Wei value,
final Bytes inputData, final Bytes inputData,
final Bytes outputData, final Bytes outputData,
final Optional<Bytes32[]> stack, final Optional<Bytes[]> stack,
final Optional<Bytes[]> memory, final Optional<Bytes[]> memory,
final Optional<Map<UInt256, UInt256>> storage, final Optional<Map<UInt256, UInt256>> storage,
final WorldUpdater worldUpdater, final WorldUpdater worldUpdater,
@ -81,7 +80,7 @@ public class TraceFrame {
final Optional<Map<Address, Wei>> maybeRefunds, final Optional<Map<Address, Wei>> maybeRefunds,
final Optional<Code> maybeCode, final Optional<Code> maybeCode,
final int stackItemsProduced, final int stackItemsProduced,
final Optional<Bytes32[]> stackPostExecution, final Optional<Bytes[]> stackPostExecution,
final boolean virtualOperation, final boolean virtualOperation,
final Optional<MemoryEntry> maybeUpdatedMemory, final Optional<MemoryEntry> maybeUpdatedMemory,
final Optional<StorageEntry> maybeUpdatedStorage) { final Optional<StorageEntry> maybeUpdatedStorage) {
@ -159,7 +158,7 @@ public class TraceFrame {
return outputData; return outputData;
} }
public Optional<Bytes32[]> getStack() { public Optional<Bytes[]> getStack() {
return stack; return stack;
} }
@ -206,7 +205,7 @@ public class TraceFrame {
return stackItemsProduced; return stackItemsProduced;
} }
public Optional<Bytes32[]> getStackPostExecution() { public Optional<Bytes[]> getStackPostExecution() {
return stackPostExecution; return stackPostExecution;
} }

@ -23,7 +23,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Responsible for ensuring the timestamp of a block is not more than "acceptableClockDriftSeconds' * Responsible for ensuring the timestamp of a block is not more than "acceptableClockDriftSeconds"
* into the future. * into the future.
*/ */
public class TimestampBoundedByFutureParameter implements DetachedBlockHeaderValidationRule { public class TimestampBoundedByFutureParameter implements DetachedBlockHeaderValidationRule {

@ -39,7 +39,6 @@ public enum TransactionInvalidReason {
MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS, MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS,
INITCODE_TOO_LARGE, INITCODE_TOO_LARGE,
NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER, NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER,
LOWER_NONCE_INVALID_TRANSACTION_EXISTS,
TOTAL_BLOB_GAS_TOO_HIGH, TOTAL_BLOB_GAS_TOO_HIGH,
GAS_PRICE_TOO_LOW, GAS_PRICE_TOO_LOW,
GAS_PRICE_BELOW_CURRENT_BASE_FEE, GAS_PRICE_BELOW_CURRENT_BASE_FEE,

@ -14,8 +14,6 @@
*/ */
package org.hyperledger.besu.ethereum.vm; package org.hyperledger.besu.ethereum.vm;
import static org.apache.tuweni.bytes.Bytes32.leftPad;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.debug.TraceFrame; import org.hyperledger.besu.ethereum.debug.TraceFrame;
@ -36,7 +34,6 @@ import java.util.OptionalLong;
import java.util.TreeMap; import java.util.TreeMap;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
public class DebugOperationTracer implements OperationTracer { public class DebugOperationTracer implements OperationTracer {
@ -45,7 +42,7 @@ public class DebugOperationTracer implements OperationTracer {
private List<TraceFrame> traceFrames = new ArrayList<>(); private List<TraceFrame> traceFrames = new ArrayList<>();
private TraceFrame lastFrame; private TraceFrame lastFrame;
private Optional<Bytes32[]> preExecutionStack; private Optional<Bytes[]> preExecutionStack;
private long gasRemaining; private long gasRemaining;
private Bytes inputData; private Bytes inputData;
private int pc; private int pc;
@ -73,7 +70,7 @@ public class DebugOperationTracer implements OperationTracer {
final WorldUpdater worldUpdater = frame.getWorldUpdater(); final WorldUpdater worldUpdater = frame.getWorldUpdater();
final Bytes outputData = frame.getOutputData(); final Bytes outputData = frame.getOutputData();
final Optional<Bytes[]> memory = captureMemory(frame); final Optional<Bytes[]> memory = captureMemory(frame);
final Optional<Bytes32[]> stackPostExecution = captureStack(frame); final Optional<Bytes[]> stackPostExecution = captureStack(frame);
if (lastFrame != null) { if (lastFrame != null) {
lastFrame.setGasRemainingPostExecution(gasRemaining); lastFrame.setGasRemainingPostExecution(gasRemaining);
@ -218,15 +215,15 @@ public class DebugOperationTracer implements OperationTracer {
return Optional.of(memoryContents); return Optional.of(memoryContents);
} }
private Optional<Bytes32[]> captureStack(final MessageFrame frame) { private Optional<Bytes[]> captureStack(final MessageFrame frame) {
if (!options.isStackEnabled()) { if (!options.isStackEnabled()) {
return Optional.empty(); return Optional.empty();
} }
final Bytes32[] stackContents = new Bytes32[frame.stackSize()]; final Bytes[] stackContents = new Bytes[frame.stackSize()];
for (int i = 0; i < stackContents.length; i++) { for (int i = 0; i < stackContents.length; i++) {
// Record stack contents in reverse // Record stack contents in reverse
stackContents[i] = leftPad(frame.getStackItem(stackContents.length - i - 1)); stackContents[i] = frame.getStackItem(stackContents.length - i - 1);
} }
return Optional.of(stackContents); return Optional.of(stackContents);
} }

@ -19,6 +19,7 @@ package org.hyperledger.besu.ethereum.worldstate;
import org.immutables.value.Value; import org.immutables.value.Value;
@Value.Immutable @Value.Immutable
@Value.Enclosing
public interface DataStorageConfiguration { public interface DataStorageConfiguration {
long DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD = 512; long DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD = 512;
@ -27,9 +28,42 @@ public interface DataStorageConfiguration {
ImmutableDataStorageConfiguration.builder() ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(DataStorageFormat.FOREST) .dataStorageFormat(DataStorageFormat.FOREST)
.bonsaiMaxLayersToLoad(DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD) .bonsaiMaxLayersToLoad(DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD)
.unstable(Unstable.DEFAULT)
.build(); .build();
DataStorageFormat getDataStorageFormat(); DataStorageFormat getDataStorageFormat();
Long getBonsaiMaxLayersToLoad(); Long getBonsaiMaxLayersToLoad();
@Value.Default
default Unstable getUnstable() {
return Unstable.DEFAULT;
}
@Value.Immutable
interface Unstable {
boolean DEFAULT_BONSAI_TRIE_LOG_PRUNING_ENABLED = false;
long DEFAULT_BONSAI_TRIE_LOG_RETENTION_THRESHOLD = 512L;
long MINIMUM_BONSAI_TRIE_LOG_RETENTION_THRESHOLD = DEFAULT_BONSAI_TRIE_LOG_RETENTION_THRESHOLD;
int DEFAULT_BONSAI_TRIE_LOG_PRUNING_LIMIT = 30_000;
DataStorageConfiguration.Unstable DEFAULT =
ImmutableDataStorageConfiguration.Unstable.builder().build();
@Value.Default
default boolean getBonsaiTrieLogPruningEnabled() {
return DEFAULT_BONSAI_TRIE_LOG_PRUNING_ENABLED;
}
@Value.Default
default long getBonsaiTrieLogRetentionThreshold() {
return DEFAULT_BONSAI_TRIE_LOG_RETENTION_THRESHOLD;
}
@Value.Default
default int getBonsaiTrieLogPruningLimit() {
return DEFAULT_BONSAI_TRIE_LOG_PRUNING_LIMIT;
}
}
} }

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

Loading…
Cancel
Save