Release 23.7.3-RC2 - Holesky Hotfix (#5938)

* Revert "Burn in candidate for 23.7.3 (#5906)"

This reverts commit ed9d80e10e.

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

* Update holesky with fixed extraData, genesis time, shanghaiTime (#5890)

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

* 23.7.3-RC2 version bump and 23.7.2 release SHAs
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* updated gradle verification metadata (#5870)

* removed old artefacts

* works with compileTestJava

* restored metadata needed for codeQL and trusted-artifacts block for javadoc/sources

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

---------

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

* Add rocksdbjni-8.0.0 gradle verification back in

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

---------

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
release-23.7.x
Simon Dudley 1 year ago committed by GitHub
parent ed9d80e10e
commit 7cb1dda986
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .github/workflows/checks.yml
  2. 2
      .github/workflows/codeql.yml
  3. 2
      .github/workflows/dco-merge-group.yml
  4. 2
      .github/workflows/dco.yml
  5. 2
      .github/workflows/gradle-wrapper-validation.yml
  6. 2
      .github/workflows/pr-checklist-on-open.yml
  7. 2
      .github/workflows/release.yml
  8. 2
      .github/workflows/repolinter.yml
  9. 15
      CHANGELOG.md
  10. 2
      README.md
  11. 130
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  12. 15
      besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java
  13. 4
      besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java
  14. 2
      besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java
  15. 44
      besu/src/main/java/org/hyperledger/besu/cli/converter/DurationMillisConverter.java
  16. 6
      besu/src/main/java/org/hyperledger/besu/cli/converter/FractionConverter.java
  17. 6
      besu/src/main/java/org/hyperledger/besu/cli/converter/PercentageConverter.java
  18. 39
      besu/src/main/java/org/hyperledger/besu/cli/converter/exception/DurationConversionException.java
  19. 45
      besu/src/main/java/org/hyperledger/besu/cli/options/OptionParser.java
  20. 263
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptions.java
  21. 122
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptions.java
  22. 2
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java
  23. 104
      besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java
  24. 6
      besu/src/main/java/org/hyperledger/besu/cli/util/TomlConfigFileDefaultProvider.java
  25. 24
      besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java
  26. 24
      besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
  27. 91
      besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java
  28. 11
      besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java
  29. 209
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  30. 7
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  31. 22
      besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java
  32. 2
      besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java
  33. 5
      besu/src/test/java/org/hyperledger/besu/cli/converter/FractionConverterTest.java
  34. 5
      besu/src/test/java/org/hyperledger/besu/cli/converter/PercentageConverterTest.java
  35. 27
      besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java
  36. 9
      besu/src/test/java/org/hyperledger/besu/cli/options/EthProtocolOptionsTest.java
  37. 9
      besu/src/test/java/org/hyperledger/besu/cli/options/MetricsCLIOptionsTest.java
  38. 8
      besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java
  39. 21
      besu/src/test/java/org/hyperledger/besu/cli/options/OptionParserTest.java
  40. 8
      besu/src/test/java/org/hyperledger/besu/cli/options/SynchronizerOptionsTest.java
  41. 155
      besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java
  42. 243
      besu/src/test/java/org/hyperledger/besu/cli/options/stable/TransactionPoolOptionsTest.java
  43. 105
      besu/src/test/java/org/hyperledger/besu/cli/options/unstable/TransactionPoolOptionsTest.java
  44. 11
      besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java
  45. 11
      besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java
  46. 11
      besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java
  47. 19
      besu/src/test/java/org/hyperledger/besu/ethereum/p2p/config/DefaultDiscoveryConfiguration.java
  48. 211
      besu/src/test/java/org/hyperledger/besu/services/TraceServiceImplTest.java
  49. 13
      besu/src/test/resources/everything_config.toml
  50. 22
      build.gradle
  51. 815
      config/src/main/resources/kotti.json
  52. 1
      consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java
  53. 12
      consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java
  54. 1
      consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java
  55. 7
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java
  56. 7
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifier.java
  57. 3
      consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java
  58. 93
      consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/PayloadIdentifierTest.java
  59. 22
      datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java
  60. 8
      datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java
  61. 57
      datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java
  62. 11
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/DefaultAuthenticationService.java
  63. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TraceBlock.java
  64. 9
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java
  65. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java
  66. 6
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java
  67. 13
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java
  68. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java
  69. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java
  70. 3
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java
  71. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java
  72. 14
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java
  73. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java
  74. 55
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java
  75. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java
  76. 16
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java
  77. 3
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java
  78. 3
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java
  79. 12
      ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/EntriesFromIntegrationTest.java
  80. 2
      ethereum/core/src/jmh/java/org/hyperledger/besu/ethereum/vm/operations/TransientStorageOperationBenchmark.java
  81. 31
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiAccount.java
  82. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateProvider.java
  83. 68
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiPreImageProxy.java
  84. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/BonsaiWorldStateKeyValueStorage.java
  85. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/storage/flat/FlatDbReaderStrategy.java
  86. 78
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java
  87. 158
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java
  88. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java
  89. 48
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
  90. 74
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionDecoder.java
  91. 109
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AccessListTransactionEncoder.java
  92. 50
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionDecoder.java
  93. 47
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobPooledTransactionEncoder.java
  94. 45
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java
  95. 35
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java
  96. 74
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionDecoder.java
  97. 41
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EIP1559TransactionEncoder.java
  98. 41
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EncodingContext.java
  99. 76
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionDecoder.java
  100. 36
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/FrontierTransactionEncoder.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -7,7 +7,7 @@ on:
jobs: jobs:
spotless: spotless:
runs-on: [besu-research-ubuntu-16] runs-on: [besu,Linux,self-hosted,X64,nodocker]
if: ${{ github.actor != 'dependabot[bot]' }} if: ${{ github.actor != 'dependabot[bot]' }}
steps: steps:
- name: Checkout Repo - name: Checkout Repo
@ -21,7 +21,7 @@ jobs:
- name: spotless - name: spotless
run: ./gradlew --no-daemon --parallel clean spotlessCheck run: ./gradlew --no-daemon --parallel clean spotlessCheck
javadoc_17: javadoc_17:
runs-on: [besu-research-ubuntu-8] runs-on: [besu,Linux,self-hosted,X64,nodocker]
if: ${{ github.actor != 'dependabot[bot]' }} if: ${{ github.actor != 'dependabot[bot]' }}
steps: steps:
- name: Checkout Repo - name: Checkout Repo

@ -24,7 +24,7 @@ on:
jobs: jobs:
analyze: analyze:
name: Analyze name: Analyze
runs-on: [besu-research-ubuntu-16] runs-on: [besu,Linux,self-hosted,X64,nodocker]
permissions: permissions:
actions: read actions: read
contents: read contents: read

@ -4,7 +4,7 @@ on:
jobs: jobs:
dco: dco:
runs-on: [besu-research-ubuntu-8] runs-on: [besu,Linux,self-hosted,nodocker]
if: ${{ github.actor != 'dependabot[bot]' }} if: ${{ github.actor != 'dependabot[bot]' }}
steps: steps:
- run: echo "This DCO job runs on merge_queue event and doesn't check PR contents" - run: echo "This DCO job runs on merge_queue event and doesn't check PR contents"

@ -5,7 +5,7 @@ on:
jobs: jobs:
dco: dco:
runs-on: [besu-research-ubuntu-8] runs-on: [besu,Linux,self-hosted,nodocker]
if: ${{ github.actor != 'dependabot[bot]' }} if: ${{ github.actor != 'dependabot[bot]' }}
steps: steps:
- run: echo "This DCO job runs on pull_request event and workflow_dispatch" - run: echo "This DCO job runs on pull_request event and workflow_dispatch"

@ -5,7 +5,7 @@ on: [push, pull_request]
jobs: jobs:
validation: validation:
name: "Gradle Wrapper Validation" name: "Gradle Wrapper Validation"
runs-on: [besu-research-ubuntu-8] runs-on: [besu,Linux,self-hosted,nodocker]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1 - uses: gradle/wrapper-validation-action@v1

@ -6,7 +6,7 @@ on:
jobs: jobs:
checklist: checklist:
name: "add checklist as a comment on newly opened PRs" name: "add checklist as a comment on newly opened PRs"
runs-on: [besu-research-ubuntu-8] runs-on: [besu,Linux,self-hosted,nodocker]
steps: steps:
- uses: actions/github-script@v5 - uses: actions/github-script@v5
with: with:

@ -4,7 +4,7 @@ on:
types: released types: released
jobs: jobs:
dockerPromoteX64: dockerPromoteX64:
runs-on: [besu-research-ubuntu-16] runs-on: [besu,Linux,self-hosted,nodocker]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-java@v3 - uses: actions/setup-java@v3

@ -15,7 +15,7 @@ on:
jobs: jobs:
build: build:
runs-on: [besu-research-ubuntu-16] runs-on: [besu,Linux,self-hosted,X64,docker]
container: ghcr.io/todogroup/repolinter:v0.10.1 container: ghcr.io/todogroup/repolinter:v0.10.1
steps: steps:
- name: Checkout Code - name: Checkout Code

@ -2,21 +2,8 @@
## 23.7.3 ## 23.7.3
### Breaking Changes
- Removed support for Kotti network (ETC) [#5816](https://github.com/hyperledger/besu/pull/5816)
- Layered transaction pool implementation is now stable and enabled by default, so the following changes to experimental options have been done [#5772](https://github.com/hyperledger/besu):
- `--Xlayered-tx-pool` is gone, to select the implementation use the new `--tx-pool` option with values `layered` (default) or `legacy`
- `--Xlayered-tx-pool-layer-max-capacity`, `--Xlayered-tx-pool-max-prioritized` and `--Xlayered-tx-pool-max-future-by-sender` just drop the `X` and keep the same behavior
### Additions and Improvements ### Additions and Improvements
- Add access to an immutable world view to start/end transaction hooks in the tracing API[#5836](https://github.com/hyperledger/besu/pull/5836) - Update Holesky config for re-launch [#5890](https://github.com/hyperledger/besu/pull/5890)
- Layered transaction pool implementation is now stable and enabled by default. If you want still to use the legacy implementation, use `--tx-pool=legacy` [#5772](https://github.com/hyperledger/besu)
- Tune G1GC to reduce Besu memory footprint, and new `besu-untuned` start scripts to run without any specific G1GC flags [#5879](https://github.com/hyperledger/besu/pull/5879)
- Update Holešky config for re-launch [#5890](https://github.com/hyperledger/besu/pull/5890)
### Bug Fixes
- do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830)
- fix duplicate key errors in EthScheduler-Transactions [#5857](https://github.com/hyperledger/besu/pull/5857)
### Download Links ### Download Links

@ -28,7 +28,7 @@ If you have any questions, queries or comments, [Besu channel on Hyperledger Dis
## Besu Users ## Besu Users
To install the Besu binary, follow [these instructions](https://besu.hyperledger.org/public-networks/get-started/install/binary-distribution). To install the Besu binary, follow [these instructions](https://besu.hyperledger.org/HowTo/Get-Started/Install-Binaries/).
## Besu Developers ## Besu Developers

@ -46,6 +46,7 @@ import org.hyperledger.besu.chainimport.JsonBlockImporter;
import org.hyperledger.besu.chainimport.RlpBlockImporter; 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.config.NetworkName; import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.cli.converter.FractionConverter;
import org.hyperledger.besu.cli.converter.MetricCategoryConverter; import org.hyperledger.besu.cli.converter.MetricCategoryConverter;
import org.hyperledger.besu.cli.converter.PercentageConverter; import org.hyperledger.besu.cli.converter.PercentageConverter;
import org.hyperledger.besu.cli.custom.CorsAllowedOriginsProperty; import org.hyperledger.besu.cli.custom.CorsAllowedOriginsProperty;
@ -58,7 +59,6 @@ import org.hyperledger.besu.cli.options.stable.EthstatsOptions;
import org.hyperledger.besu.cli.options.stable.LoggingLevelOption; import org.hyperledger.besu.cli.options.stable.LoggingLevelOption;
import org.hyperledger.besu.cli.options.stable.NodePrivateKeyFileOption; import org.hyperledger.besu.cli.options.stable.NodePrivateKeyFileOption;
import org.hyperledger.besu.cli.options.stable.P2PTLSConfigOptions; import org.hyperledger.besu.cli.options.stable.P2PTLSConfigOptions;
import org.hyperledger.besu.cli.options.stable.TransactionPoolOptions;
import org.hyperledger.besu.cli.options.unstable.ChainPruningOptions; import org.hyperledger.besu.cli.options.unstable.ChainPruningOptions;
import org.hyperledger.besu.cli.options.unstable.DnsOptions; import org.hyperledger.besu.cli.options.unstable.DnsOptions;
import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions;
@ -73,6 +73,7 @@ import org.hyperledger.besu.cli.options.unstable.PkiBlockCreationOptions;
import org.hyperledger.besu.cli.options.unstable.PrivacyPluginOptions; import org.hyperledger.besu.cli.options.unstable.PrivacyPluginOptions;
import org.hyperledger.besu.cli.options.unstable.RPCOptions; import org.hyperledger.besu.cli.options.unstable.RPCOptions;
import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions; import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions;
import org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions;
import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner; import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner;
import org.hyperledger.besu.cli.presynctasks.PrivateDatabaseMigrationPreSyncTask; import org.hyperledger.besu.cli.presynctasks.PrivateDatabaseMigrationPreSyncTask;
import org.hyperledger.besu.cli.subcommands.PasswordSubCommand; import org.hyperledger.besu.cli.subcommands.PasswordSubCommand;
@ -126,7 +127,6 @@ import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.mainnet.FrontierTargetingGasLimitCalculator; import org.hyperledger.besu.ethereum.mainnet.FrontierTargetingGasLimitCalculator;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration; import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
@ -280,9 +280,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final SynchronizerOptions unstableSynchronizerOptions = SynchronizerOptions.create(); final SynchronizerOptions unstableSynchronizerOptions = SynchronizerOptions.create();
final EthProtocolOptions unstableEthProtocolOptions = EthProtocolOptions.create(); final EthProtocolOptions unstableEthProtocolOptions = EthProtocolOptions.create();
final MetricsCLIOptions unstableMetricsCLIOptions = MetricsCLIOptions.create(); final MetricsCLIOptions unstableMetricsCLIOptions = MetricsCLIOptions.create();
final org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions final TransactionPoolOptions unstableTransactionPoolOptions = TransactionPoolOptions.create();
unstableTransactionPoolOptions =
org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions.create();
private final DnsOptions unstableDnsOptions = DnsOptions.create(); private final DnsOptions unstableDnsOptions = DnsOptions.create();
private final MiningOptions unstableMiningOptions = MiningOptions.create(); private final MiningOptions unstableMiningOptions = MiningOptions.create();
private final NatOptions unstableNatOptions = NatOptions.create(); private final NatOptions unstableNatOptions = NatOptions.create();
@ -300,10 +298,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
NodePrivateKeyFileOption.create(); NodePrivateKeyFileOption.create();
private final LoggingLevelOption loggingLevelOption = LoggingLevelOption.create(); private final LoggingLevelOption loggingLevelOption = LoggingLevelOption.create();
@CommandLine.ArgGroup(validate = false, heading = "@|bold Tx Pool Common Options|@%n")
final org.hyperledger.besu.cli.options.stable.TransactionPoolOptions
stableTransactionPoolOptions = TransactionPoolOptions.create();
private final RunnerBuilder runnerBuilder; private final RunnerBuilder runnerBuilder;
private final BesuController.Builder controllerBuilderFactory; private final BesuController.Builder controllerBuilderFactory;
private final BesuPluginContextImpl besuPluginContext; private final BesuPluginContextImpl besuPluginContext;
@ -460,8 +454,10 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
"The maximum percentage of P2P connections that can be initiated remotely. Must be between 0 and 100 inclusive. (default: ${DEFAULT-VALUE})", "The maximum percentage of P2P connections that can be initiated remotely. Must be between 0 and 100 inclusive. (default: ${DEFAULT-VALUE})",
arity = "1", arity = "1",
converter = PercentageConverter.class) converter = PercentageConverter.class)
private final Percentage maxRemoteConnectionsPercentage = private final Integer maxRemoteConnectionsPercentage =
Fraction.fromFloat(DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED).toPercentage(); Fraction.fromFloat(DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED)
.toPercentage()
.getValue();
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option( @CommandLine.Option(
@ -1115,6 +1111,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
arity = "1") arity = "1")
private final Wei minTransactionGasPrice = DEFAULT_MIN_TRANSACTION_GAS_PRICE; private final Wei minTransactionGasPrice = DEFAULT_MIN_TRANSACTION_GAS_PRICE;
@Option(
names = {"--rpc-tx-feecap"},
description =
"Maximum transaction fees (in Wei) accepted for transaction submitted through RPC (default: ${DEFAULT-VALUE})",
arity = "1")
private final Wei txFeeCap = DEFAULT_RPC_TX_FEE_CAP;
@Option( @Option(
names = {"--min-block-occupancy-ratio"}, names = {"--min-block-occupancy-ratio"},
description = "Minimum occupancy ratio for a mined block (default: ${DEFAULT-VALUE})", description = "Minimum occupancy ratio for a mined block (default: ${DEFAULT-VALUE})",
@ -1206,6 +1209,75 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
"Sets target gas limit per block. If set, each block's gas limit will approach this setting over time if the current gas limit is different.") "Sets target gas limit per block. If set, each block's gas limit will approach this setting over time if the current gas limit is different.")
private final Long targetGasLimit = null; private final Long targetGasLimit = null;
// Tx Pool Option Group
@CommandLine.ArgGroup(validate = false, heading = "@|bold Tx Pool Options|@%n")
TxPoolOptionGroup txPoolOptionGroup = new TxPoolOptionGroup();
static class TxPoolOptionGroup {
@CommandLine.Option(
names = {"--tx-pool-disable-locals"},
paramLabel = "<Boolean>",
description =
"Set to true if transactions sent via RPC should have the same checks and not be prioritized over remote ones (default: ${DEFAULT-VALUE})",
fallbackValue = "true",
arity = "0..1")
private Boolean disableLocalTxs = TransactionPoolConfiguration.DEFAULT_DISABLE_LOCAL_TXS;
@CommandLine.Option(
names = {"--tx-pool-enable-save-restore"},
paramLabel = "<Boolean>",
description =
"Set to true to enable saving the txpool content to file on shutdown and reloading it on startup (default: ${DEFAULT-VALUE})",
fallbackValue = "true",
arity = "0..1")
private Boolean saveRestoreEnabled = TransactionPoolConfiguration.DEFAULT_ENABLE_SAVE_RESTORE;
@CommandLine.Option(
names = {"--tx-pool-limit-by-account-percentage"},
paramLabel = "<DOUBLE>",
converter = FractionConverter.class,
description =
"Maximum portion of the transaction pool which a single account may occupy with future transactions (default: ${DEFAULT-VALUE})",
arity = "1")
private Float txPoolLimitByAccountPercentage =
TransactionPoolConfiguration.DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE;
@CommandLine.Option(
names = {"--tx-pool-save-file"},
paramLabel = "<STRING>",
description =
"If saving the txpool content is enabled, define a custom path for the save file (default: ${DEFAULT-VALUE} in the data-dir)",
arity = "1")
private File saveFile = TransactionPoolConfiguration.DEFAULT_SAVE_FILE;
@Option(
names = {"--tx-pool-max-size"},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description =
"Maximum number of pending transactions that will be kept in the transaction pool (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer txPoolMaxSize =
TransactionPoolConfiguration.DEFAULT_MAX_PENDING_TRANSACTIONS;
@Option(
names = {"--tx-pool-retention-hours"},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description =
"Maximum retention period of pending transactions in hours (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer pendingTxRetentionPeriod =
TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS;
@Option(
names = {"--tx-pool-price-bump"},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
converter = PercentageConverter.class,
description =
"Price bump percentage to replace an already existing transaction (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer priceBump = TransactionPoolConfiguration.DEFAULT_PRICE_BUMP.getValue();
}
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@Option( @Option(
names = {"--key-value-storage"}, names = {"--key-value-storage"},
@ -1834,15 +1906,10 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
validateRpcOptionsParams(); validateRpcOptionsParams();
validateChainDataPruningParams(); validateChainDataPruningParams();
validatePostMergeCheckpointBlockRequirements(); validatePostMergeCheckpointBlockRequirements();
validateTransactionPoolOptions();
p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine); p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine);
pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine); pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine);
} }
private void validateTransactionPoolOptions() {
stableTransactionPoolOptions.validate(commandLine);
}
private void validateRequiredOptions() { private void validateRequiredOptions() {
commandLine commandLine
.getCommandSpec() .getCommandSpec()
@ -2920,14 +2987,28 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
} }
private TransactionPoolConfiguration buildTransactionPoolConfiguration() { private TransactionPoolConfiguration buildTransactionPoolConfiguration() {
final var stableTxPoolOption = stableTransactionPoolOptions.toDomainObject(); return unstableTransactionPoolOptions
return ImmutableTransactionPoolConfiguration.builder() .toDomainObject()
.from(stableTxPoolOption) .enableSaveRestore(txPoolOptionGroup.saveRestoreEnabled)
.unstable(unstableTransactionPoolOptions.toDomainObject()) .disableLocalTransactions(txPoolOptionGroup.disableLocalTxs)
.saveFile((dataPath.resolve(stableTxPoolOption.getSaveFile().getPath()).toFile())) .txPoolLimitByAccountPercentage(txPoolOptionGroup.txPoolLimitByAccountPercentage)
.txPoolMaxSize(txPoolOptionGroup.txPoolMaxSize)
.pendingTxRetentionPeriod(txPoolOptionGroup.pendingTxRetentionPeriod)
.priceBump(Percentage.fromInt(txPoolOptionGroup.priceBump))
.txFeeCap(txFeeCap)
.saveFile(dataPath.resolve(txPoolOptionGroup.saveFile.getPath()).toFile())
.build(); .build();
} }
/**
* Return the file where to save txpool content if the relative option is enabled.
*
* @return the save file
*/
public File getSaveFile() {
return txPoolOptionGroup.saveFile;
}
private boolean isPruningEnabled() { private boolean isPruningEnabled() {
return pruningEnabled; return pruningEnabled;
} }
@ -3408,8 +3489,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
getActualGenesisConfigOptions().getTerminalTotalDifficulty().isPresent()); getActualGenesisConfigOptions().getTerminalTotalDifficulty().isPresent());
} }
/** Set ignorable segments in RocksDB Storage Provider plugin. */ private void setIgnorableStorageSegments() {
public void setIgnorableStorageSegments() {
if (!unstableChainPruningOptions.getChainDataPruningEnabled()) { if (!unstableChainPruningOptions.getChainDataPruningEnabled()) {
rocksDBPlugin.addIgnorableSegmentIdentifier(KeyValueSegmentIdentifier.CHAIN_PRUNER_STATE); rocksDBPlugin.addIgnorableSegmentIdentifier(KeyValueSegmentIdentifier.CHAIN_PRUNER_STATE);
} }
@ -3532,7 +3612,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
builder.setHighSpecEnabled(); builder.setHighSpecEnabled();
} }
builder.setTxPoolImplementation(buildTransactionPoolConfiguration().getTxPoolImplementation()); if (buildTransactionPoolConfiguration().getLayeredTxPoolEnabled()) {
builder.setLayeredTxPoolEnabled();
}
return builder.build(); return builder.build();
} }

@ -15,7 +15,6 @@
package org.hyperledger.besu.cli; package org.hyperledger.besu.cli;
import org.hyperledger.besu.BesuInfo; import org.hyperledger.besu.BesuInfo;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.util.log.FramedLogMessage; import org.hyperledger.besu.util.log.FramedLogMessage;
import org.hyperledger.besu.util.platform.PlatformDetector; import org.hyperledger.besu.util.platform.PlatformDetector;
@ -48,7 +47,7 @@ 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 TransactionPoolConfiguration.Implementation txPoolImplementation; private boolean isLayeredTxPool = false;
private Map<String, String> environment; private Map<String, String> environment;
/** /**
@ -168,14 +167,12 @@ public class ConfigurationOverviewBuilder {
} }
/** /**
* Sets the txpool implementation in use. * Sets experimental layered txpool enabled.
* *
* @param implementation the txpool implementation
* @return the builder * @return the builder
*/ */
public ConfigurationOverviewBuilder setTxPoolImplementation( public ConfigurationOverviewBuilder setLayeredTxPoolEnabled() {
final TransactionPoolConfiguration.Implementation implementation) { isLayeredTxPool = true;
txPoolImplementation = implementation;
return this; return this;
} }
@ -254,7 +251,9 @@ public class ConfigurationOverviewBuilder {
lines.add("Experimental high spec configuration enabled"); lines.add("Experimental high spec configuration enabled");
} }
lines.add("Using " + txPoolImplementation + " transaction pool implementation"); if (isLayeredTxPool) {
lines.add("Experimental layered transaction pool configuration enabled");
}
lines.add(""); lines.add("");
lines.add("Host:"); lines.add("Host:");

@ -16,6 +16,7 @@ package org.hyperledger.besu.cli;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration; import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration;
import org.hyperledger.besu.nat.NatMethod; import org.hyperledger.besu.nat.NatMethod;
@ -60,6 +61,9 @@ public interface DefaultCommandValues {
String MANDATORY_NODE_ID_FORMAT_HELP = "<NODEID>"; String MANDATORY_NODE_ID_FORMAT_HELP = "<NODEID>";
/** The constant DEFAULT_MIN_TRANSACTION_GAS_PRICE. */ /** The constant DEFAULT_MIN_TRANSACTION_GAS_PRICE. */
Wei DEFAULT_MIN_TRANSACTION_GAS_PRICE = Wei.of(1000); Wei DEFAULT_MIN_TRANSACTION_GAS_PRICE = Wei.of(1000);
/** The constant DEFAULT_RPC_TX_FEE_CAP. */
Wei DEFAULT_RPC_TX_FEE_CAP = TransactionPoolConfiguration.DEFAULT_RPC_TX_FEE_CAP;
/** The constant DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO. */ /** The constant DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO. */
Double DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO = 0.8; Double DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO = 0.8;
/** The constant DEFAULT_EXTRA_DATA. */ /** The constant DEFAULT_EXTRA_DATA. */

@ -38,6 +38,8 @@ public enum NetworkName {
EXPERIMENTAL_EIPS("/experimental.json", BigInteger.valueOf(2023), false), EXPERIMENTAL_EIPS("/experimental.json", BigInteger.valueOf(2023), false),
/** Classic network name. */ /** Classic network name. */
CLASSIC("/classic.json", BigInteger.valueOf(1)), CLASSIC("/classic.json", BigInteger.valueOf(1)),
/** Kotti network name. */
KOTTI("/kotti.json", BigInteger.valueOf(6)),
/** Mordor network name. */ /** Mordor network name. */
MORDOR("/mordor.json", BigInteger.valueOf(7)); MORDOR("/mordor.json", BigInteger.valueOf(7));

@ -1,44 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.converter;
import org.hyperledger.besu.cli.converter.exception.DurationConversionException;
import java.time.Duration;
import picocli.CommandLine;
/** The Duration (milliseconds) Cli type converter. */
public class DurationMillisConverter
implements CommandLine.ITypeConverter<Duration>, TypeFormatter<Duration> {
@Override
public Duration convert(final String value) throws DurationConversionException {
try {
final long millis = Long.parseLong(value);
if (millis < 0) {
throw new DurationConversionException(millis);
}
return Duration.ofMillis(Long.parseLong(value));
} catch (NullPointerException | IllegalArgumentException e) {
throw new DurationConversionException(value);
}
}
@Override
public String format(final Duration value) {
return Long.toString(value.toMillis());
}
}

@ -20,12 +20,12 @@ import org.hyperledger.besu.util.number.Fraction;
import picocli.CommandLine; import picocli.CommandLine;
/** The Fraction converter to convert floats in CLI. */ /** The Fraction converter to convert floats in CLI. */
public class FractionConverter implements CommandLine.ITypeConverter<Fraction> { public class FractionConverter implements CommandLine.ITypeConverter<Float> {
@Override @Override
public Fraction convert(final String value) throws FractionConversionException { public Float convert(final String value) throws FractionConversionException {
try { try {
return Fraction.fromString(value); return Fraction.fromString(value).getValue();
} catch (final NullPointerException | IllegalArgumentException e) { } catch (final NullPointerException | IllegalArgumentException e) {
throw new FractionConversionException(value); throw new FractionConversionException(value);
} }

@ -20,12 +20,12 @@ import org.hyperledger.besu.util.number.Percentage;
import picocli.CommandLine; import picocli.CommandLine;
/** The Percentage Cli type converter. */ /** The Percentage Cli type converter. */
public class PercentageConverter implements CommandLine.ITypeConverter<Percentage> { public class PercentageConverter implements CommandLine.ITypeConverter<Integer> {
@Override @Override
public Percentage convert(final String value) throws PercentageConversionException { public Integer convert(final String value) throws PercentageConversionException {
try { try {
return Percentage.fromString(value); return Percentage.fromString(value).getValue();
} catch (NullPointerException | IllegalArgumentException e) { } catch (NullPointerException | IllegalArgumentException e) {
throw new PercentageConversionException(value); throw new PercentageConversionException(value);
} }

@ -1,39 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.converter.exception;
import static java.lang.String.format;
/** The custom Duration conversion exception. */
public final class DurationConversionException extends Exception {
/**
* Instantiates a new Duration conversion exception for malformed value.
*
* @param value the value
*/
public DurationConversionException(final String value) {
super(format("'%s' is not a long", value));
}
/**
* Instantiates a new Duration conversion exception for negative value.
*
* @param value the millis
*/
public DurationConversionException(final long value) {
super(format("negative value '%d' is not allowed", value));
}
}

@ -16,11 +16,6 @@ package org.hyperledger.besu.cli.options;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import org.hyperledger.besu.datatypes.Wei;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator; import java.util.Iterator;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
@ -101,44 +96,4 @@ public class OptionParser {
public static String format(final UInt256 value) { public static String format(final UInt256 value) {
return value.toBigInteger().toString(10); return value.toBigInteger().toString(10);
} }
/**
* Format Wei to string.
*
* @param value the value
* @return the string
*/
public static String format(final Wei value) {
return format(value.toUInt256());
}
/**
* Format any object to string. This implementation tries to find an existing format method, in
* this class, that matches the type of the passed object, and if not found just invoke, to string
* on the passed object
*
* @param value the object
* @return the string
*/
public static String format(final Object value) {
Method formatMethod;
try {
formatMethod = OptionParser.class.getMethod("format", value.getClass());
} catch (NoSuchMethodException e) {
try {
// maybe a primitive version of the method exists
formatMethod =
OptionParser.class.getMethod(
"format", MethodType.methodType(value.getClass()).unwrap().returnType());
} catch (NoSuchMethodException ex) {
return value.toString();
}
}
try {
return (String) formatMethod.invoke(null, value);
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
} }

@ -1,263 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_DOUBLE_FORMAT_HELP;
import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_INTEGER_FORMAT_HELP;
import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_LONG_FORMAT_HELP;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY;
import org.hyperledger.besu.cli.converter.FractionConverter;
import org.hyperledger.besu.cli.converter.PercentageConverter;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.util.number.Fraction;
import org.hyperledger.besu.util.number.Percentage;
import java.io.File;
import java.util.List;
import picocli.CommandLine;
/** The Transaction pool Cli stable options. */
public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfiguration> {
private static final String TX_POOL_IMPLEMENTATION = "--tx-pool";
private static final String TX_POOL_DISABLE_LOCALS = "--tx-pool-disable-locals";
private static final String TX_POOL_ENABLE_SAVE_RESTORE = "--tx-pool-enable-save-restore";
private static final String TX_POOL_SAVE_FILE = "--tx-pool-save-file";
private static final String TX_POOL_PRICE_BUMP = "--tx-pool-price-bump";
private static final String RPC_TX_FEECAP = "--rpc-tx-feecap";
private static final String STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG =
"--strict-tx-replay-protection-enabled";
@CommandLine.Option(
names = {TX_POOL_IMPLEMENTATION},
paramLabel = "<Enum>",
description = "The Transaction Pool implementation to use(default: ${DEFAULT-VALUE})",
arity = "0..1")
private TransactionPoolConfiguration.Implementation txPoolImplementation = LAYERED;
@CommandLine.Option(
names = {TX_POOL_DISABLE_LOCALS},
paramLabel = "<Boolean>",
description =
"Set to true if transactions sent via RPC should have the same checks and not be prioritized over remote ones (default: ${DEFAULT-VALUE})",
fallbackValue = "true",
arity = "0..1")
private Boolean disableLocalTxs = TransactionPoolConfiguration.DEFAULT_DISABLE_LOCAL_TXS;
@CommandLine.Option(
names = {TX_POOL_ENABLE_SAVE_RESTORE},
paramLabel = "<Boolean>",
description =
"Set to true to enable saving the txpool content to file on shutdown and reloading it on startup (default: ${DEFAULT-VALUE})",
fallbackValue = "true",
arity = "0..1")
private Boolean saveRestoreEnabled = TransactionPoolConfiguration.DEFAULT_ENABLE_SAVE_RESTORE;
@CommandLine.Option(
names = {TX_POOL_SAVE_FILE},
paramLabel = "<STRING>",
description =
"If saving the txpool content is enabled, define a custom path for the save file (default: ${DEFAULT-VALUE} in the data-dir)",
arity = "1")
private File saveFile = TransactionPoolConfiguration.DEFAULT_SAVE_FILE;
@CommandLine.Option(
names = {TX_POOL_PRICE_BUMP},
paramLabel = "<Percentage>",
converter = PercentageConverter.class,
description =
"Price bump percentage to replace an already existing transaction (default: ${DEFAULT-VALUE})",
arity = "1")
private Percentage priceBump = TransactionPoolConfiguration.DEFAULT_PRICE_BUMP;
@CommandLine.Option(
names = {RPC_TX_FEECAP},
description =
"Maximum transaction fees (in Wei) accepted for transaction submitted through RPC (default: ${DEFAULT-VALUE})",
arity = "1")
private Wei txFeeCap = TransactionPoolConfiguration.DEFAULT_RPC_TX_FEE_CAP;
@CommandLine.Option(
names = {STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG},
paramLabel = "<Boolean>",
description =
"Require transactions submitted via JSON-RPC to use replay protection in accordance with EIP-155 (default: ${DEFAULT-VALUE})",
fallbackValue = "true",
arity = "0..1")
private Boolean strictTxReplayProtectionEnabled = false;
@CommandLine.ArgGroup(
validate = false,
heading = "@|bold Tx Pool Layered Implementation Options|@%n")
private final Layered layeredOptions = new Layered();
static class Layered {
private static final String TX_POOL_LAYER_MAX_CAPACITY = "--tx-pool-layer-max-capacity";
private static final String TX_POOL_MAX_PRIORITIZED = "--tx-pool-max-prioritized";
private static final String TX_POOL_MAX_FUTURE_BY_SENDER = "--tx-pool-max-future-by-sender";
@CommandLine.Option(
names = {TX_POOL_LAYER_MAX_CAPACITY},
paramLabel = MANDATORY_LONG_FORMAT_HELP,
description =
"Max amount of memory space, in bytes, that any layer within the transaction pool could occupy (default: ${DEFAULT-VALUE})",
arity = "1")
Long txPoolLayerMaxCapacity =
TransactionPoolConfiguration.DEFAULT_PENDING_TRANSACTIONS_LAYER_MAX_CAPACITY_BYTES;
@CommandLine.Option(
names = {TX_POOL_MAX_PRIORITIZED},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description =
"Max number of pending transactions that are prioritized and thus kept sorted (default: ${DEFAULT-VALUE})",
arity = "1")
Integer txPoolMaxPrioritized =
TransactionPoolConfiguration.DEFAULT_MAX_PRIORITIZED_TRANSACTIONS;
@CommandLine.Option(
names = {TX_POOL_MAX_FUTURE_BY_SENDER},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description =
"Max number of future pending transactions allowed for a single sender (default: ${DEFAULT-VALUE})",
arity = "1")
Integer txPoolMaxFutureBySender = TransactionPoolConfiguration.DEFAULT_MAX_FUTURE_BY_SENDER;
}
@CommandLine.ArgGroup(
validate = false,
heading = "@|bold Tx Pool Legacy Implementation Options|@%n")
private final Legacy legacyOptions = new Legacy();
static class Legacy {
private static final String TX_POOL_RETENTION_HOURS = "--tx-pool-retention-hours";
private static final String TX_POOL_LIMIT_BY_ACCOUNT_PERCENTAGE =
"--tx-pool-limit-by-account-percentage";
private static final String TX_POOL_MAX_SIZE = "--tx-pool-max-size";
@CommandLine.Option(
names = {TX_POOL_RETENTION_HOURS},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description =
"Maximum retention period of pending transactions in hours (default: ${DEFAULT-VALUE})",
arity = "1")
Integer pendingTxRetentionPeriod = TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS;
@CommandLine.Option(
names = {TX_POOL_LIMIT_BY_ACCOUNT_PERCENTAGE},
paramLabel = MANDATORY_DOUBLE_FORMAT_HELP,
converter = FractionConverter.class,
description =
"Maximum portion of the transaction pool which a single account may occupy with future transactions (default: ${DEFAULT-VALUE})",
arity = "1")
Fraction txPoolLimitByAccountPercentage =
TransactionPoolConfiguration.DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE;
@CommandLine.Option(
names = {TX_POOL_MAX_SIZE},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description =
"Maximum number of pending transactions that will be kept in the transaction pool (default: ${DEFAULT-VALUE})",
arity = "1")
Integer txPoolMaxSize = TransactionPoolConfiguration.DEFAULT_MAX_PENDING_TRANSACTIONS;
}
private TransactionPoolOptions() {}
/**
* Create transaction pool options.
*
* @return the transaction pool options
*/
public static TransactionPoolOptions create() {
return new TransactionPoolOptions();
}
/**
* Create Transaction Pool Options from Transaction Pool Configuration.
*
* @param config the Transaction Pool Configuration
* @return the transaction pool options
*/
public static TransactionPoolOptions fromConfig(final TransactionPoolConfiguration config) {
final TransactionPoolOptions options = TransactionPoolOptions.create();
options.txPoolImplementation = config.getTxPoolImplementation();
options.saveRestoreEnabled = config.getEnableSaveRestore();
options.disableLocalTxs = config.getDisableLocalTransactions();
options.priceBump = config.getPriceBump();
options.txFeeCap = config.getTxFeeCap();
options.saveFile = config.getSaveFile();
options.strictTxReplayProtectionEnabled = config.getStrictTransactionReplayProtectionEnabled();
options.layeredOptions.txPoolLayerMaxCapacity =
config.getPendingTransactionsLayerMaxCapacityBytes();
options.layeredOptions.txPoolMaxPrioritized = config.getMaxPrioritizedTransactions();
options.layeredOptions.txPoolMaxFutureBySender = config.getMaxFutureBySender();
options.legacyOptions.txPoolLimitByAccountPercentage =
config.getTxPoolLimitByAccountPercentage();
options.legacyOptions.txPoolMaxSize = config.getTxPoolMaxSize();
options.legacyOptions.pendingTxRetentionPeriod = config.getPendingTxRetentionPeriod();
return options;
}
/**
* Validate that there are no inconsistencies in the specified options. For example that the
* options are valid for the selected implementation.
*
* @param commandLine the full commandLine to check all the options specified by the user
*/
public void validate(final CommandLine commandLine) {
CommandLineUtils.failIfOptionDoesntMeetRequirement(
commandLine,
"Could not use legacy transaction pool options with layered implementation",
!txPoolImplementation.equals(LAYERED),
CommandLineUtils.getCLIOptionNames(Legacy.class));
CommandLineUtils.failIfOptionDoesntMeetRequirement(
commandLine,
"Could not use layered transaction pool options with legacy implementation",
!txPoolImplementation.equals(LEGACY),
CommandLineUtils.getCLIOptionNames(Layered.class));
}
@Override
public TransactionPoolConfiguration toDomainObject() {
return ImmutableTransactionPoolConfiguration.builder()
.txPoolImplementation(txPoolImplementation)
.enableSaveRestore(saveRestoreEnabled)
.disableLocalTransactions(disableLocalTxs)
.priceBump(priceBump)
.txFeeCap(txFeeCap)
.saveFile(saveFile)
.strictTransactionReplayProtectionEnabled(strictTxReplayProtectionEnabled)
.pendingTransactionsLayerMaxCapacityBytes(layeredOptions.txPoolLayerMaxCapacity)
.maxPrioritizedTransactions(layeredOptions.txPoolMaxPrioritized)
.maxFutureBySender(layeredOptions.txPoolMaxFutureBySender)
.txPoolLimitByAccountPercentage(legacyOptions.txPoolLimitByAccountPercentage)
.txPoolMaxSize(legacyOptions.txPoolMaxSize)
.pendingTxRetentionPeriod(legacyOptions.pendingTxRetentionPeriod)
.build();
}
@Override
public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new TransactionPoolOptions());
}
}

@ -14,25 +14,50 @@
*/ */
package org.hyperledger.besu.cli.options.unstable; package org.hyperledger.besu.cli.options.unstable;
import org.hyperledger.besu.cli.converter.DurationMillisConverter;
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.cli.options.OptionParser;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import java.time.Duration; import java.time.Duration;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine; import picocli.CommandLine;
/** The Transaction pool Cli unstable options. */ /** The Transaction pool Cli options. */
public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfiguration.Unstable> { public class TransactionPoolOptions
implements CLIOptions<ImmutableTransactionPoolConfiguration.Builder> {
private static final Logger LOG = LoggerFactory.getLogger(TransactionPoolOptions.class);
private static final String TX_MESSAGE_KEEP_ALIVE_SEC_FLAG = private static final String TX_MESSAGE_KEEP_ALIVE_SEC_FLAG =
"--Xincoming-tx-messages-keep-alive-seconds"; "--Xincoming-tx-messages-keep-alive-seconds";
private static final String ETH65_TX_ANNOUNCED_BUFFERING_PERIOD_FLAG = private static final String ETH65_TX_ANNOUNCED_BUFFERING_PERIOD_FLAG =
"--Xeth65-tx-announced-buffering-period-milliseconds"; "--Xeth65-tx-announced-buffering-period-milliseconds";
private static final String STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG =
"--strict-tx-replay-protection-enabled";
private static final String LAYERED_TX_POOL_ENABLED_FLAG = "--Xlayered-tx-pool";
private static final String LAYERED_TX_POOL_LAYER_MAX_CAPACITY =
"--Xlayered-tx-pool-layer-max-capacity";
private static final String LAYERED_TX_POOL_MAX_PRIORITIZED =
"--Xlayered-tx-pool-max-prioritized";
private static final String LAYERED_TX_POOL_MAX_FUTURE_BY_SENDER =
"--Xlayered-tx-pool-max-future-by-sender";
@CommandLine.Option(
names = {STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG},
paramLabel = "<Boolean>",
description =
"Require transactions submitted via JSON-RPC to use replay protection in accordance with EIP-155 (default: ${DEFAULT-VALUE})",
fallbackValue = "true",
arity = "0..1")
private Boolean strictTxReplayProtectionEnabled = false;
@CommandLine.Option( @CommandLine.Option(
names = {TX_MESSAGE_KEEP_ALIVE_SEC_FLAG}, names = {TX_MESSAGE_KEEP_ALIVE_SEC_FLAG},
paramLabel = "<INTEGER>", paramLabel = "<INTEGER>",
@ -41,18 +66,56 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
"Keep alive of incoming transaction messages in seconds (default: ${DEFAULT-VALUE})", "Keep alive of incoming transaction messages in seconds (default: ${DEFAULT-VALUE})",
arity = "1") arity = "1")
private Integer txMessageKeepAliveSeconds = private Integer txMessageKeepAliveSeconds =
TransactionPoolConfiguration.Unstable.DEFAULT_TX_MSG_KEEP_ALIVE; TransactionPoolConfiguration.DEFAULT_TX_MSG_KEEP_ALIVE;
@CommandLine.Option( @CommandLine.Option(
names = {ETH65_TX_ANNOUNCED_BUFFERING_PERIOD_FLAG}, names = {ETH65_TX_ANNOUNCED_BUFFERING_PERIOD_FLAG},
paramLabel = "<LONG>", paramLabel = "<LONG>",
converter = DurationMillisConverter.class,
hidden = true, hidden = true,
description = description =
"The period for which the announced transactions remain in the buffer before being requested from the peers in milliseconds (default: ${DEFAULT-VALUE})", "The period for which the announced transactions remain in the buffer before being requested from the peers in milliseconds (default: ${DEFAULT-VALUE})",
arity = "1") arity = "1")
private Duration eth65TrxAnnouncedBufferingPeriod = private long eth65TrxAnnouncedBufferingPeriod =
TransactionPoolConfiguration.Unstable.ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD; TransactionPoolConfiguration.ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD.toMillis();
@CommandLine.Option(
names = {LAYERED_TX_POOL_ENABLED_FLAG},
paramLabel = "<Boolean>",
hidden = true,
description = "Enable the Layered Transaction Pool (default: ${DEFAULT-VALUE})",
arity = "0..1")
private Boolean layeredTxPoolEnabled =
TransactionPoolConfiguration.DEFAULT_LAYERED_TX_POOL_ENABLED;
@CommandLine.Option(
names = {LAYERED_TX_POOL_LAYER_MAX_CAPACITY},
paramLabel = "<Long>",
hidden = true,
description =
"Max amount of memory space, in bytes, that any layer within the transaction pool could occupy (default: ${DEFAULT-VALUE})",
arity = "1")
private long layeredTxPoolLayerMaxCapacity =
TransactionPoolConfiguration.DEFAULT_PENDING_TRANSACTIONS_LAYER_MAX_CAPACITY_BYTES;
@CommandLine.Option(
names = {LAYERED_TX_POOL_MAX_PRIORITIZED},
paramLabel = "<Int>",
hidden = true,
description =
"Max number of pending transactions that are prioritized and thus kept sorted (default: ${DEFAULT-VALUE})",
arity = "1")
private int layeredTxPoolMaxPrioritized =
TransactionPoolConfiguration.DEFAULT_MAX_PRIORITIZED_TRANSACTIONS;
@CommandLine.Option(
names = {LAYERED_TX_POOL_MAX_FUTURE_BY_SENDER},
paramLabel = "<Int>",
hidden = true,
description =
"Max number of future pending transactions allowed for a single sender (default: ${DEFAULT-VALUE})",
arity = "1")
private int layeredTxPoolMaxFutureBySender =
TransactionPoolConfiguration.DEFAULT_MAX_FUTURE_BY_SENDER;
private TransactionPoolOptions() {} private TransactionPoolOptions() {}
@ -71,24 +134,51 @@ public class TransactionPoolOptions implements CLIOptions<TransactionPoolConfigu
* @param config the Transaction Pool Configuration * @param config the Transaction Pool Configuration
* @return the transaction pool options * @return the transaction pool options
*/ */
public static TransactionPoolOptions fromConfig( public static TransactionPoolOptions fromConfig(final TransactionPoolConfiguration config) {
final TransactionPoolConfiguration.Unstable config) {
final TransactionPoolOptions options = TransactionPoolOptions.create(); final TransactionPoolOptions options = TransactionPoolOptions.create();
options.txMessageKeepAliveSeconds = config.getTxMessageKeepAliveSeconds(); options.txMessageKeepAliveSeconds = config.getTxMessageKeepAliveSeconds();
options.eth65TrxAnnouncedBufferingPeriod = config.getEth65TrxAnnouncedBufferingPeriod(); options.eth65TrxAnnouncedBufferingPeriod =
config.getEth65TrxAnnouncedBufferingPeriod().toMillis();
options.strictTxReplayProtectionEnabled = config.getStrictTransactionReplayProtectionEnabled();
options.layeredTxPoolEnabled = config.getLayeredTxPoolEnabled();
options.layeredTxPoolLayerMaxCapacity = config.getPendingTransactionsLayerMaxCapacityBytes();
options.layeredTxPoolMaxPrioritized = config.getMaxPrioritizedTransactions();
options.layeredTxPoolMaxFutureBySender = config.getMaxFutureBySender();
return options; return options;
} }
@Override @Override
public TransactionPoolConfiguration.Unstable toDomainObject() { public ImmutableTransactionPoolConfiguration.Builder toDomainObject() {
return ImmutableTransactionPoolConfiguration.Unstable.builder() if (layeredTxPoolEnabled) {
LOG.warn(
"Layered transaction pool enabled, ignoring settings for "
+ "--tx-pool-max-size and --tx-pool-limit-by-account-percentage");
}
return ImmutableTransactionPoolConfiguration.builder()
.strictTransactionReplayProtectionEnabled(strictTxReplayProtectionEnabled)
.txMessageKeepAliveSeconds(txMessageKeepAliveSeconds) .txMessageKeepAliveSeconds(txMessageKeepAliveSeconds)
.eth65TrxAnnouncedBufferingPeriod(eth65TrxAnnouncedBufferingPeriod) .eth65TrxAnnouncedBufferingPeriod(Duration.ofMillis(eth65TrxAnnouncedBufferingPeriod))
.build(); .layeredTxPoolEnabled(layeredTxPoolEnabled)
.pendingTransactionsLayerMaxCapacityBytes(layeredTxPoolLayerMaxCapacity)
.maxPrioritizedTransactions(layeredTxPoolMaxPrioritized)
.maxFutureBySender(layeredTxPoolMaxFutureBySender);
} }
@Override @Override
public List<String> getCLIOptions() { public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new TransactionPoolOptions()); return Arrays.asList(
STRICT_TX_REPLAY_PROTECTION_ENABLED_FLAG + "=" + strictTxReplayProtectionEnabled,
TX_MESSAGE_KEEP_ALIVE_SEC_FLAG,
OptionParser.format(txMessageKeepAliveSeconds),
ETH65_TX_ANNOUNCED_BUFFERING_PERIOD_FLAG,
OptionParser.format(eth65TrxAnnouncedBufferingPeriod),
LAYERED_TX_POOL_ENABLED_FLAG + "=" + layeredTxPoolEnabled,
LAYERED_TX_POOL_LAYER_MAX_CAPACITY,
OptionParser.format(layeredTxPoolLayerMaxCapacity),
LAYERED_TX_POOL_MAX_PRIORITIZED,
OptionParser.format(layeredTxPoolMaxPrioritized),
LAYERED_TX_POOL_MAX_FUTURE_BY_SENDER,
OptionParser.format(layeredTxPoolMaxFutureBySender));
} }
} }

@ -99,8 +99,6 @@ public class StorageSubCommand implements Runnable {
} }
private StorageProvider getStorageProvider() { private StorageProvider getStorageProvider() {
// init collection of ignorable segments
parentCommand.parentCommand.setIgnorableStorageSegments();
return parentCommand.parentCommand.getStorageProvider(); return parentCommand.parentCommand.getStorageProvider();
} }

@ -14,17 +14,10 @@
*/ */
package org.hyperledger.besu.cli.util; package org.hyperledger.besu.cli.util;
import org.hyperledger.besu.cli.converter.TypeFormatter;
import org.hyperledger.besu.cli.options.OptionParser;
import org.hyperledger.besu.util.StringUtils; import org.hyperledger.besu.util.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.google.common.base.Strings; import com.google.common.base.Strings;
@ -131,103 +124,6 @@ public class CommandLineUtils {
} }
} }
/**
* Return all the option names declared in a class. Note this will recursively check in any inner
* option class if present.
*
* @param optClass the class to look for options
* @return a list of option names found in the class
*/
public static List<String> getCLIOptionNames(final Class<?> optClass) {
final List<String> cliOpts = new ArrayList<>();
final Field[] fields = optClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Annotation ann = field.getAnnotation(CommandLine.Option.class);
if (ann != null) {
final var optAnn = CommandLine.Option.class.cast(ann);
cliOpts.add(optAnn.names()[0]);
} else {
ann = field.getAnnotation(CommandLine.ArgGroup.class);
if (ann != null) {
cliOpts.addAll(getCLIOptionNames(field.getType()));
}
}
}
return cliOpts;
}
/**
* Converts the runtime options into their CLI representation. Options with a value equals to its
* default are not included in the result since redundant. Note this will recursively check in any
* inner option class if present.
*
* @param currOptions the actual runtime options
* @param defaults the default option values
* @return a list of CLI arguments
*/
public static List<String> getCLIOptions(final Object currOptions, final Object defaults) {
final List<String> cliOpts = new ArrayList<>();
final Field[] fields = currOptions.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Annotation ann = field.getAnnotation(CommandLine.Option.class);
if (ann != null) {
try {
var optVal = field.get(currOptions);
if (!Objects.equals(optVal, field.get(defaults))) {
var optAnn = CommandLine.Option.class.cast(ann);
cliOpts.add(optAnn.names()[0]);
final var optConverter = optAnn.converter();
cliOpts.add(formatValue(optConverter, optVal));
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
} else {
ann = field.getAnnotation(CommandLine.ArgGroup.class);
if (ann != null) {
try {
cliOpts.addAll(getCLIOptions(field.get(currOptions), field.get(defaults)));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
return cliOpts;
}
/**
* There are different ways to format an option value back to its CLI form, the first is to use a
* {@link TypeFormatter} if present, otherwise the formatting it is delegated to {@link
* OptionParser#format(Object)}
*
* @param optConverter the list of converter types for the option
* @param optVal the value of the options
* @return a string with the CLI form of the value
*/
@SuppressWarnings("unchecked")
private static String formatValue(
final Class<? extends CommandLine.ITypeConverter<?>>[] optConverter, final Object optVal) {
return Arrays.stream(optConverter)
.filter(c -> Arrays.stream(c.getInterfaces()).anyMatch(i -> i.equals(TypeFormatter.class)))
.findFirst()
.map(
ctf -> {
try {
return (TypeFormatter) ctf.getDeclaredConstructor().newInstance();
} catch (InstantiationException
| IllegalAccessException
| InvocationTargetException
| NoSuchMethodException e) {
throw new RuntimeException(e);
}
})
.map(tf -> tf.format(optVal))
.orElseGet(() -> OptionParser.format(optVal));
}
private static String getAffectedOptions( private static String getAffectedOptions(
final CommandLine commandLine, final List<String> dependentOptionsNames) { final CommandLine commandLine, final List<String> dependentOptionsNames) {
return commandLine.getCommandSpec().options().stream() return commandLine.getCommandSpec().options().stream()

@ -15,8 +15,6 @@
package org.hyperledger.besu.cli.util; package org.hyperledger.besu.cli.util;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.util.number.Fraction;
import org.hyperledger.besu.util.number.Percentage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -91,10 +89,6 @@ public class TomlConfigFileDefaultProvider implements IDefaultValueProvider {
defaultValue = getNumericEntryAsString(optionSpec); defaultValue = getNumericEntryAsString(optionSpec);
} else if (optionSpec.type().equals(Float.class) || optionSpec.type().equals(float.class)) { } else if (optionSpec.type().equals(Float.class) || optionSpec.type().equals(float.class)) {
defaultValue = getNumericEntryAsString(optionSpec); defaultValue = getNumericEntryAsString(optionSpec);
} else if (optionSpec.type().equals(Percentage.class)) {
defaultValue = getNumericEntryAsString(optionSpec);
} else if (optionSpec.type().equals(Fraction.class)) {
defaultValue = getNumericEntryAsString(optionSpec);
} else { // else will be treated as String } else { // else will be treated as String
defaultValue = getEntryAsString(optionSpec); defaultValue = getEntryAsString(optionSpec);
} }

@ -72,7 +72,6 @@ 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.p2p.config.SubProtocolConfiguration; import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.plugin.services.BesuEvents;
import org.hyperledger.besu.util.Subscribers; import org.hyperledger.besu.util.Subscribers;
import java.util.HashMap; import java.util.HashMap;
@ -232,30 +231,7 @@ public class IbftBesuControllerBuilder extends BftBesuControllerBuilder {
blockCreatorFactory, blockCreatorFactory,
blockchain, blockchain,
bftEventQueue); bftEventQueue);
if (syncState.isInitialSyncPhaseDone()) {
LOG.info("Starting IBFT mining coordinator");
ibftMiningCoordinator.enable();
ibftMiningCoordinator.start();
} else {
LOG.info("IBFT mining coordinator not starting while initial sync in progress");
}
syncState.subscribeCompletionReached(
new BesuEvents.InitialSyncCompletionListener() {
@Override
public void onInitialSyncCompleted() {
LOG.info("Starting IBFT mining coordinator following initial sync");
ibftMiningCoordinator.enable(); ibftMiningCoordinator.enable();
ibftMiningCoordinator.start();
}
@Override
public void onInitialSyncRestart() {
// Nothing to do. The mining coordinator won't be started until
// sync has completed.
}
});
return ibftMiningCoordinator; return ibftMiningCoordinator;
} }

@ -82,7 +82,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration; import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.plugin.services.BesuEvents;
import org.hyperledger.besu.util.Subscribers; import org.hyperledger.besu.util.Subscribers;
import java.util.HashMap; import java.util.HashMap;
@ -272,30 +271,7 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
blockCreatorFactory, blockCreatorFactory,
blockchain, blockchain,
bftEventQueue); bftEventQueue);
if (syncState.isInitialSyncPhaseDone()) {
LOG.info("Starting QBFT mining coordinator");
miningCoordinator.enable();
miningCoordinator.start();
} else {
LOG.info("QBFT mining coordinator not starting while initial sync in progress");
}
syncState.subscribeCompletionReached(
new BesuEvents.InitialSyncCompletionListener() {
@Override
public void onInitialSyncCompleted() {
LOG.info("Starting QBFT mining coordinator following initial sync");
miningCoordinator.enable(); miningCoordinator.enable();
miningCoordinator.start();
}
@Override
public void onInitialSyncRestart() {
// Nothing to do. The mining coordinator won't be started until
// sync has completed.
}
});
return miningCoordinator; return miningCoordinator;
} }

@ -31,7 +31,6 @@ 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.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.Unstable;
import org.hyperledger.besu.plugin.services.TraceService; import org.hyperledger.besu.plugin.services.TraceService;
import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer;
@ -39,8 +38,6 @@ import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.LongStream;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -91,71 +88,20 @@ public class TraceServiceImpl implements TraceService {
block.ifPresent(value -> trace(value, tracer)); block.ifPresent(value -> trace(value, tracer));
} }
/**
* Traces range of blocks
*
* @param fromBlockNumber the beginning of the range (inclusive)
* @param toBlockNumber the end of the range (inclusive)
* @param beforeTracing Function which performs an operation on a MutableWorldState before tracing
* @param afterTracing Function which performs an operation on a MutableWorldState after tracing
* @param tracer an instance of OperationTracer
*/
@Override
public void trace(
final long fromBlockNumber,
final long toBlockNumber,
final Consumer<WorldUpdater> beforeTracing,
final Consumer<WorldUpdater> afterTracing,
final BlockAwareOperationTracer tracer) {
checkArgument(tracer != null);
LOG.debug("Tracing from block {} to block {}", fromBlockNumber, toBlockNumber);
final Blockchain blockchain = blockchainQueries.getBlockchain();
final List<Block> blocks =
LongStream.rangeClosed(fromBlockNumber, toBlockNumber)
.mapToObj(
number ->
blockchain
.getBlockByNumber(number)
.orElseThrow(() -> new RuntimeException("Block not found " + number)))
.toList();
Tracer.processTracing(
blockchainQueries,
blocks.get(0).getHash(),
traceableState -> {
final WorldUpdater worldStateUpdater = traceableState.updater();
final ChainUpdater chainUpdater = new ChainUpdater(traceableState, worldStateUpdater);
beforeTracing.accept(worldStateUpdater);
final List<TransactionProcessingResult> results = new ArrayList<>();
blocks.forEach(
block -> {
results.addAll(trace(blockchain, block, chainUpdater, tracer));
tracer.traceEndBlock(block.getHeader(), block.getBody());
});
afterTracing.accept(chainUpdater.getNextUpdater());
return Optional.of(results);
});
}
private void trace(final Block block, final BlockAwareOperationTracer tracer) { private void trace(final Block block, final BlockAwareOperationTracer tracer) {
LOG.debug("Tracing block {}", block.toLogString()); LOG.debug("Tracing block {}", block.toLogString());
final Blockchain blockchain = blockchainQueries.getBlockchain(); final List<TransactionProcessingResult> results = new ArrayList<>();
Tracer.processTracing( Tracer.processTracing(
blockchainQueries, blockchainQueries,
block.getHash(), block.getHash(),
traceableState -> traceableState -> {
Optional.of(trace(blockchain, block, new ChainUpdater(traceableState), tracer))); final Blockchain blockchain = blockchainQueries.getBlockchain();
tracer.traceEndBlock(block.getHeader(), block.getBody()); final ChainUpdater chainUpdater = new ChainUpdater(traceableState);
}
private List<TransactionProcessingResult> trace(
final Blockchain blockchain,
final Block block,
final ChainUpdater chainUpdater,
final BlockAwareOperationTracer tracer) {
final List<TransactionProcessingResult> results = new ArrayList<>();
final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(block.getHeader()); final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(block.getHeader());
final MainnetTransactionProcessor transactionProcessor = protocolSpec.getTransactionProcessor(); final MainnetTransactionProcessor transactionProcessor =
protocolSpec.getTransactionProcessor();
final BlockHeader header = block.getHeader(); final BlockHeader header = block.getHeader();
tracer.traceStartBlock(block.getHeader(), block.getBody()); tracer.traceStartBlock(block.getHeader(), block.getBody());
block block
@ -170,15 +116,17 @@ public class TraceServiceImpl implements TraceService {
.getFeeMarket() .getFeeMarket()
.blobGasPricePerGas( .blobGasPricePerGas(
maybeParentHeader maybeParentHeader
.map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) .map(
parent ->
calculateExcessBlobGasForParent(protocolSpec, parent))
.orElse(BlobGas.ZERO)); .orElse(BlobGas.ZERO));
final WorldUpdater worldUpdater = chainUpdater.getNextUpdater(); tracer.traceStartTransaction(transaction);
tracer.traceStartTransaction(worldUpdater, transaction);
final TransactionProcessingResult result = final TransactionProcessingResult result =
transactionProcessor.processTransaction( transactionProcessor.processTransaction(
blockchain, blockchain,
worldUpdater, chainUpdater.getNextUpdater(),
header, header,
transaction, transaction,
header.getCoinbase(), header.getCoinbase(),
@ -188,20 +136,13 @@ public class TraceServiceImpl implements TraceService {
blobGasPrice); blobGasPrice);
long transactionGasUsed = transaction.getGasLimit() - result.getGasRemaining(); long transactionGasUsed = transaction.getGasLimit() - result.getGasRemaining();
tracer.traceEndTransaction( tracer.traceEndTransaction(result.getOutput(), transactionGasUsed, 0);
worldUpdater,
transaction,
result.isSuccessful(),
result.getOutput(),
result.getLogs(),
transactionGasUsed,
0);
results.add(result); results.add(result);
}); });
return Optional.of(results);
});
tracer.traceEndBlock(block.getHeader(), block.getBody()); tracer.traceEndBlock(block.getHeader(), block.getBody());
return results;
} }
} }

@ -130,6 +130,17 @@ public class ForkIdsNetworkConfigTest {
new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L), new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L)) new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L))
}, },
new Object[] {
NetworkName.KOTTI,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x550152eL), 716617L),
new ForkId(Bytes.ofUnsignedInt(0xa3270822L), 1705549L),
new ForkId(Bytes.ofUnsignedInt(0x8f3698e0L), 2200013L),
new ForkId(Bytes.ofUnsignedInt(0x6f402821L), 4368634),
new ForkId(Bytes.ofUnsignedInt(0xf03e54e7L), 5578000L),
new ForkId(Bytes.ofUnsignedInt(0xc5459816L), 0L),
new ForkId(Bytes.ofUnsignedInt(0xc5459816L), 0L))
},
new Object[] { new Object[] {
NetworkName.CLASSIC, NetworkName.CLASSIC,
List.of( List.of(

@ -25,6 +25,7 @@ import static org.hyperledger.besu.cli.config.NetworkName.EXPERIMENTAL_EIPS;
import static org.hyperledger.besu.cli.config.NetworkName.FUTURE_EIPS; import static org.hyperledger.besu.cli.config.NetworkName.FUTURE_EIPS;
import static org.hyperledger.besu.cli.config.NetworkName.GOERLI; import static org.hyperledger.besu.cli.config.NetworkName.GOERLI;
import static org.hyperledger.besu.cli.config.NetworkName.HOLESKY; import static org.hyperledger.besu.cli.config.NetworkName.HOLESKY;
import static org.hyperledger.besu.cli.config.NetworkName.KOTTI;
import static org.hyperledger.besu.cli.config.NetworkName.MAINNET; import static org.hyperledger.besu.cli.config.NetworkName.MAINNET;
import static org.hyperledger.besu.cli.config.NetworkName.MORDOR; import static org.hyperledger.besu.cli.config.NetworkName.MORDOR;
import static org.hyperledger.besu.cli.config.NetworkName.SEPOLIA; import static org.hyperledger.besu.cli.config.NetworkName.SEPOLIA;
@ -58,6 +59,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.BesuInfo; import org.hyperledger.besu.BesuInfo;
import org.hyperledger.besu.cli.config.EthNetworkConfig; import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions;
import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
@ -4107,6 +4109,22 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
} }
@Test
public void kottiValuesAreUsed() throws Exception {
parseCommand("--network", "kotti");
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(KOTTI));
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test @Test
public void mordorValuesAreUsed() throws Exception { public void mordorValuesAreUsed() throws Exception {
parseCommand("--network", "mordor"); parseCommand("--network", "mordor");
@ -4148,6 +4166,11 @@ public class BesuCommandTest extends CommandTestAbstract {
networkValuesCanBeOverridden("classic"); networkValuesCanBeOverridden("classic");
} }
@Test
public void kottiValuesCanBeOverridden() throws Exception {
networkValuesCanBeOverridden("kotti");
}
@Test @Test
public void mordorValuesCanBeOverridden() throws Exception { public void mordorValuesCanBeOverridden() throws Exception {
networkValuesCanBeOverridden("mordor"); networkValuesCanBeOverridden("mordor");
@ -4596,6 +4619,192 @@ public class BesuCommandTest extends CommandTestAbstract {
.contains(staticNodeURI.toString(), "not in nodes-allowlist"); .contains(staticNodeURI.toString(), "not in nodes-allowlist");
} }
@Test
public void disableLocalsDefault() {
parseCommand();
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getDisableLocalTransactions()).isFalse();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void disableLocalsOn() {
parseCommand("--tx-pool-disable-locals=true");
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getDisableLocalTransactions()).isTrue();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void disableLocalsOff() {
parseCommand("--tx-pool-disable-locals=false");
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getDisableLocalTransactions()).isFalse();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void saveToFileDisabledByDefault() {
parseCommand();
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getEnableSaveRestore()).isFalse();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void saveToFileEnabledDefaultPath() {
parseCommand("--tx-pool-enable-save-restore=true");
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getEnableSaveRestore()).isTrue();
assertThat(transactionPoolConfigCaptor.getValue().getSaveFile())
.hasName(TransactionPoolConfiguration.DEFAULT_SAVE_FILE_NAME);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void saveToFileEnabledCustomPath() {
parseCommand("--tx-pool-enable-save-restore=true", "--tx-pool-save-file=my.save.file");
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getEnableSaveRestore()).isTrue();
assertThat(transactionPoolConfigCaptor.getValue().getSaveFile()).hasName("my.save.file");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void senderLimitedTxPool_derived() {
parseCommand("--tx-pool-limit-by-account-percentage=0.002");
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getTxPoolMaxFutureTransactionByAccount())
.isEqualTo(9);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void senderLimitedTxPoolFloor_derived() {
parseCommand("--tx-pool-limit-by-account-percentage=0.0001");
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getTxPoolMaxFutureTransactionByAccount())
.isEqualTo(1);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void senderLimitedTxPoolCeiling_violated() {
TestBesuCommand commandTest = parseCommand("--tx-pool-limit-by-account-percentage=1.00002341");
TransactionPoolOptions txPoolOption = commandTest.getTransactionPoolOptions();
final TransactionPoolConfiguration config = txPoolOption.toDomainObject().build();
assertThat(config.getTxPoolLimitByAccountPercentage())
.isEqualTo(TransactionPoolConfiguration.DEFAULT_LIMIT_TX_POOL_BY_ACCOUNT_PERCENTAGE);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains("Invalid value for option '--tx-pool-limit-by-account-percentage'");
}
@Test
public void pendingTransactionRetentionPeriod() {
final int pendingTxRetentionHours = 999;
parseCommand("--tx-pool-retention-hours", String.valueOf(pendingTxRetentionHours));
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getPendingTxRetentionPeriod())
.isEqualTo(pendingTxRetentionHours);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void transactionPoolPriceBump() {
final Percentage priceBump = Percentage.fromInt(13);
parseCommand("--tx-pool-price-bump", priceBump.toString());
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getPriceBump()).isEqualTo(priceBump);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void invalidTansactionPoolPriceBumpShouldFail() {
parseCommand("--tx-pool-price-bump", "101");
assertThat(commandErrorOutput.toString(UTF_8))
.contains(
"Invalid value for option '--tx-pool-price-bump'",
"should be a number between 0 and 100 inclusive");
}
@Test
public void transactionPoolTxFeeCap() {
final Wei txFeeCap = Wei.fromEth(2);
parseCommand("--rpc-tx-feecap", txFeeCap.toDecimalString());
verify(mockControllerBuilder)
.transactionPoolConfiguration(transactionPoolConfigCaptor.capture());
assertThat(transactionPoolConfigCaptor.getValue().getTxFeeCap()).isEqualTo(txFeeCap);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void invalidTansactionPoolTxFeeCapShouldFail() {
parseCommand("--rpc-tx-feecap", "abcd");
assertThat(commandErrorOutput.toString(UTF_8))
.contains("Invalid value for option '--rpc-tx-feecap'", "cannot convert 'abcd' to Wei");
}
@Test
public void txMessageKeepAliveSecondsWithInvalidInputShouldFail() {
parseCommand("--Xincoming-tx-messages-keep-alive-seconds", "acbd");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains(
"Invalid value for option '--Xincoming-tx-messages-keep-alive-seconds': 'acbd' is not an int");
}
@Test
public void eth65TrxAnnouncedBufferingPeriodWithInvalidInputShouldFail() {
parseCommand("--Xeth65-tx-announced-buffering-period-milliseconds", "acbd");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains(
"Invalid value for option '--Xeth65-tx-announced-buffering-period-milliseconds': 'acbd' is not a long");
}
@Test @Test
public void tomlThatHasInvalidOptions() throws IOException { public void tomlThatHasInvalidOptions() throws IOException {
final URL configFile = this.getClass().getResource("/complete_config.toml"); final URL configFile = this.getClass().getResource("/complete_config.toml");

@ -519,12 +519,7 @@ public abstract class CommandTestAbstract {
return unstableEthProtocolOptions; return unstableEthProtocolOptions;
} }
public org.hyperledger.besu.cli.options.stable.TransactionPoolOptions public TransactionPoolOptions getTransactionPoolOptions() {
getStableTransactionPoolOptions() {
return stableTransactionPoolOptions;
}
public TransactionPoolOptions getUnstableTransactionPoolOptions() {
return unstableTransactionPoolOptions; return unstableTransactionPoolOptions;
} }

@ -15,8 +15,6 @@
package org.hyperledger.besu.cli; package org.hyperledger.besu.cli;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import java.math.BigInteger; import java.math.BigInteger;
@ -147,16 +145,14 @@ class ConfigurationOverviewBuilderTest {
} }
@Test @Test
void setTxPoolImplementationLayered() { void setLayeredTxPoolEnabled() {
builder.setTxPoolImplementation(LAYERED); final String layeredTxPoolDisabled = builder.build();
final String layeredTxPoolSelected = builder.build(); assertThat(layeredTxPoolDisabled)
assertThat(layeredTxPoolSelected).contains("Using LAYERED transaction pool implementation"); .doesNotContain("Experimental layered transaction pool configuration enabled");
}
builder.setLayeredTxPoolEnabled();
@Test final String layeredTxPoolEnabled = builder.build();
void setTxPoolImplementationLegacy() { assertThat(layeredTxPoolEnabled)
builder.setTxPoolImplementation(LEGACY); .contains("Experimental layered transaction pool configuration enabled");
final String legacyTxPoolSelected = builder.build();
assertThat(legacyTxPoolSelected).contains("Using LEGACY transaction pool implementation");
} }
} }

@ -39,7 +39,7 @@ class NetworkDeprecationMessageTest {
@EnumSource( @EnumSource(
value = NetworkName.class, value = NetworkName.class,
names = { names = {
"MAINNET", "SEPOLIA", "GOERLI", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "MAINNET", "SEPOLIA", "GOERLI", "DEV", "CLASSIC", "KOTTI", "MORDOR", "HOLESKY",
}) })
void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) { void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) {
assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network)) assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network))

@ -18,7 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.Assertions.catchThrowable;
import org.hyperledger.besu.cli.converter.exception.FractionConversionException; import org.hyperledger.besu.cli.converter.exception.FractionConversionException;
import org.hyperledger.besu.util.number.Fraction;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -31,9 +30,9 @@ public class FractionConverterTest {
@Test @Test
public void assertThatConvertHandlesProperlyAValidString() throws FractionConversionException { public void assertThatConvertHandlesProperlyAValidString() throws FractionConversionException {
final Fraction fraction = fractionConverter.convert("0.58"); final float fraction = fractionConverter.convert("0.58");
assertThat(fraction).isNotNull(); assertThat(fraction).isNotNull();
assertThat(fraction.getValue()).isEqualTo(0.58f); assertThat(fraction).isEqualTo(0.58f);
} }
@Test @Test

@ -18,7 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.Assertions.catchThrowable;
import org.hyperledger.besu.cli.converter.exception.PercentageConversionException; import org.hyperledger.besu.cli.converter.exception.PercentageConversionException;
import org.hyperledger.besu.util.number.Percentage;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -31,9 +30,9 @@ public class PercentageConverterTest {
@Test @Test
public void assertThatConvertHandlesProperlyAValidString() throws PercentageConversionException { public void assertThatConvertHandlesProperlyAValidString() throws PercentageConversionException {
final Percentage percentage = percentageConverter.convert("58"); final int percentage = percentageConverter.convert("58");
assertThat(percentage).isNotNull(); assertThat(percentage).isNotNull();
assertThat(percentage.getValue()).isEqualTo(58); assertThat(percentage).isEqualTo(58);
} }
@Test @Test

@ -21,7 +21,6 @@ import org.hyperledger.besu.cli.CommandTestAbstract;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import org.junit.Test; import org.junit.Test;
@ -88,9 +87,9 @@ public abstract class AbstractCLIOptionsTest<D, T extends CLIOptions<D>>
.isEqualTo(defaultOptions); .isEqualTo(defaultOptions);
} }
protected abstract D createDefaultDomainObject(); abstract D createDefaultDomainObject();
protected abstract D createCustomizedDomainObject(); abstract D createCustomizedDomainObject();
protected List<String> getFieldsWithComputedDefaults() { protected List<String> getFieldsWithComputedDefaults() {
return Collections.emptyList(); return Collections.emptyList();
@ -100,25 +99,7 @@ public abstract class AbstractCLIOptionsTest<D, T extends CLIOptions<D>>
return Collections.emptyList(); return Collections.emptyList();
} }
protected abstract T optionsFromDomainObject(D domainObject); abstract T optionsFromDomainObject(D domainObject);
protected abstract T getOptionsFromBesuCommand(final TestBesuCommand besuCommand); abstract T getOptionsFromBesuCommand(final TestBesuCommand besuCommand);
protected void internalTestSuccess(final Consumer<D> assertion, final String... args) {
final TestBesuCommand cmd = parseCommand(args);
final T options = getOptionsFromBesuCommand(cmd);
final D config = options.toDomainObject();
assertion.accept(config);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
protected void internalTestFailure(final String errorMsg, final String... args) {
parseCommand(args);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).contains(errorMsg);
}
} }

@ -165,12 +165,12 @@ public class EthProtocolOptionsTest
} }
@Override @Override
protected EthProtocolConfiguration createDefaultDomainObject() { EthProtocolConfiguration createDefaultDomainObject() {
return EthProtocolConfiguration.builder().build(); return EthProtocolConfiguration.builder().build();
} }
@Override @Override
protected EthProtocolConfiguration createCustomizedDomainObject() { EthProtocolConfiguration createCustomizedDomainObject() {
return EthProtocolConfiguration.builder() return EthProtocolConfiguration.builder()
.maxMessageSize(EthProtocolConfiguration.DEFAULT_MAX_MESSAGE_SIZE * 2) .maxMessageSize(EthProtocolConfiguration.DEFAULT_MAX_MESSAGE_SIZE * 2)
.maxGetBlockHeaders(EthProtocolConfiguration.DEFAULT_MAX_GET_BLOCK_HEADERS + 2) .maxGetBlockHeaders(EthProtocolConfiguration.DEFAULT_MAX_GET_BLOCK_HEADERS + 2)
@ -184,13 +184,12 @@ public class EthProtocolOptionsTest
} }
@Override @Override
protected EthProtocolOptions optionsFromDomainObject( EthProtocolOptions optionsFromDomainObject(final EthProtocolConfiguration domainObject) {
final EthProtocolConfiguration domainObject) {
return EthProtocolOptions.fromConfig(domainObject); return EthProtocolOptions.fromConfig(domainObject);
} }
@Override @Override
protected EthProtocolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { EthProtocolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getEthProtocolOptions(); return besuCommand.getEthProtocolOptions();
} }
} }

@ -25,25 +25,24 @@ public class MetricsCLIOptionsTest
extends AbstractCLIOptionsTest<MetricsConfiguration.Builder, MetricsCLIOptions> { extends AbstractCLIOptionsTest<MetricsConfiguration.Builder, MetricsCLIOptions> {
@Override @Override
protected MetricsConfiguration.Builder createDefaultDomainObject() { MetricsConfiguration.Builder createDefaultDomainObject() {
return MetricsConfiguration.builder(); return MetricsConfiguration.builder();
} }
@Override @Override
protected MetricsConfiguration.Builder createCustomizedDomainObject() { MetricsConfiguration.Builder createCustomizedDomainObject() {
return MetricsConfiguration.builder() return MetricsConfiguration.builder()
.timersEnabled(!MetricsConfiguration.DEFAULT_METRICS_TIMERS_ENABLED) .timersEnabled(!MetricsConfiguration.DEFAULT_METRICS_TIMERS_ENABLED)
.idleTimeout(MetricsConfiguration.DEFAULT_METRICS_IDLE_TIMEOUT_SECONDS); .idleTimeout(MetricsConfiguration.DEFAULT_METRICS_IDLE_TIMEOUT_SECONDS);
} }
@Override @Override
protected MetricsCLIOptions optionsFromDomainObject( MetricsCLIOptions optionsFromDomainObject(final MetricsConfiguration.Builder domainObject) {
final MetricsConfiguration.Builder domainObject) {
return MetricsCLIOptions.fromConfiguration(domainObject.build()); return MetricsCLIOptions.fromConfiguration(domainObject.build());
} }
@Override @Override
protected MetricsCLIOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { MetricsCLIOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getMetricsCLIOptions(); return besuCommand.getMetricsCLIOptions();
} }
} }

@ -165,12 +165,12 @@ public class NetworkingOptionsTest
} }
@Override @Override
protected NetworkingConfiguration createDefaultDomainObject() { NetworkingConfiguration createDefaultDomainObject() {
return NetworkingConfiguration.create(); return NetworkingConfiguration.create();
} }
@Override @Override
protected NetworkingConfiguration createCustomizedDomainObject() { NetworkingConfiguration createCustomizedDomainObject() {
final NetworkingConfiguration config = NetworkingConfiguration.create(); final NetworkingConfiguration config = NetworkingConfiguration.create();
config.setInitiateConnectionsFrequency( config.setInitiateConnectionsFrequency(
NetworkingConfiguration.DEFAULT_INITIATE_CONNECTIONS_FREQUENCY_SEC + 10); NetworkingConfiguration.DEFAULT_INITIATE_CONNECTIONS_FREQUENCY_SEC + 10);
@ -181,12 +181,12 @@ public class NetworkingOptionsTest
} }
@Override @Override
protected NetworkingOptions optionsFromDomainObject(final NetworkingConfiguration domainObject) { NetworkingOptions optionsFromDomainObject(final NetworkingConfiguration domainObject) {
return NetworkingOptions.fromConfig(domainObject); return NetworkingOptions.fromConfig(domainObject);
} }
@Override @Override
protected NetworkingOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { NetworkingOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getNetworkingOptions(); return besuCommand.getNetworkingOptions();
} }

@ -104,25 +104,4 @@ public class OptionParserTest {
final String expected = "-1233"; final String expected = "-1233";
assertThat(OptionParser.format(input)).isEqualTo(expected); assertThat(OptionParser.format(input)).isEqualTo(expected);
} }
@Test
public void format_object_int() {
final Object input = 1233;
final String expected = "1233";
assertThat(OptionParser.format(input)).isEqualTo(expected);
}
@Test
public void format_object_Integer() {
final Object input = Integer.valueOf(1233);
final String expected = "1233";
assertThat(OptionParser.format(input)).isEqualTo(expected);
}
@Test
public void format_object_uint256() {
final Object input = UInt256.valueOf(new BigInteger("123456789", 10));
final String expected = "123456789";
assertThat(OptionParser.format(input)).isEqualTo(expected);
}
} }

@ -31,12 +31,12 @@ public class SynchronizerOptionsTest
extends AbstractCLIOptionsTest<SynchronizerConfiguration.Builder, SynchronizerOptions> { extends AbstractCLIOptionsTest<SynchronizerConfiguration.Builder, SynchronizerOptions> {
@Override @Override
protected SynchronizerConfiguration.Builder createDefaultDomainObject() { SynchronizerConfiguration.Builder createDefaultDomainObject() {
return SynchronizerConfiguration.builder(); return SynchronizerConfiguration.builder();
} }
@Override @Override
protected SynchronizerConfiguration.Builder createCustomizedDomainObject() { SynchronizerConfiguration.Builder createCustomizedDomainObject() {
return SynchronizerConfiguration.builder() return SynchronizerConfiguration.builder()
.fastSyncPivotDistance(SynchronizerConfiguration.DEFAULT_PIVOT_DISTANCE_FROM_HEAD + 10) .fastSyncPivotDistance(SynchronizerConfiguration.DEFAULT_PIVOT_DISTANCE_FROM_HEAD + 10)
.fastSyncFullValidationRate(SynchronizerConfiguration.DEFAULT_FULL_VALIDATION_RATE / 2) .fastSyncFullValidationRate(SynchronizerConfiguration.DEFAULT_FULL_VALIDATION_RATE / 2)
@ -87,7 +87,7 @@ public class SynchronizerOptionsTest
} }
@Override @Override
protected SynchronizerOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { SynchronizerOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getSynchronizerOptions(); return besuCommand.getSynchronizerOptions();
} }
@ -97,7 +97,7 @@ public class SynchronizerOptionsTest
} }
@Override @Override
protected SynchronizerOptions optionsFromDomainObject( SynchronizerOptions optionsFromDomainObject(
final SynchronizerConfiguration.Builder domainObject) { final SynchronizerConfiguration.Builder domainObject) {
return SynchronizerOptions.fromConfig(domainObject.build()); return SynchronizerOptions.fromConfig(domainObject.build());
} }

@ -0,0 +1,155 @@
/*
* Copyright ConsenSys AG.
*
* 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;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import java.time.Duration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class TransactionPoolOptionsTest
extends AbstractCLIOptionsTest<
ImmutableTransactionPoolConfiguration.Builder, TransactionPoolOptions> {
@Test
public void strictTxReplayProtection_enabled() {
final TestBesuCommand cmd = parseCommand("--strict-tx-replay-protection-enabled");
final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd);
final TransactionPoolConfiguration config = options.toDomainObject().build();
assertThat(config.getStrictTransactionReplayProtectionEnabled()).isTrue();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void strictTxReplayProtection_enabledWithBooleanArg() {
final TestBesuCommand cmd = parseCommand("--strict-tx-replay-protection-enabled=true");
final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd);
final TransactionPoolConfiguration config = options.toDomainObject().build();
assertThat(config.getStrictTransactionReplayProtectionEnabled()).isTrue();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void strictTxReplayProtection_disabled() {
final TestBesuCommand cmd = parseCommand("--strict-tx-replay-protection-enabled=false");
final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd);
final TransactionPoolConfiguration config = options.toDomainObject().build();
assertThat(config.getStrictTransactionReplayProtectionEnabled()).isFalse();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void strictTxReplayProtection_default() {
final TestBesuCommand cmd = parseCommand();
final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd);
final TransactionPoolConfiguration config = options.toDomainObject().build();
assertThat(config.getStrictTransactionReplayProtectionEnabled()).isFalse();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void txMessageKeepAliveSeconds() {
final int txMessageKeepAliveSeconds = 999;
final TestBesuCommand cmd =
parseCommand(
"--Xincoming-tx-messages-keep-alive-seconds",
String.valueOf(txMessageKeepAliveSeconds));
final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd);
final TransactionPoolConfiguration config = options.toDomainObject().build();
assertThat(config.getTxMessageKeepAliveSeconds()).isEqualTo(txMessageKeepAliveSeconds);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void eth65TrxAnnouncedBufferingPeriod() {
final long eth65TrxAnnouncedBufferingPeriod = 999;
final TestBesuCommand cmd =
parseCommand(
"--Xeth65-tx-announced-buffering-period-milliseconds",
String.valueOf(eth65TrxAnnouncedBufferingPeriod));
final TransactionPoolOptions options = getOptionsFromBesuCommand(cmd);
final TransactionPoolConfiguration config = options.toDomainObject().build();
assertThat(config.getEth65TrxAnnouncedBufferingPeriod())
.hasMillis(eth65TrxAnnouncedBufferingPeriod);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Override
ImmutableTransactionPoolConfiguration.Builder createDefaultDomainObject() {
final ImmutableTransactionPoolConfiguration defaultValue =
ImmutableTransactionPoolConfiguration.builder().build();
return ImmutableTransactionPoolConfiguration.builder()
.strictTransactionReplayProtectionEnabled(false)
.txMessageKeepAliveSeconds(defaultValue.getTxMessageKeepAliveSeconds())
.eth65TrxAnnouncedBufferingPeriod(defaultValue.getEth65TrxAnnouncedBufferingPeriod())
.layeredTxPoolEnabled(defaultValue.getLayeredTxPoolEnabled())
.pendingTransactionsLayerMaxCapacityBytes(
defaultValue.getPendingTransactionsLayerMaxCapacityBytes())
.maxPrioritizedTransactions(defaultValue.getMaxPrioritizedTransactions())
.maxFutureBySender(defaultValue.getMaxFutureBySender());
}
@Override
ImmutableTransactionPoolConfiguration.Builder createCustomizedDomainObject() {
return ImmutableTransactionPoolConfiguration.builder()
.strictTransactionReplayProtectionEnabled(true)
.txMessageKeepAliveSeconds(TransactionPoolConfiguration.DEFAULT_TX_MSG_KEEP_ALIVE + 1)
.eth65TrxAnnouncedBufferingPeriod(
TransactionPoolConfiguration.ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD.plus(
Duration.ofMillis(100)))
.layeredTxPoolEnabled(true)
.pendingTransactionsLayerMaxCapacityBytes(1_000_000L)
.maxPrioritizedTransactions(1000)
.maxFutureBySender(10);
}
@Override
TransactionPoolOptions optionsFromDomainObject(
final ImmutableTransactionPoolConfiguration.Builder domainObject) {
return TransactionPoolOptions.fromConfig(domainObject.build());
}
@Override
TransactionPoolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getTransactionPoolOptions();
}
}

@ -1,243 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY;
import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest;
import org.hyperledger.besu.cli.options.OptionParser;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.util.number.Percentage;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class TransactionPoolOptionsTest
extends AbstractCLIOptionsTest<TransactionPoolConfiguration, TransactionPoolOptions> {
@Test
public void strictTxReplayProtection_enabled() {
internalTestSuccess(
config -> assertThat(config.getStrictTransactionReplayProtectionEnabled()).isTrue(),
"--strict-tx-replay-protection-enabled");
}
@Test
public void strictTxReplayProtection_enabledWithBooleanArg() {
internalTestSuccess(
config -> assertThat(config.getStrictTransactionReplayProtectionEnabled()).isTrue(),
"--strict-tx-replay-protection-enabled=true");
}
@Test
public void strictTxReplayProtection_disabled() {
internalTestSuccess(
config -> assertThat(config.getStrictTransactionReplayProtectionEnabled()).isFalse(),
"--strict-tx-replay-protection-enabled=false");
}
@Test
public void strictTxReplayProtection_default() {
internalTestSuccess(
config -> assertThat(config.getStrictTransactionReplayProtectionEnabled()).isFalse());
}
@Test
public void pendingTransactionRetentionPeriod() {
final int pendingTxRetentionHours = 999;
internalTestSuccess(
config ->
assertThat(config.getPendingTxRetentionPeriod()).isEqualTo(pendingTxRetentionHours),
"--tx-pool-retention-hours",
String.valueOf(pendingTxRetentionHours),
"--tx-pool=legacy");
}
@Test
public void disableLocalsDefault() {
internalTestSuccess(config -> assertThat(config.getDisableLocalTransactions()).isFalse());
}
@Test
public void disableLocalsOn() {
internalTestSuccess(
config -> assertThat(config.getDisableLocalTransactions()).isTrue(),
"--tx-pool-disable-locals=true");
}
@Test
public void disableLocalsOff() {
internalTestSuccess(
config -> assertThat(config.getDisableLocalTransactions()).isFalse(),
"--tx-pool-disable-locals=false");
}
@Test
public void saveToFileDisabledByDefault() {
internalTestSuccess(config -> assertThat(config.getEnableSaveRestore()).isFalse());
}
@Test
public void saveToFileEnabledDefaultPath() {
internalTestSuccess(
config -> assertThat(config.getEnableSaveRestore()).isTrue(),
"--tx-pool-enable-save-restore=true");
}
@Test
public void saveToFileEnabledCustomPath() {
internalTestSuccess(
config -> {
assertThat(config.getEnableSaveRestore()).isTrue();
assertThat(config.getSaveFile()).hasName("my.save.file");
},
"--tx-pool-enable-save-restore=true",
"--tx-pool-save-file=my.save.file");
}
@Test
public void senderLimited_derived() {
internalTestSuccess(
config -> assertThat(config.getTxPoolMaxFutureTransactionByAccount()).isEqualTo(9),
"--tx-pool-limit-by-account-percentage=0.002",
"--tx-pool=legacy");
}
@Test
public void senderLimitedFloor_derived() {
internalTestSuccess(
config -> assertThat(config.getTxPoolMaxFutureTransactionByAccount()).isEqualTo(1),
"--tx-pool-limit-by-account-percentage=0.0001",
"--tx-pool=legacy");
}
@Test
public void senderLimitedCeiling_violated() {
internalTestFailure(
"Invalid value for option '--tx-pool-limit-by-account-percentage'",
"--tx-pool-limit-by-account-percentage=1.00002341",
"--tx-pool=legacy");
}
@Test
public void priceBump() {
final Percentage priceBump = Percentage.fromInt(13);
internalTestSuccess(
config -> assertThat(config.getPriceBump()).isEqualTo(priceBump),
"--tx-pool-price-bump",
priceBump.toString());
}
@Test
public void invalidPriceBumpShouldFail() {
internalTestFailure(
"Invalid value: 101, should be a number between 0 and 100 inclusive",
"--tx-pool-price-bump",
"101");
}
@Test
public void txFeeCap() {
final Wei txFeeCap = Wei.fromEth(2);
internalTestSuccess(
config -> assertThat(config.getTxFeeCap()).isEqualTo(txFeeCap),
"--rpc-tx-feecap",
OptionParser.format(txFeeCap));
}
@Test
public void invalidTxFeeCapShouldFail() {
internalTestFailure(
"Invalid value for option '--rpc-tx-feecap'",
"cannot convert 'abcd' to Wei",
"--rpc-tx-feecap",
"abcd");
}
@Test
public void selectLayeredImplementationByDefault() {
internalTestSuccess(config -> assertThat(config.getTxPoolImplementation()).isEqualTo(LAYERED));
}
@Test
public void selectLayeredImplementationByArg() {
internalTestSuccess(
config -> assertThat(config.getTxPoolImplementation()).isEqualTo(LAYERED),
"--tx-pool=layered");
}
@Test
public void selectLegacyImplementationByArg() {
internalTestSuccess(
config -> assertThat(config.getTxPoolImplementation()).isEqualTo(LEGACY),
"--tx-pool=legacy");
}
@Test
public void failIfLegacyOptionsWhenLayeredSelectedByDefault() {
internalTestFailure(
"Could not use legacy transaction pool options with layered implementation",
"--tx-pool-max-size=1000");
}
@Test
public void failIfLegacyOptionsWhenLayeredSelectedByArg() {
internalTestFailure(
"Could not use legacy transaction pool options with layered implementation",
"--tx-pool=layered",
"--tx-pool-max-size=1000");
}
@Test
public void failIfLayeredOptionsWhenLegacySelectedByArg() {
internalTestFailure(
"Could not use layered transaction pool options with legacy implementation",
"--tx-pool=legacy",
"--tx-pool-max-prioritized=1000");
}
@Override
protected TransactionPoolConfiguration createDefaultDomainObject() {
return TransactionPoolConfiguration.DEFAULT;
}
@Override
protected TransactionPoolConfiguration createCustomizedDomainObject() {
return ImmutableTransactionPoolConfiguration.builder()
.strictTransactionReplayProtectionEnabled(true)
.txPoolImplementation(LAYERED)
.pendingTransactionsLayerMaxCapacityBytes(1_000_000L)
.maxPrioritizedTransactions(1000)
.maxFutureBySender(10)
.build();
}
@Override
protected TransactionPoolOptions optionsFromDomainObject(
final TransactionPoolConfiguration domainObject) {
return TransactionPoolOptions.fromConfig(domainObject);
}
@Override
protected TransactionPoolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getStableTransactionPoolOptions();
}
}

@ -1,105 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.unstable;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.cli.converter.DurationMillisConverter;
import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import java.time.Duration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class TransactionPoolOptionsTest
extends AbstractCLIOptionsTest<TransactionPoolConfiguration.Unstable, TransactionPoolOptions> {
@Test
public void txMessageKeepAliveSeconds() {
final int txMessageKeepAliveSeconds = 999;
internalTestSuccess(
config ->
assertThat(config.getTxMessageKeepAliveSeconds()).isEqualTo(txMessageKeepAliveSeconds),
"--Xincoming-tx-messages-keep-alive-seconds",
String.valueOf(txMessageKeepAliveSeconds));
}
@Test
public void txMessageKeepAliveSecondsWithInvalidInputShouldFail() {
internalTestFailure(
"Invalid value for option '--Xincoming-tx-messages-keep-alive-seconds': 'acbd' is not an int",
"--Xincoming-tx-messages-keep-alive-seconds",
"acbd");
}
@Test
public void eth65TrxAnnouncedBufferingPeriod() {
final Duration eth65TrxAnnouncedBufferingPeriod = Duration.ofMillis(999);
internalTestSuccess(
config ->
assertThat(config.getEth65TrxAnnouncedBufferingPeriod())
.isEqualTo(eth65TrxAnnouncedBufferingPeriod),
"--Xeth65-tx-announced-buffering-period-milliseconds",
new DurationMillisConverter().format(eth65TrxAnnouncedBufferingPeriod));
}
@Test
public void eth65TrxAnnouncedBufferingPeriodWithInvalidInputShouldFail() {
internalTestFailure(
"Invalid value for option '--Xeth65-tx-announced-buffering-period-milliseconds': cannot convert 'acbd' to Duration (org.hyperledger.besu.cli.converter.exception.DurationConversionException: 'acbd' is not a long)",
"--Xeth65-tx-announced-buffering-period-milliseconds",
"acbd");
}
@Test
public void eth65TrxAnnouncedBufferingPeriodWithInvalidInputShouldFail2() {
internalTestFailure(
"Invalid value for option '--Xeth65-tx-announced-buffering-period-milliseconds': cannot convert '-1' to Duration (org.hyperledger.besu.cli.converter.exception.DurationConversionException: negative value '-1' is not allowed)",
"--Xeth65-tx-announced-buffering-period-milliseconds",
"-1");
}
@Override
protected TransactionPoolConfiguration.Unstable createDefaultDomainObject() {
return TransactionPoolConfiguration.Unstable.DEFAULT;
}
@Override
protected TransactionPoolConfiguration.Unstable createCustomizedDomainObject() {
return ImmutableTransactionPoolConfiguration.Unstable.builder()
.txMessageKeepAliveSeconds(
TransactionPoolConfiguration.Unstable.DEFAULT_TX_MSG_KEEP_ALIVE + 1)
.eth65TrxAnnouncedBufferingPeriod(
TransactionPoolConfiguration.Unstable.ETH65_TRX_ANNOUNCED_BUFFERING_PERIOD.plus(
Duration.ofMillis(100)))
.build();
}
@Override
protected TransactionPoolOptions optionsFromDomainObject(
final TransactionPoolConfiguration.Unstable domainObject) {
return TransactionPoolOptions.fromConfig(domainObject);
}
@Override
protected TransactionPoolOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getUnstableTransactionPoolOptions();
}
}

@ -15,6 +15,7 @@
package org.hyperledger.besu.controller; package org.hyperledger.besu.controller;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@ -54,7 +55,6 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage;
import java.math.BigInteger; import java.math.BigInteger;
@ -85,17 +85,16 @@ public class BesuControllerBuilderTest {
@Mock SynchronizerConfiguration synchronizerConfiguration; @Mock SynchronizerConfiguration synchronizerConfiguration;
@Mock EthProtocolConfiguration ethProtocolConfiguration; @Mock EthProtocolConfiguration ethProtocolConfiguration;
@Mock MiningParameters miningParameters; @Mock MiningParameters miningParameters;
@Mock ObservableMetricsSystem observableMetricsSystem;
@Mock PrivacyParameters privacyParameters; @Mock PrivacyParameters privacyParameters;
@Mock Clock clock; @Mock Clock clock;
@Mock TransactionPoolConfiguration poolConfiguration;
@Mock StorageProvider storageProvider; @Mock StorageProvider storageProvider;
@Mock GasLimitCalculator gasLimitCalculator; @Mock GasLimitCalculator gasLimitCalculator;
@Mock WorldStateStorage worldStateStorage; @Mock WorldStateStorage worldStateStorage;
@Mock WorldStateArchive worldStateArchive; @Mock WorldStateArchive worldStateArchive;
@Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage; @Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage;
@Mock WorldStatePreimageStorage worldStatePreimageStorage; @Mock WorldStatePreimageStorage worldStatePreimageStorage;
private final TransactionPoolConfiguration poolConfiguration =
TransactionPoolConfiguration.DEFAULT;
private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem();
BigInteger networkId = BigInteger.ONE; BigInteger networkId = BigInteger.ONE;
@ -128,6 +127,10 @@ public class BesuControllerBuilderTest {
when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L)); when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L));
when(observableMetricsSystem.createLabelledCounter(
any(), anyString(), anyString(), anyString()))
.thenReturn(labels -> null);
when(storageProvider.createWorldStateStorage(DataStorageFormat.FOREST)) when(storageProvider.createWorldStateStorage(DataStorageFormat.FOREST))
.thenReturn(worldStateStorage); .thenReturn(worldStateStorage);
when(storageProvider.createWorldStatePreimageStorage()).thenReturn(worldStatePreimageStorage); when(storageProvider.createWorldStatePreimageStorage()).thenReturn(worldStatePreimageStorage);

@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -57,7 +58,6 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage;
import java.math.BigInteger; import java.math.BigInteger;
@ -90,8 +90,10 @@ public class MergeBesuControllerBuilderTest {
@Mock EthProtocolConfiguration ethProtocolConfiguration; @Mock EthProtocolConfiguration ethProtocolConfiguration;
@Mock CheckpointConfigOptions checkpointConfigOptions; @Mock CheckpointConfigOptions checkpointConfigOptions;
@Mock MiningParameters miningParameters; @Mock MiningParameters miningParameters;
@Mock ObservableMetricsSystem observableMetricsSystem;
@Mock PrivacyParameters privacyParameters; @Mock PrivacyParameters privacyParameters;
@Mock Clock clock; @Mock Clock clock;
@Mock TransactionPoolConfiguration poolConfiguration;
@Mock StorageProvider storageProvider; @Mock StorageProvider storageProvider;
@Mock GasLimitCalculator gasLimitCalculator; @Mock GasLimitCalculator gasLimitCalculator;
@Mock WorldStateStorage worldStateStorage; @Mock WorldStateStorage worldStateStorage;
@ -100,9 +102,6 @@ public class MergeBesuControllerBuilderTest {
BigInteger networkId = BigInteger.ONE; BigInteger networkId = BigInteger.ONE;
private final BlockHeaderTestFixture headerGenerator = new BlockHeaderTestFixture(); private final BlockHeaderTestFixture headerGenerator = new BlockHeaderTestFixture();
private final BaseFeeMarket feeMarket = new LondonFeeMarket(0, Optional.of(Wei.of(42))); private final BaseFeeMarket feeMarket = new LondonFeeMarket(0, Optional.of(Wei.of(42)));
private final TransactionPoolConfiguration poolConfiguration =
TransactionPoolConfiguration.DEFAULT;
private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem();
@Rule public final TemporaryFolder tempDirRule = new TemporaryFolder(); @Rule public final TemporaryFolder tempDirRule = new TemporaryFolder();
@ -135,6 +134,10 @@ public class MergeBesuControllerBuilderTest {
when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L)); when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L));
when(observableMetricsSystem.createLabelledCounter(
any(), anyString(), anyString(), anyString()))
.thenReturn(labels -> null);
when(storageProvider.createWorldStateStorage(DataStorageFormat.FOREST)) when(storageProvider.createWorldStateStorage(DataStorageFormat.FOREST))
.thenReturn(worldStateStorage); .thenReturn(worldStateStorage);
when(storageProvider.createWorldStatePreimageStorage()).thenReturn(worldStatePreimageStorage); when(storageProvider.createWorldStatePreimageStorage()).thenReturn(worldStatePreimageStorage);

@ -17,6 +17,7 @@ package org.hyperledger.besu.controller;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -52,7 +53,6 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage;
import java.math.BigInteger; import java.math.BigInteger;
@ -80,17 +80,16 @@ public class QbftBesuControllerBuilderTest {
@Mock private EthProtocolConfiguration ethProtocolConfiguration; @Mock private EthProtocolConfiguration ethProtocolConfiguration;
@Mock CheckpointConfigOptions checkpointConfigOptions; @Mock CheckpointConfigOptions checkpointConfigOptions;
@Mock private MiningParameters miningParameters; @Mock private MiningParameters miningParameters;
@Mock private ObservableMetricsSystem observableMetricsSystem;
@Mock private PrivacyParameters privacyParameters; @Mock private PrivacyParameters privacyParameters;
@Mock private Clock clock; @Mock private Clock clock;
@Mock private TransactionPoolConfiguration poolConfiguration;
@Mock private StorageProvider storageProvider; @Mock private StorageProvider storageProvider;
@Mock private GasLimitCalculator gasLimitCalculator; @Mock private GasLimitCalculator gasLimitCalculator;
@Mock private WorldStateStorage worldStateStorage; @Mock private WorldStateStorage worldStateStorage;
@Mock private WorldStatePreimageStorage worldStatePreimageStorage; @Mock private WorldStatePreimageStorage worldStatePreimageStorage;
private static final BigInteger networkId = BigInteger.ONE; private static final BigInteger networkId = BigInteger.ONE;
private static final NodeKey nodeKey = NodeKeyUtils.generate(); private static final NodeKey nodeKey = NodeKeyUtils.generate();
private final TransactionPoolConfiguration poolConfiguration =
TransactionPoolConfiguration.DEFAULT;
private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem();
@Rule public final TemporaryFolder tempDirRule = new TemporaryFolder(); @Rule public final TemporaryFolder tempDirRule = new TemporaryFolder();
@ -121,7 +120,9 @@ public class QbftBesuControllerBuilderTest {
when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1); when(synchronizerConfiguration.getDownloaderParallelism()).thenReturn(1);
when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1); when(synchronizerConfiguration.getTransactionsParallelism()).thenReturn(1);
when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1); when(synchronizerConfiguration.getComputationParallelism()).thenReturn(1);
when(observableMetricsSystem.createLabelledCounter(
any(), anyString(), anyString(), anyString()))
.thenReturn(labels -> null);
when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L)); when(synchronizerConfiguration.getBlockPropagationRange()).thenReturn(Range.closed(1L, 2L));
// qbft prepForBuild setup // qbft prepForBuild setup

@ -109,6 +109,25 @@ public class DefaultDiscoveryConfiguration {
"enode://5cd218959f8263bc3721d7789070806b0adff1a0ed3f95ec886fb469f9362c7507e3b32b256550b9a7964a23a938e8d42d45a0c34b332bfebc54b29081e83b93@35.187.57.94:30303") "enode://5cd218959f8263bc3721d7789070806b0adff1a0ed3f95ec886fb469f9362c7507e3b32b256550b9a7964a23a938e8d42d45a0c34b332bfebc54b29081e83b93@35.187.57.94:30303")
.map(EnodeURLImpl::fromString) .map(EnodeURLImpl::fromString)
.collect(toList())); .collect(toList()));
public static final List<EnodeURL> KOTTI_BOOTSTRAP_NODES =
Collections.unmodifiableList(
Stream.of(
// Authority Nodes
"enode://a59e33ccd2b3e52d578f1fbd70c6f9babda2650f0760d6ff3b37742fdcdfdb3defba5d56d315b40c46b70198c7621e63ffa3f987389c7118634b0fefbbdfa7fd@51.158.191.43:37956", // @q9f Mizar
"enode://93c94e999be5dd854c5d82a7cf5c14822973b5d9badb56ad4974586ec4d4f1995c815af795c20bb6e0a6226d3ee55808435c4dc89baf94ee581141b064d19dfc@80.187.116.161:25720",
"enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303",
"enode://b477ca6d507a3f57070783eb62ba838847635f8b1a0cbffb8b7f8173f5894cf550f0225a5c279341e2d862a606e778b57180a4f1db3db78c51eadcfa4fdc6963@40.68.240.160:30303",
// @q9f Bootnodes
"enode://4956f6924335c951cb70cbc169a85c081f6ff0b374aa2815453b8a3132b49613f38a1a6b8e103f878dbec86364f60091e92a376d7cd3aca9d82d2f2554794e63@51.15.97.240:41235", // @q9f Ginan
"enode://6c9a052c01bb9995fa53bebfcdbc17733fe90708270d0e6d8e38dc57b32e1dbe8c287590b634ee9753b94ba302f411c96519c7fa07df0df6a6848149d819b2c5@51.15.70.7:41235", // @q9f Polis
"enode://95a7302fd8f35d9ad716a591b90dfe839dbf2d3d6a6737ef39e07899f844ad82f1659dd6212492922dd36705fb0a1e984c1d5d5c42069d5bd329388831e820c1@51.15.97.240:45678", // @q9f Ginan
"enode://8c5c4dec9a0728c7058d3c29698bae888adc244e443cebc21f3d708a20751511acbf98a52b5e5ea472f8715c658913e8084123461fd187a4980a0600420b0791@51.15.70.7:45678", // @q9f Polis
"enode://efd7391a3bed73ad74ae5760319bb48f9c9f1983ff22964422688cdb426c5d681004ece26c47121396653cf9bafe7104aa4ecff70e24cc5b11fd76be8e5afce0@51.158.191.43:45678", // @q9f Mizar
"enode://93b12383c74c39b67afa99a7ff44ce250fe94295fa1fc087465cc4fe2d0b33b91a8d8cabe03b250104a9096aa0e06bcde5f95665a5bd9f890edd2ab33e16ae47@51.15.41.19:30303" // @q9f Zibal
)
.map(EnodeURLImpl::fromString)
.collect(toList()));
public static final List<EnodeURL> MORDOR_BOOTSTRAP_NODES = public static final List<EnodeURL> MORDOR_BOOTSTRAP_NODES =
Collections.unmodifiableList( Collections.unmodifiableList(
Stream.of( Stream.of(

@ -1,211 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.services;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.worldstate.WorldView;
import org.hyperledger.besu.plugin.services.TraceService;
import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
class TraceServiceImplTest {
TraceService traceService;
private MutableBlockchain blockchain;
private WorldStateArchive worldStateArchive;
private BlockchainQueries blockchainQueries;
/**
* The blockchain for testing has a height of 32 and the account
* 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b makes a transaction per block. So, in the head, the
* nonce of this account should be 32.
*/
@BeforeEach
public void setup() {
final BlockchainSetupUtil blockchainSetupUtil =
BlockchainSetupUtil.forTesting(DataStorageFormat.BONSAI);
blockchainSetupUtil.importAllBlocks();
blockchain = blockchainSetupUtil.getBlockchain();
worldStateArchive = blockchainSetupUtil.getWorldArchive();
blockchainQueries = new BlockchainQueries(blockchain, worldStateArchive);
traceService =
new TraceServiceImpl(blockchainQueries, blockchainSetupUtil.getProtocolSchedule());
}
@Test
void shouldRetrieveStateUpdatePostTracingForOneBlock() {
final Address addressToVerify =
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
final long persistedNonceForAccount =
worldStateArchive.getMutable().get(addressToVerify).getNonce();
traceService.trace(
2,
2,
worldState -> {
assertThat(worldState.get(addressToVerify).getNonce()).isEqualTo(1);
},
worldState -> {
assertThat(worldState.get(addressToVerify).getNonce()).isEqualTo(2);
},
BlockAwareOperationTracer.NO_TRACING);
assertThat(worldStateArchive.getMutable().get(addressToVerify).getNonce())
.isEqualTo(persistedNonceForAccount);
}
@Test
void shouldRetrieveStateUpdatePostTracingForAllBlocks() {
final Address addressToVerify =
Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
final long persistedNonceForAccount =
worldStateArchive.getMutable().get(addressToVerify).getNonce();
traceService.trace(
0,
32,
worldState -> {
assertThat(worldState.get(addressToVerify).getNonce()).isEqualTo(0);
},
worldState -> {
assertThat(worldState.get(addressToVerify).getNonce())
.isEqualTo(persistedNonceForAccount);
},
BlockAwareOperationTracer.NO_TRACING);
assertThat(worldStateArchive.getMutable().get(addressToVerify).getNonce())
.isEqualTo(persistedNonceForAccount);
}
@Test
void shouldReturnTheCorrectWorldViewForTxStartEnd() {
final TxStartEndTracer txStartEndTracer = new TxStartEndTracer();
// block contains 1 transaction
traceService.traceBlock(31, txStartEndTracer);
assertThat(txStartEndTracer.txStartWorldView).isNotNull();
assertThat(txStartEndTracer.txEndWorldView).isNotNull();
assertThat(txStartEndTracer.txStartTransaction.getNonce())
.isEqualTo(txStartEndTracer.txEndTransaction.getNonce())
.isEqualTo(30);
assertThat(txStartEndTracer.txStartTransaction.getGasLimit())
.isEqualTo(txStartEndTracer.txEndTransaction.getGasLimit())
.isEqualTo(314159);
assertThat(txStartEndTracer.txStartTransaction.getTo().get())
.isEqualTo(txStartEndTracer.txEndTransaction.getTo().get())
.isEqualTo(Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"));
assertThat(txStartEndTracer.txStartTransaction.getValue())
.isEqualTo(txStartEndTracer.txEndTransaction.getValue())
.isEqualTo(
Wei.fromHexString(
"0x000000000000000000000000000000000000000000000000000000000000000a"));
assertThat(txStartEndTracer.txStartTransaction.getPayload())
.isEqualTo(txStartEndTracer.txEndTransaction.getPayload())
.isEqualTo(Bytes.fromHexString("0xfd408767"));
assertThat(txStartEndTracer.txEndStatus).isTrue();
assertThat(txStartEndTracer.txEndOutput).isEqualTo(Bytes.fromHexString("0x"));
assertThat(txStartEndTracer.txEndGasUsed).isEqualTo(24303);
assertThat(txStartEndTracer.txEndTimeNs).isNotNull();
assertThat(txStartEndTracer.txEndLogs).isNotEmpty();
final Log actualLog = txStartEndTracer.txEndLogs.get(0);
assertThat(actualLog.getLogger())
.isEqualTo(Address.fromHexString("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"));
assertThat(actualLog.getData())
.isEqualTo(
Bytes.fromHexString(
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9000000000000000000000000000000000000000000000000000000000000002a"));
assertThat(actualLog.getTopics()).hasSize(4);
assertThat(actualLog.getTopics().get(0))
.isEqualTo(
Bytes.fromHexString(
"0xd5f0a30e4be0c6be577a71eceb7464245a796a7e6a55c0d971837b250de05f4e"));
assertThat(actualLog.getTopics().get(1))
.isEqualTo(
Bytes.fromHexString(
"0x0000000000000000000000000000000000000000000000000000000000000001"));
assertThat(actualLog.getTopics().get(2))
.isEqualTo(
Bytes.fromHexString(
"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"));
assertThat(actualLog.getTopics().get(3))
.isEqualTo(
Bytes.fromHexString(
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
}
private static class TxStartEndTracer implements BlockAwareOperationTracer {
public WorldView txStartWorldView;
public WorldView txEndWorldView;
public Transaction txStartTransaction;
public Transaction txEndTransaction;
public boolean txEndStatus;
public Bytes txEndOutput;
public List<Log> txEndLogs;
public long txEndGasUsed;
public Long txEndTimeNs;
@Override
public void traceStartTransaction(final WorldView worldView, final Transaction transaction) {
txStartWorldView = worldView;
txStartTransaction = transaction;
}
@Override
public void traceEndTransaction(
final WorldView worldView,
final Transaction transaction,
final boolean status,
final Bytes output,
final List<Log> logs,
final long gasUsed,
final long timeNs) {
txEndWorldView = worldView;
txEndTransaction = transaction;
txEndStatus = status;
txEndOutput = output;
txEndLogs = logs;
txEndGasUsed = gasUsed;
txEndTimeNs = timeNs;
}
}
}

@ -170,21 +170,16 @@ privacy-onchain-groups-enabled=false
privacy-flexible-groups-enabled=false privacy-flexible-groups-enabled=false
# Transaction Pool # Transaction Pool
tx-pool="layered" tx-pool-retention-hours=999
tx-pool-price-bump=13 tx-pool-price-bump=13
tx-pool-max-size=1234
tx-pool-limit-by-account-percentage=0.017
Xincoming-tx-messages-keep-alive-seconds=60
rpc-tx-feecap=2000000000000000000 rpc-tx-feecap=2000000000000000000
strict-tx-replay-protection-enabled=true strict-tx-replay-protection-enabled=true
tx-pool-disable-locals=false tx-pool-disable-locals=false
tx-pool-enable-save-restore=true tx-pool-enable-save-restore=true
tx-pool-save-file="txpool.dump" tx-pool-save-file="txpool.dump"
## Layered
tx-pool-layer-max-capacity=12345678
tx-pool-max-prioritized=9876
tx-pool-max-future-by-sender=321
## Legacy
tx-pool-retention-hours=999
tx-pool-max-size=1234
tx-pool-limit-by-account-percentage=0.017
# Revert Reason # Revert Reason
revert-reason-enabled=false revert-reason-enabled=false

@ -551,22 +551,6 @@ def tweakStartScript(createScriptTask) {
} }
startScripts { startScripts {
defaultJvmOpts = applicationDefaultJvmArgs + [
"-XX:G1ConcRefinementThreads=2",
"-XX:G1HeapWastePercent=15",
"-XX:MaxGCPauseMillis=100"
]
unixStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/unixStartScript.txt")
windowsStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/windowsStartScript.txt")
doLast { tweakStartScript(startScripts) }
}
task untunedStartScripts(type: CreateStartScripts) {
mainClass = 'org.hyperledger.besu.Besu'
classpath = startScripts.classpath
outputDir = startScripts.outputDir
applicationName = 'besu-untuned'
defaultJvmOpts = applicationDefaultJvmArgs
unixStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/unixStartScript.txt") unixStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/unixStartScript.txt")
windowsStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/windowsStartScript.txt") windowsStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/windowsStartScript.txt")
doLast { tweakStartScript(startScripts) } doLast { tweakStartScript(startScripts) }
@ -603,10 +587,10 @@ task autocomplete(type: JavaExec) {
} }
} }
installDist { dependsOn checkLicenses, untunedStartScripts, evmToolStartScripts } installDist { dependsOn checkLicenses, evmToolStartScripts }
distTar { distTar {
dependsOn checkLicenses, autocomplete, untunedStartScripts, evmToolStartScripts dependsOn checkLicenses, autocomplete, evmToolStartScripts
doFirst { doFirst {
delete fileTree(dir: 'build/distributions', include: '*.tar.gz') delete fileTree(dir: 'build/distributions', include: '*.tar.gz')
} }
@ -615,7 +599,7 @@ distTar {
} }
distZip { distZip {
dependsOn checkLicenses, autocomplete, untunedStartScripts, evmToolStartScripts dependsOn checkLicenses, autocomplete, evmToolStartScripts
doFirst { doFirst {
delete fileTree(dir: 'build/distributions', include: '*.zip') delete fileTree(dir: 'build/distributions', include: '*.zip')
} }

@ -0,0 +1,815 @@
{
"config": {
"chainId": 6,
"ecip1041Block": 0,
"atlantisBlock": 716617,
"aghartaBlock": 1705549,
"phoenixBlock": 2200013,
"magnetoBlock": 4368634,
"mystiqueBlock": 5578000,
"clique":{
"blockperiodseconds":15,
"epochlength":30000
},
"discovery": {
"bootnodes": [
"enode://a59e33ccd2b3e52d578f1fbd70c6f9babda2650f0760d6ff3b37742fdcdfdb3defba5d56d315b40c46b70198c7621e63ffa3f987389c7118634b0fefbbdfa7fd@51.158.191.43:37956",
"enode://93c94e999be5dd854c5d82a7cf5c14822973b5d9badb56ad4974586ec4d4f1995c815af795c20bb6e0a6226d3ee55808435c4dc89baf94ee581141b064d19dfc@80.187.116.161:25720",
"enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303",
"enode://b477ca6d507a3f57070783eb62ba838847635f8b1a0cbffb8b7f8173f5894cf550f0225a5c279341e2d862a606e778b57180a4f1db3db78c51eadcfa4fdc6963@40.68.240.160:30303",
"enode://4956f6924335c951cb70cbc169a85c081f6ff0b374aa2815453b8a3132b49613f38a1a6b8e103f878dbec86364f60091e92a376d7cd3aca9d82d2f2554794e63@51.15.97.240:41235",
"enode://6c9a052c01bb9995fa53bebfcdbc17733fe90708270d0e6d8e38dc57b32e1dbe8c287590b634ee9753b94ba302f411c96519c7fa07df0df6a6848149d819b2c5@51.15.70.7:41235",
"enode://95a7302fd8f35d9ad716a591b90dfe839dbf2d3d6a6737ef39e07899f844ad82f1659dd6212492922dd36705fb0a1e984c1d5d5c42069d5bd329388831e820c1@51.15.97.240:45678",
"enode://8c5c4dec9a0728c7058d3c29698bae888adc244e443cebc21f3d708a20751511acbf98a52b5e5ea472f8715c658913e8084123461fd187a4980a0600420b0791@51.15.70.7:45678",
"enode://efd7391a3bed73ad74ae5760319bb48f9c9f1983ff22964422688cdb426c5d681004ece26c47121396653cf9bafe7104aa4ecff70e24cc5b11fd76be8e5afce0@51.158.191.43:45678",
"enode://93b12383c74c39b67afa99a7ff44ce250fe94295fa1fc087465cc4fe2d0b33b91a8d8cabe03b250104a9096aa0e06bcde5f95665a5bd9f890edd2ab33e16ae47@51.15.41.19:30303"
]
}
},
"nonce": "0x0",
"timestamp": "0x5c2d2287",
"extraData": "0x000000000000000000000000000000000000000000000000000000000000000025b7955e43adf9c2a01a9475908702cce67f302a6aaf8cba3c9255a2b863415d4db7bae4f4bbca020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0xa00000",
"difficulty": "0x1",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"0000000000000000000000000000000000000000": {
"balance": "0x1"
},
"0000000000000000000000000000000000000001": {
"balance": "0x1"
},
"0000000000000000000000000000000000000002": {
"balance": "0x1"
},
"0000000000000000000000000000000000000003": {
"balance": "0x1"
},
"0000000000000000000000000000000000000004": {
"balance": "0x1"
},
"0000000000000000000000000000000000000005": {
"balance": "0x1"
},
"0000000000000000000000000000000000000006": {
"balance": "0x1"
},
"0000000000000000000000000000000000000007": {
"balance": "0x1"
},
"0000000000000000000000000000000000000008": {
"balance": "0x1"
},
"0000000000000000000000000000000000000009": {
"balance": "0x1"
},
"000000000000000000000000000000000000000a": {
"balance": "0x1"
},
"000000000000000000000000000000000000000b": {
"balance": "0x1"
},
"000000000000000000000000000000000000000c": {
"balance": "0x1"
},
"000000000000000000000000000000000000000d": {
"balance": "0x1"
},
"000000000000000000000000000000000000000e": {
"balance": "0x1"
},
"000000000000000000000000000000000000000f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000010": {
"balance": "0x1"
},
"0000000000000000000000000000000000000011": {
"balance": "0x1"
},
"0000000000000000000000000000000000000012": {
"balance": "0x1"
},
"0000000000000000000000000000000000000013": {
"balance": "0x1"
},
"0000000000000000000000000000000000000014": {
"balance": "0x1"
},
"0000000000000000000000000000000000000015": {
"balance": "0x1"
},
"0000000000000000000000000000000000000016": {
"balance": "0x1"
},
"0000000000000000000000000000000000000017": {
"balance": "0x1"
},
"0000000000000000000000000000000000000018": {
"balance": "0x1"
},
"0000000000000000000000000000000000000019": {
"balance": "0x1"
},
"000000000000000000000000000000000000001a": {
"balance": "0x1"
},
"000000000000000000000000000000000000001b": {
"balance": "0x1"
},
"000000000000000000000000000000000000001c": {
"balance": "0x1"
},
"000000000000000000000000000000000000001d": {
"balance": "0x1"
},
"000000000000000000000000000000000000001e": {
"balance": "0x1"
},
"000000000000000000000000000000000000001f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000020": {
"balance": "0x1"
},
"0000000000000000000000000000000000000021": {
"balance": "0x1"
},
"0000000000000000000000000000000000000022": {
"balance": "0x1"
},
"0000000000000000000000000000000000000023": {
"balance": "0x1"
},
"0000000000000000000000000000000000000024": {
"balance": "0x1"
},
"0000000000000000000000000000000000000025": {
"balance": "0x1"
},
"0000000000000000000000000000000000000026": {
"balance": "0x1"
},
"0000000000000000000000000000000000000027": {
"balance": "0x1"
},
"0000000000000000000000000000000000000028": {
"balance": "0x1"
},
"0000000000000000000000000000000000000029": {
"balance": "0x1"
},
"000000000000000000000000000000000000002a": {
"balance": "0x1"
},
"000000000000000000000000000000000000002b": {
"balance": "0x1"
},
"000000000000000000000000000000000000002c": {
"balance": "0x1"
},
"000000000000000000000000000000000000002d": {
"balance": "0x1"
},
"000000000000000000000000000000000000002e": {
"balance": "0x1"
},
"000000000000000000000000000000000000002f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000030": {
"balance": "0x1"
},
"0000000000000000000000000000000000000031": {
"balance": "0x1"
},
"0000000000000000000000000000000000000032": {
"balance": "0x1"
},
"0000000000000000000000000000000000000033": {
"balance": "0x1"
},
"0000000000000000000000000000000000000034": {
"balance": "0x1"
},
"0000000000000000000000000000000000000035": {
"balance": "0x1"
},
"0000000000000000000000000000000000000036": {
"balance": "0x1"
},
"0000000000000000000000000000000000000037": {
"balance": "0x1"
},
"0000000000000000000000000000000000000038": {
"balance": "0x1"
},
"0000000000000000000000000000000000000039": {
"balance": "0x1"
},
"000000000000000000000000000000000000003a": {
"balance": "0x1"
},
"000000000000000000000000000000000000003b": {
"balance": "0x1"
},
"000000000000000000000000000000000000003c": {
"balance": "0x1"
},
"000000000000000000000000000000000000003d": {
"balance": "0x1"
},
"000000000000000000000000000000000000003e": {
"balance": "0x1"
},
"000000000000000000000000000000000000003f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000040": {
"balance": "0x1"
},
"0000000000000000000000000000000000000041": {
"balance": "0x1"
},
"0000000000000000000000000000000000000042": {
"balance": "0x1"
},
"0000000000000000000000000000000000000043": {
"balance": "0x1"
},
"0000000000000000000000000000000000000044": {
"balance": "0x1"
},
"0000000000000000000000000000000000000045": {
"balance": "0x1"
},
"0000000000000000000000000000000000000046": {
"balance": "0x1"
},
"0000000000000000000000000000000000000047": {
"balance": "0x1"
},
"0000000000000000000000000000000000000048": {
"balance": "0x1"
},
"0000000000000000000000000000000000000049": {
"balance": "0x1"
},
"000000000000000000000000000000000000004a": {
"balance": "0x1"
},
"000000000000000000000000000000000000004b": {
"balance": "0x1"
},
"000000000000000000000000000000000000004c": {
"balance": "0x1"
},
"000000000000000000000000000000000000004d": {
"balance": "0x1"
},
"000000000000000000000000000000000000004e": {
"balance": "0x1"
},
"000000000000000000000000000000000000004f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000050": {
"balance": "0x1"
},
"0000000000000000000000000000000000000051": {
"balance": "0x1"
},
"0000000000000000000000000000000000000052": {
"balance": "0x1"
},
"0000000000000000000000000000000000000053": {
"balance": "0x1"
},
"0000000000000000000000000000000000000054": {
"balance": "0x1"
},
"0000000000000000000000000000000000000055": {
"balance": "0x1"
},
"0000000000000000000000000000000000000056": {
"balance": "0x1"
},
"0000000000000000000000000000000000000057": {
"balance": "0x1"
},
"0000000000000000000000000000000000000058": {
"balance": "0x1"
},
"0000000000000000000000000000000000000059": {
"balance": "0x1"
},
"000000000000000000000000000000000000005a": {
"balance": "0x1"
},
"000000000000000000000000000000000000005b": {
"balance": "0x1"
},
"000000000000000000000000000000000000005c": {
"balance": "0x1"
},
"000000000000000000000000000000000000005d": {
"balance": "0x1"
},
"000000000000000000000000000000000000005e": {
"balance": "0x1"
},
"000000000000000000000000000000000000005f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000060": {
"balance": "0x1"
},
"0000000000000000000000000000000000000061": {
"balance": "0x1"
},
"0000000000000000000000000000000000000062": {
"balance": "0x1"
},
"0000000000000000000000000000000000000063": {
"balance": "0x1"
},
"0000000000000000000000000000000000000064": {
"balance": "0x1"
},
"0000000000000000000000000000000000000065": {
"balance": "0x1"
},
"0000000000000000000000000000000000000066": {
"balance": "0x1"
},
"0000000000000000000000000000000000000067": {
"balance": "0x1"
},
"0000000000000000000000000000000000000068": {
"balance": "0x1"
},
"0000000000000000000000000000000000000069": {
"balance": "0x1"
},
"000000000000000000000000000000000000006a": {
"balance": "0x1"
},
"000000000000000000000000000000000000006b": {
"balance": "0x1"
},
"000000000000000000000000000000000000006c": {
"balance": "0x1"
},
"000000000000000000000000000000000000006d": {
"balance": "0x1"
},
"000000000000000000000000000000000000006e": {
"balance": "0x1"
},
"000000000000000000000000000000000000006f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000070": {
"balance": "0x1"
},
"0000000000000000000000000000000000000071": {
"balance": "0x1"
},
"0000000000000000000000000000000000000072": {
"balance": "0x1"
},
"0000000000000000000000000000000000000073": {
"balance": "0x1"
},
"0000000000000000000000000000000000000074": {
"balance": "0x1"
},
"0000000000000000000000000000000000000075": {
"balance": "0x1"
},
"0000000000000000000000000000000000000076": {
"balance": "0x1"
},
"0000000000000000000000000000000000000077": {
"balance": "0x1"
},
"0000000000000000000000000000000000000078": {
"balance": "0x1"
},
"0000000000000000000000000000000000000079": {
"balance": "0x1"
},
"000000000000000000000000000000000000007a": {
"balance": "0x1"
},
"000000000000000000000000000000000000007b": {
"balance": "0x1"
},
"000000000000000000000000000000000000007c": {
"balance": "0x1"
},
"000000000000000000000000000000000000007d": {
"balance": "0x1"
},
"000000000000000000000000000000000000007e": {
"balance": "0x1"
},
"000000000000000000000000000000000000007f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000080": {
"balance": "0x1"
},
"0000000000000000000000000000000000000081": {
"balance": "0x1"
},
"0000000000000000000000000000000000000082": {
"balance": "0x1"
},
"0000000000000000000000000000000000000083": {
"balance": "0x1"
},
"0000000000000000000000000000000000000084": {
"balance": "0x1"
},
"0000000000000000000000000000000000000085": {
"balance": "0x1"
},
"0000000000000000000000000000000000000086": {
"balance": "0x1"
},
"0000000000000000000000000000000000000087": {
"balance": "0x1"
},
"0000000000000000000000000000000000000088": {
"balance": "0x1"
},
"0000000000000000000000000000000000000089": {
"balance": "0x1"
},
"000000000000000000000000000000000000008a": {
"balance": "0x1"
},
"000000000000000000000000000000000000008b": {
"balance": "0x1"
},
"000000000000000000000000000000000000008c": {
"balance": "0x1"
},
"000000000000000000000000000000000000008d": {
"balance": "0x1"
},
"000000000000000000000000000000000000008e": {
"balance": "0x1"
},
"000000000000000000000000000000000000008f": {
"balance": "0x1"
},
"0000000000000000000000000000000000000090": {
"balance": "0x1"
},
"0000000000000000000000000000000000000091": {
"balance": "0x1"
},
"0000000000000000000000000000000000000092": {
"balance": "0x1"
},
"0000000000000000000000000000000000000093": {
"balance": "0x1"
},
"0000000000000000000000000000000000000094": {
"balance": "0x1"
},
"0000000000000000000000000000000000000095": {
"balance": "0x1"
},
"0000000000000000000000000000000000000096": {
"balance": "0x1"
},
"0000000000000000000000000000000000000097": {
"balance": "0x1"
},
"0000000000000000000000000000000000000098": {
"balance": "0x1"
},
"0000000000000000000000000000000000000099": {
"balance": "0x1"
},
"000000000000000000000000000000000000009a": {
"balance": "0x1"
},
"000000000000000000000000000000000000009b": {
"balance": "0x1"
},
"000000000000000000000000000000000000009c": {
"balance": "0x1"
},
"000000000000000000000000000000000000009d": {
"balance": "0x1"
},
"000000000000000000000000000000000000009e": {
"balance": "0x1"
},
"000000000000000000000000000000000000009f": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000a9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000aa": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ab": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ac": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ad": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ae": {
"balance": "0x1"
},
"00000000000000000000000000000000000000af": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000b9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ba": {
"balance": "0x1"
},
"00000000000000000000000000000000000000bb": {
"balance": "0x1"
},
"00000000000000000000000000000000000000bc": {
"balance": "0x1"
},
"00000000000000000000000000000000000000bd": {
"balance": "0x1"
},
"00000000000000000000000000000000000000be": {
"balance": "0x1"
},
"00000000000000000000000000000000000000bf": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000c9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ca": {
"balance": "0x1"
},
"00000000000000000000000000000000000000cb": {
"balance": "0x1"
},
"00000000000000000000000000000000000000cc": {
"balance": "0x1"
},
"00000000000000000000000000000000000000cd": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ce": {
"balance": "0x1"
},
"00000000000000000000000000000000000000cf": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000d9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000da": {
"balance": "0x1"
},
"00000000000000000000000000000000000000db": {
"balance": "0x1"
},
"00000000000000000000000000000000000000dc": {
"balance": "0x1"
},
"00000000000000000000000000000000000000dd": {
"balance": "0x1"
},
"00000000000000000000000000000000000000de": {
"balance": "0x1"
},
"00000000000000000000000000000000000000df": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000e9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ea": {
"balance": "0x1"
},
"00000000000000000000000000000000000000eb": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ec": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ed": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ee": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ef": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f0": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f1": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f2": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f3": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f4": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f5": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f6": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f7": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f8": {
"balance": "0x1"
},
"00000000000000000000000000000000000000f9": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fa": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fb": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fc": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fd": {
"balance": "0x1"
},
"00000000000000000000000000000000000000fe": {
"balance": "0x1"
},
"00000000000000000000000000000000000000ff": {
"balance": "0x1"
},
"25b7955e43adf9c2a01a9475908702cce67f302a": {
"balance": "0x84595161401484a000000"
},
"6aaf8cba3c9255a2b863415d4db7bae4f4bbca02": {
"balance": "0x4a723dc6b40b8a9a000000"
}
},
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}

@ -65,7 +65,6 @@ public class MigratingMiningCoordinator implements MiningCoordinator, BlockAdded
} }
private void startActiveMiningCoordinator() { private void startActiveMiningCoordinator() {
activeMiningCoordinator.enable();
activeMiningCoordinator.start(); activeMiningCoordinator.start();
if (activeMiningCoordinator instanceof BlockAddedObserver) { if (activeMiningCoordinator instanceof BlockAddedObserver) {
((BlockAddedObserver) activeMiningCoordinator).removeObserver(); ((BlockAddedObserver) activeMiningCoordinator).removeObserver();

@ -46,9 +46,7 @@ public class BftMiningCoordinator implements MiningCoordinator, BlockAddedObserv
/** Running state. */ /** Running state. */
RUNNING, RUNNING,
/** Stopped state. */ /** Stopped state. */
STOPPED, STOPPED
/** Paused state. */
PAUSED,
} }
private static final Logger LOG = LoggerFactory.getLogger(BftMiningCoordinator.class); private static final Logger LOG = LoggerFactory.getLogger(BftMiningCoordinator.class);
@ -63,7 +61,7 @@ public class BftMiningCoordinator implements MiningCoordinator, BlockAddedObserv
private final BftExecutors bftExecutors; private final BftExecutors bftExecutors;
private long blockAddedObserverId; private long blockAddedObserverId;
private final AtomicReference<State> state = new AtomicReference<>(State.PAUSED); private final AtomicReference<State> state = new AtomicReference<>(State.IDLE);
/** /**
* Instantiates a new Bft mining coordinator. * Instantiates a new Bft mining coordinator.
@ -124,14 +122,8 @@ public class BftMiningCoordinator implements MiningCoordinator, BlockAddedObserv
@Override @Override
public boolean enable() { public boolean enable() {
// Return true if we're already running or idle, or successfully switch to idle
if (state.get() == State.RUNNING
|| state.get() == State.IDLE
|| state.compareAndSet(State.PAUSED, State.IDLE)) {
return true; return true;
} }
return false;
}
@Override @Override
public boolean disable() { public boolean disable() {

@ -75,7 +75,6 @@ public class BftMiningCoordinatorTest {
bftMiningCoordinator.stop(); bftMiningCoordinator.stop();
verify(bftProcessor, never()).stop(); verify(bftProcessor, never()).stop();
bftMiningCoordinator.enable();
bftMiningCoordinator.start(); bftMiningCoordinator.start();
bftMiningCoordinator.stop(); bftMiningCoordinator.stop();
verify(bftProcessor).stop(); verify(bftProcessor).stop();

@ -254,12 +254,7 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
final PayloadIdentifier payloadIdentifier = final PayloadIdentifier payloadIdentifier =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
parentHeader.getBlockHash(), parentHeader.getBlockHash(), timestamp, prevRandao, feeRecipient, withdrawals);
timestamp,
prevRandao,
feeRecipient,
withdrawals,
parentBeaconBlockRoot);
if (blockCreationTasks.containsKey(payloadIdentifier)) { if (blockCreationTasks.containsKey(payloadIdentifier)) {
LOG.debug( LOG.debug(

@ -62,7 +62,6 @@ public class PayloadIdentifier implements Quantity {
* @param prevRandao the prev randao * @param prevRandao the prev randao
* @param feeRecipient the fee recipient * @param feeRecipient the fee recipient
* @param withdrawals the withdrawals * @param withdrawals the withdrawals
* @param parentBeaconBlockRoot the parent beacon block root
* @return the payload identifier * @return the payload identifier
*/ */
public static PayloadIdentifier forPayloadParams( public static PayloadIdentifier forPayloadParams(
@ -70,8 +69,7 @@ public class PayloadIdentifier implements Quantity {
final Long timestamp, final Long timestamp,
final Bytes32 prevRandao, final Bytes32 prevRandao,
final Address feeRecipient, final Address feeRecipient,
final Optional<List<Withdrawal>> withdrawals, final Optional<List<Withdrawal>> withdrawals) {
final Optional<Bytes32> parentBeaconBlockRoot) {
return new PayloadIdentifier( return new PayloadIdentifier(
timestamp timestamp
@ -86,8 +84,7 @@ public class PayloadIdentifier implements Quantity {
.sorted(Comparator.comparing(Withdrawal::getIndex)) .sorted(Comparator.comparing(Withdrawal::getIndex))
.map(Withdrawal::hashCode) .map(Withdrawal::hashCode)
.reduce(1, (a, b) -> a ^ (b * 31))) .reduce(1, (a, b) -> a ^ (b * 31)))
.orElse(0) .orElse(0));
^ ((long) parentBeaconBlockRoot.hashCode()) << 40);
} }
@Override @Override

@ -76,7 +76,6 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.metrics.StubMetricsSystem; import org.hyperledger.besu.metrics.StubMetricsSystem;
import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.testutil.TestClock;
import org.hyperledger.besu.util.number.Fraction;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.ArrayList; import java.util.ArrayList;
@ -162,7 +161,7 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper {
private final TransactionPoolConfiguration poolConf = private final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder() ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(10) .txPoolMaxSize(10)
.txPoolLimitByAccountPercentage(Fraction.fromPercentage(100)) .txPoolLimitByAccountPercentage(100.0f)
.build(); .build();
private final BaseFeePendingTransactionsSorter transactions = private final BaseFeePendingTransactionsSorter transactions =
new BaseFeePendingTransactionsSorter( new BaseFeePendingTransactionsSorter(

@ -48,12 +48,7 @@ public class PayloadIdentifierTest {
public void conversionCoverage() { public void conversionCoverage() {
var idTest = var idTest =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 1337L, Bytes32.random(), Address.fromHexString("0x42"), Optional.empty());
1337L,
Bytes32.random(),
Address.fromHexString("0x42"),
Optional.empty(),
Optional.empty());
assertThat(new PayloadIdentifier(idTest.getAsBigInteger().longValue())).isEqualTo(idTest); assertThat(new PayloadIdentifier(idTest.getAsBigInteger().longValue())).isEqualTo(idTest);
assertThat(new PayloadIdentifier(idTest.getAsBigInteger().longValue())).isEqualTo(idTest); assertThat(new PayloadIdentifier(idTest.getAsBigInteger().longValue())).isEqualTo(idTest);
} }
@ -87,20 +82,10 @@ public class PayloadIdentifierTest {
final Bytes32 prevRandao = Bytes32.random(); final Bytes32 prevRandao = Bytes32.random();
var idForWithdrawals1 = var idForWithdrawals1 =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(withdrawals1));
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.of(withdrawals1),
Optional.empty());
var idForWithdrawals2 = var idForWithdrawals2 =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(withdrawals2));
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.of(withdrawals2),
Optional.empty());
assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2); assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2);
} }
@ -133,20 +118,10 @@ public class PayloadIdentifierTest {
final Bytes32 prevRandao = Bytes32.random(); final Bytes32 prevRandao = Bytes32.random();
var idForWithdrawals1 = var idForWithdrawals1 =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(withdrawals1));
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.of(withdrawals1),
Optional.empty());
var idForWithdrawals2 = var idForWithdrawals2 =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(withdrawals2));
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.of(withdrawals2),
Optional.empty());
assertThat(idForWithdrawals1).isEqualTo(idForWithdrawals2); assertThat(idForWithdrawals1).isEqualTo(idForWithdrawals2);
} }
@ -155,64 +130,10 @@ public class PayloadIdentifierTest {
final Bytes32 prevRandao = Bytes32.random(); final Bytes32 prevRandao = Bytes32.random();
var idForWithdrawals1 = var idForWithdrawals1 =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.empty());
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.empty(),
Optional.empty());
var idForWithdrawals2 = var idForWithdrawals2 =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 1337L, prevRandao, Address.fromHexString("0x42"), Optional.of(emptyList()));
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.of(emptyList()),
Optional.empty());
assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2);
}
@Test
public void emptyOptionalAndNonEmptyParentBeaconBlockRootYieldDifferentHash() {
final Bytes32 prevRandao = Bytes32.random();
var idForWithdrawals1 =
PayloadIdentifier.forPayloadParams(
Hash.ZERO,
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.empty(),
Optional.empty());
var idForWithdrawals2 =
PayloadIdentifier.forPayloadParams(
Hash.ZERO,
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.empty(),
Optional.of(Bytes32.ZERO));
assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2);
}
@Test
public void differentParentBeaconBlockRootYieldDifferentHash() {
final Bytes32 prevRandao = Bytes32.random();
var idForWithdrawals1 =
PayloadIdentifier.forPayloadParams(
Hash.ZERO,
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.empty(),
Optional.of(Bytes32.fromHexStringLenient("0x1")));
var idForWithdrawals2 =
PayloadIdentifier.forPayloadParams(
Hash.ZERO,
1337L,
prevRandao,
Address.fromHexString("0x42"),
Optional.empty(),
Optional.of(Bytes32.ZERO));
assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2); assertThat(idForWithdrawals1).isNotEqualTo(idForWithdrawals2);
} }
} }

@ -59,24 +59,28 @@ public class Address extends DelegatingBytes {
public static final Address BLAKE2B_F_COMPRESSION = Address.precompiled(0x09); public static final Address BLAKE2B_F_COMPRESSION = Address.precompiled(0x09);
/** The constant KZG_POINT_EVAL aka POINT_EVALUATION_PRECOMPILE_ADDRESS. */ /** The constant KZG_POINT_EVAL aka POINT_EVALUATION_PRECOMPILE_ADDRESS. */
public static final Address KZG_POINT_EVAL = Address.precompiled(0xA); public static final Address KZG_POINT_EVAL = Address.precompiled(0xA);
/** The constant PARENT_BEACON_BLOCK_ROOT_REGISTRY aka HISTORY_STORAGE_ADDRESS. */
public static final Address PARENT_BEACON_BLOCK_ROOT_REGISTRY = Address.precompiled(0xB);
// TODO: this is not a precompile anymore. The address is correct for testnet 8. Fix after testnet
// 8 when we know what the real address is
/** The constant BLS12_G1ADD. */ /** The constant BLS12_G1ADD. */
public static final Address BLS12_G1ADD = Address.precompiled(0xB); public static final Address BLS12_G1ADD = Address.precompiled(0xC);
/** The constant BLS12_G1MUL. */ /** The constant BLS12_G1MUL. */
public static final Address BLS12_G1MUL = Address.precompiled(0xC); public static final Address BLS12_G1MUL = Address.precompiled(0xD);
/** The constant BLS12_G1MULTIEXP. */ /** The constant BLS12_G1MULTIEXP. */
public static final Address BLS12_G1MULTIEXP = Address.precompiled(0xD); public static final Address BLS12_G1MULTIEXP = Address.precompiled(0xE);
/** The constant BLS12_G2ADD. */ /** The constant BLS12_G2ADD. */
public static final Address BLS12_G2ADD = Address.precompiled(0xE); public static final Address BLS12_G2ADD = Address.precompiled(0xF);
/** The constant BLS12_G2MUL. */ /** The constant BLS12_G2MUL. */
public static final Address BLS12_G2MUL = Address.precompiled(0xF); public static final Address BLS12_G2MUL = Address.precompiled(0x10);
/** The constant BLS12_G2MULTIEXP. */ /** The constant BLS12_G2MULTIEXP. */
public static final Address BLS12_G2MULTIEXP = Address.precompiled(0x10); public static final Address BLS12_G2MULTIEXP = Address.precompiled(0x11);
/** The constant BLS12_PAIRING. */ /** The constant BLS12_PAIRING. */
public static final Address BLS12_PAIRING = Address.precompiled(0x11); public static final Address BLS12_PAIRING = Address.precompiled(0x12);
/** The constant BLS12_MAP_FP_TO_G1. */ /** The constant BLS12_MAP_FP_TO_G1. */
public static final Address BLS12_MAP_FP_TO_G1 = Address.precompiled(0x12); public static final Address BLS12_MAP_FP_TO_G1 = Address.precompiled(0x13);
/** The constant BLS12_MAP_FP2_TO_G2. */ /** The constant BLS12_MAP_FP2_TO_G2. */
public static final Address BLS12_MAP_FP2_TO_G2 = Address.precompiled(0x13); public static final Address BLS12_MAP_FP2_TO_G2 = Address.precompiled(0x14);
/** The constant ZERO. */ /** The constant ZERO. */
public static final Address ZERO = Address.fromHexString("0x0"); public static final Address ZERO = Address.fromHexString("0x0");

@ -38,15 +38,11 @@ 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) {
throw new InvalidParameterException(
"There needs to be a minimum of one blob in a blob transaction with commitments");
}
if (blobs.size() != kzgCommitments.size() if (blobs.size() != kzgCommitments.size()
|| blobs.size() != kzgProofs.size() || blobs.size() != kzgProofs.size()
|| blobs.size() != versionedHashes.size()) { || kzgCommitments.size() != versionedHashes.size()) {
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 and proofs");
} }
this.kzgCommitments = kzgCommitments; this.kzgCommitments = kzgCommitments;
this.blobs = blobs; this.blobs = blobs;

@ -22,70 +22,19 @@ import java.security.InvalidParameterException;
import java.util.List; import java.util.List;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class BlobsWithCommitmentsTest { public class BlobsWithCommitmentsTest {
@Test @Test
public void blobsWithCommitmentsMustHaveAtLeastOneBlob() { public void blobsWithCommitmentsMustHaveSameNumberOfElements() {
String actualMessage =
assertThrows(
InvalidParameterException.class,
() -> new BlobsWithCommitments(List.of(), List.of(), List.of(), List.of()))
.getMessage();
final String expectedMessage =
"There needs to be a minimum of one blob in a blob transaction with commitments";
assertThat(actualMessage).isEqualTo(expectedMessage);
}
@Test
public void blobsWithCommitmentsMustHaveSameNumberOfElementsVersionedHashes() {
String actualMessage =
assertThrows(
InvalidParameterException.class,
() ->
new BlobsWithCommitments(
List.of(new KZGCommitment(Bytes.of(1))),
List.of(new Blob(Bytes.EMPTY)),
List.of(new KZGProof(Bytes.EMPTY)),
List.of()))
.getMessage();
final String expectedMessage =
"There must be an equal number of blobs, commitments, proofs, and versioned hashes";
assertThat(actualMessage).isEqualTo(expectedMessage);
}
@Test
public void blobsWithCommitmentsMustHaveSameNumberOfElementsKZGCommitment() {
String actualMessage =
assertThrows(
InvalidParameterException.class,
() ->
new BlobsWithCommitments(
List.of(),
List.of(new Blob(Bytes.EMPTY)),
List.of(new KZGProof(Bytes.EMPTY)),
List.of(new VersionedHash(Bytes32.rightPad(Bytes.fromHexString("0x01"))))))
.getMessage();
final String expectedMessage =
"There must be an equal number of blobs, commitments, proofs, and versioned hashes";
assertThat(actualMessage).isEqualTo(expectedMessage);
}
@Test
public void blobsWithCommitmentsMustHaveSameNumberOfElementsKZGProof() {
String actualMessage = String actualMessage =
assertThrows( assertThrows(
InvalidParameterException.class, InvalidParameterException.class,
() -> () ->
new BlobsWithCommitments( new BlobsWithCommitments(
List.of(new KZGCommitment(Bytes.of(1))), List.of(new KZGCommitment(Bytes.of(1))), List.of(), List.of(), List.of()))
List.of(new Blob(Bytes.EMPTY)),
List.of(),
List.of(new VersionedHash(Bytes32.rightPad(Bytes.fromHexString("0x01"))))))
.getMessage(); .getMessage();
final String expectedMessage = final String expectedMessage = "There must be an equal number of blobs, commitments and proofs";
"There must be an equal number of blobs, commitments, proofs, and versioned hashes";
assertThat(actualMessage).isEqualTo(expectedMessage); assertThat(actualMessage).isEqualTo(expectedMessage);
} }
} }

@ -33,9 +33,6 @@ import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.JWTOptions; import io.vertx.ext.auth.JWTOptions;
import io.vertx.ext.auth.User; import io.vertx.ext.auth.User;
import io.vertx.ext.auth.authentication.AuthenticationProvider; import io.vertx.ext.auth.authentication.AuthenticationProvider;
import io.vertx.ext.auth.authentication.Credentials;
import io.vertx.ext.auth.authentication.TokenCredentials;
import io.vertx.ext.auth.authentication.UsernamePasswordCredentials;
import io.vertx.ext.auth.jwt.JWTAuth; import io.vertx.ext.auth.jwt.JWTAuth;
import io.vertx.ext.auth.jwt.JWTAuthOptions; import io.vertx.ext.auth.jwt.JWTAuthOptions;
import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.RoutingContext;
@ -169,7 +166,7 @@ public class DefaultAuthenticationService implements AuthenticationService {
private void login( private void login(
final RoutingContext routingContext, final AuthenticationProvider credentialAuthProvider) { final RoutingContext routingContext, final AuthenticationProvider credentialAuthProvider) {
final JsonObject requestBody = routingContext.body().asJsonObject(); final JsonObject requestBody = routingContext.getBodyAsJson();
if (requestBody == null) { if (requestBody == null) {
routingContext routingContext
@ -184,10 +181,8 @@ public class DefaultAuthenticationService implements AuthenticationService {
final JsonObject authParams = new JsonObject(); final JsonObject authParams = new JsonObject();
authParams.put(USERNAME, requestBody.getValue(USERNAME)); authParams.put(USERNAME, requestBody.getValue(USERNAME));
authParams.put("password", requestBody.getValue("password")); authParams.put("password", requestBody.getValue("password"));
final Credentials credentials = new UsernamePasswordCredentials(authParams);
credentialAuthProvider.authenticate( credentialAuthProvider.authenticate(
credentials, authParams,
r -> { r -> {
if (r.failed()) { if (r.failed()) {
routingContext routingContext
@ -232,7 +227,7 @@ public class DefaultAuthenticationService implements AuthenticationService {
try { try {
getJwtAuthProvider() getJwtAuthProvider()
.authenticate( .authenticate(
new TokenCredentials(new JsonObject().put("token", token)), new JsonObject().put("token", token),
r -> { r -> {
if (r.succeeded()) { if (r.succeeded()) {
final Optional<User> user = Optional.ofNullable(r.result()); final Optional<User> user = Optional.ofNullable(r.result());

@ -199,11 +199,6 @@ public class TraceBlock extends AbstractBlockParameterMethod {
this.worldState = worldState; this.worldState = worldState;
} }
public ChainUpdater(final MutableWorldState worldState, final WorldUpdater updater) {
this.worldState = worldState;
this.updater = updater;
}
public WorldUpdater getNextUpdater() { public WorldUpdater getNextUpdater() {
// if we have no prior updater, it must be the first TX, so use the block's initial state // if we have no prior updater, it must be the first TX, so use the block's initial state
if (updater == null) { if (updater == null) {

@ -219,14 +219,9 @@ public abstract class AbstractEngineForkchoiceUpdated extends ExecutionEngineJso
return false; return false;
} }
if (payloadAttributes.getTimestamp() < cancunTimestamp) { if (payloadAttributes.getTimestamp() < cancunTimestamp) {
if (payloadAttributes.getParentBeaconBlockRoot() != null) { LOG.warn("Payload attributes are present before cancun hardfork");
LOG.error(
"Parent beacon block root hash present in payload attributes before cancun hardfork");
return false;
}
} else if (payloadAttributes.getParentBeaconBlockRoot() == null) { } else if (payloadAttributes.getParentBeaconBlockRoot() == null) {
LOG.error( LOG.warn("Parent beacon block root not present in payload attributes after cancun hardfork");
"Parent beacon block root hash not present in payload attributes after cancun hardfork");
return false; return false;
} }
if (!getWithdrawalsValidator( if (!getWithdrawalsValidator(

@ -50,7 +50,6 @@ import org.hyperledger.besu.ethereum.core.Deposit;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
@ -171,7 +170,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
transactions = transactions =
blockParam.getTransactions().stream() blockParam.getTransactions().stream()
.map(Bytes::fromHexString) .map(Bytes::fromHexString)
.map(in -> TransactionDecoder.decodeOpaqueBytes(in, EncodingContext.BLOCK_BODY)) .map(TransactionDecoder::decodeOpaqueBytes)
.collect(Collectors.toList()); .collect(Collectors.toList());
} catch (final RLPException | IllegalArgumentException e) { } catch (final RLPException | IllegalArgumentException e) {
return respondWithInvalid( return respondWithInvalid(
@ -210,7 +209,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
blockParam.getPrevRandao(), blockParam.getPrevRandao(),
0, 0,
maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null), maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null),
blockParam.getBlobGasUsed(), blockParam.getBlobGasUsed() == null ? null : blockParam.getBlobGasUsed(),
blockParam.getExcessBlobGas() == null blockParam.getExcessBlobGas() == null
? null ? null
: BlobGas.fromHexString(blockParam.getExcessBlobGas()), : BlobGas.fromHexString(blockParam.getExcessBlobGas()),

@ -69,7 +69,8 @@ public class TransactionTracer {
final Hash blockHash, final Hash blockHash,
final Hash transactionHash, final Hash transactionHash,
final DebugOperationTracer tracer) { final DebugOperationTracer tracer) {
return blockReplay.beforeTransactionInBlock( Optional<TransactionTrace> transactionTrace =
blockReplay.beforeTransactionInBlock(
mutableWorldState, mutableWorldState,
blockHash, blockHash,
transactionHash, transactionHash,
@ -85,6 +86,7 @@ public class TransactionTracer {
blobGasPrice); blobGasPrice);
return new TransactionTrace(transaction, result, tracer.getTraceFrames()); return new TransactionTrace(transaction, result, tracer.getTraceFrames());
}); });
return transactionTrace;
} }
public List<String> traceTransactionToFile( public List<String> traceTransactionToFile(
@ -137,7 +139,7 @@ public class TransactionTracer {
stackedUpdater, stackedUpdater,
transaction, transaction,
transactionProcessor, transactionProcessor,
new StandardJsonTracer(out, showMemory, true, true, false), new StandardJsonTracer(out, showMemory, true, true),
blobGasPrice); blobGasPrice);
out.println( out.println(
summaryTrace( summaryTrace(

@ -24,7 +24,6 @@ import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockValueCalculator; import org.hyperledger.besu.ethereum.core.BlockValueCalculator;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import java.util.ArrayList; import java.util.ArrayList;
@ -96,9 +95,7 @@ public class BlockResultFactory {
public EngineGetPayloadResultV1 payloadTransactionCompleteV1(final Block block) { public EngineGetPayloadResultV1 payloadTransactionCompleteV1(final Block block) {
final List<String> txs = final List<String> txs =
block.getBody().getTransactions().stream() block.getBody().getTransactions().stream()
.map( .map(TransactionEncoder::encodeOpaqueBytes)
transaction ->
TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY))
.map(Bytes::toHexString) .map(Bytes::toHexString)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -109,9 +106,7 @@ public class BlockResultFactory {
final BlockWithReceipts blockWithReceipts) { final BlockWithReceipts blockWithReceipts) {
final List<String> txs = final List<String> txs =
blockWithReceipts.getBlock().getBody().getTransactions().stream() blockWithReceipts.getBlock().getBody().getTransactions().stream()
.map( .map(TransactionEncoder::encodeOpaqueBytes)
transaction ->
TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY))
.map(Bytes::toHexString) .map(Bytes::toHexString)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -137,9 +132,7 @@ public class BlockResultFactory {
final BlockWithReceipts blockWithReceipts) { final BlockWithReceipts blockWithReceipts) {
final List<String> txs = final List<String> txs =
blockWithReceipts.getBlock().getBody().getTransactions().stream() blockWithReceipts.getBlock().getBody().getTransactions().stream()
.map( .map(TransactionEncoder::encodeOpaqueBytes)
transaction ->
TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY))
.map(Bytes::toHexString) .map(Bytes::toHexString)
.collect(Collectors.toList()); .collect(Collectors.toList());

@ -16,7 +16,6 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter;
import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import java.util.Collections; import java.util.Collections;
@ -53,9 +52,7 @@ public class EngineGetPayloadBodiesResultV1 {
public PayloadBody(final BlockBody blockBody) { public PayloadBody(final BlockBody blockBody) {
this.transactions = this.transactions =
blockBody.getTransactions().stream() blockBody.getTransactions().stream()
.map( .map(TransactionEncoder::encodeOpaqueBytes)
transaction ->
TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY))
.map(Bytes::toHexString) .map(Bytes::toHexString)
.collect(Collectors.toList()); .collect(Collectors.toList());
this.withdrawals = this.withdrawals =

@ -20,7 +20,6 @@ import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import java.util.List; import java.util.List;
@ -100,9 +99,7 @@ public class TransactionPendingResult implements TransactionResult {
this.input = transaction.getPayload().toString(); this.input = transaction.getPayload().toString();
this.nonce = Quantity.create(transaction.getNonce()); this.nonce = Quantity.create(transaction.getNonce());
this.publicKey = transaction.getPublicKey().orElse(null); this.publicKey = transaction.getPublicKey().orElse(null);
this.raw = this.raw = TransactionEncoder.encodeOpaqueBytes(transaction).toString();
TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.POOLED_TRANSACTION)
.toString();
this.to = transaction.getTo().map(Address::toHexString).orElse(null); this.to = transaction.getTo().map(Address::toHexString).orElse(null);
this.type = this.type =
transactionType.equals(TransactionType.FRONTIER) transactionType.equals(TransactionType.FRONTIER)

@ -16,7 +16,6 @@ package org.hyperledger.besu.ethereum.api.util;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder;
import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPException;
@ -28,7 +27,7 @@ public class DomainObjectDecodeUtils {
throws InvalidJsonRpcRequestException { throws InvalidJsonRpcRequestException {
try { try {
Bytes txnBytes = Bytes.fromHexString(rawTransaction); Bytes txnBytes = Bytes.fromHexString(rawTransaction);
return TransactionDecoder.decodeOpaqueBytes(txnBytes, EncodingContext.POOLED_TRANSACTION); return TransactionDecoder.decodeOpaqueBytes(txnBytes);
} catch (final IllegalArgumentException e) { } catch (final IllegalArgumentException e) {
throw new InvalidJsonRpcRequestException("Invalid raw transaction hex", e); throw new InvalidJsonRpcRequestException("Invalid raw transaction hex", e);
} catch (final RLPException r) { } catch (final RLPException r) {

@ -242,7 +242,6 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
payloadParams.getTimestamp(), payloadParams.getTimestamp(),
payloadParams.getPrevRandao(), payloadParams.getPrevRandao(),
payloadParams.getSuggestedFeeRecipient(), payloadParams.getSuggestedFeeRecipient(),
Optional.empty(),
Optional.empty()); Optional.empty());
when(mergeCoordinator.preparePayload( when(mergeCoordinator.preparePayload(
@ -519,7 +518,6 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
payloadParams.getTimestamp(), payloadParams.getTimestamp(),
payloadParams.getPrevRandao(), payloadParams.getPrevRandao(),
payloadParams.getSuggestedFeeRecipient(), payloadParams.getSuggestedFeeRecipient(),
Optional.empty(),
Optional.empty()); Optional.empty());
when(mergeCoordinator.preparePayload( when(mergeCoordinator.preparePayload(
@ -605,8 +603,7 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
payloadParams.getTimestamp(), payloadParams.getTimestamp(),
payloadParams.getPrevRandao(), payloadParams.getPrevRandao(),
payloadParams.getSuggestedFeeRecipient(), payloadParams.getSuggestedFeeRecipient(),
withdrawals, withdrawals);
Optional.empty());
when(mergeCoordinator.preparePayload( when(mergeCoordinator.preparePayload(
mockHeader, mockHeader,
@ -648,7 +645,6 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
payloadParams.getTimestamp(), payloadParams.getTimestamp(),
payloadParams.getPrevRandao(), payloadParams.getPrevRandao(),
payloadParams.getSuggestedFeeRecipient(), payloadParams.getSuggestedFeeRecipient(),
Optional.empty(),
Optional.empty()); Optional.empty());
when(mergeCoordinator.preparePayload( when(mergeCoordinator.preparePayload(

@ -85,12 +85,7 @@ public abstract class AbstractEngineGetPayloadTest extends AbstractScheduledApiT
protected static final BlockResultFactory factory = new BlockResultFactory(); protected static final BlockResultFactory factory = new BlockResultFactory();
protected static final PayloadIdentifier mockPid = protected static final PayloadIdentifier mockPid =
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 1337L, Bytes32.random(), Address.fromHexString("0x42"), Optional.empty());
1337L,
Bytes32.random(),
Address.fromHexString("0x42"),
Optional.empty(),
Optional.empty());
protected static final BlockHeader mockHeader = protected static final BlockHeader mockHeader =
new BlockHeaderTestFixture().prevRandao(Bytes32.random()).buildHeader(); new BlockHeaderTestFixture().prevRandao(Bytes32.random()).buildHeader();
private static final Block mockBlock = private static final Block mockBlock =
@ -152,12 +147,7 @@ public abstract class AbstractEngineGetPayloadTest extends AbstractScheduledApiT
resp( resp(
getMethodName(), getMethodName(),
PayloadIdentifier.forPayloadParams( PayloadIdentifier.forPayloadParams(
Hash.ZERO, Hash.ZERO, 0L, Bytes32.random(), Address.fromHexString("0x42"), Optional.empty()));
0L,
Bytes32.random(),
Address.fromHexString("0x42"),
Optional.empty(),
Optional.empty()));
assertThat(resp).isInstanceOf(JsonRpcErrorResponse.class); assertThat(resp).isInstanceOf(JsonRpcErrorResponse.class);
verify(engineCallListener, times(1)).executionEngineCalled(); verify(engineCallListener, times(1)).executionEngineCalled();
} }

@ -104,7 +104,6 @@ public class EngineGetPayloadV3Test extends AbstractEngineGetPayloadTest {
cancunHardfork.milestone(), cancunHardfork.milestone(),
Bytes32.random(), Bytes32.random(),
Address.fromHexString("0x42"), Address.fromHexString("0x42"),
Optional.empty(),
Optional.empty()); Optional.empty());
BlobTestFixture blobTestFixture = new BlobTestFixture(); BlobTestFixture blobTestFixture = new BlobTestFixture();

@ -23,13 +23,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingOutputs;
import org.hyperledger.besu.ethereum.BlockProcessingResult; import org.hyperledger.besu.ethereum.BlockProcessingResult;
@ -41,26 +35,18 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadStatusResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadStatusResult;
import org.hyperledger.besu.ethereum.core.BlobTestFixture;
import org.hyperledger.besu.ethereum.core.BlockHeader; 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.Deposit; import org.hyperledger.besu.ethereum.core.Deposit;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;
import java.math.BigInteger;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -70,9 +56,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
protected static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair();
public EngineNewPayloadV3Test() {} public EngineNewPayloadV3Test() {}
@ -211,42 +194,4 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
assertThat(jsonRpcError.getData()).isEqualTo("Missing blob gas fields"); assertThat(jsonRpcError.getData()).isEqualTo("Missing blob gas fields");
verify(engineCallListener, times(1)).executionEngineCalled(); verify(engineCallListener, times(1)).executionEngineCalled();
} }
@Test
public void shouldRejectTransactionsWithFullBlobs() {
Bytes transactionWithBlobsBytes =
TransactionEncoder.encodeOpaqueBytes(
createTransactionWithBlobs(), EncodingContext.POOLED_TRANSACTION);
List<String> transactions = List.of(transactionWithBlobsBytes.toString());
BlockHeader mockHeader =
setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(),
Optional.empty());
var resp = resp(mockEnginePayload(mockHeader, transactions));
EnginePayloadStatusResult res = fromSuccessResp(resp);
assertThat(res.getStatusAsString()).isEqualTo(INVALID.name());
assertThat(res.getError()).isEqualTo("Failed to decode transactions from block parameter");
verify(engineCallListener, times(1)).executionEngineCalled();
}
private Transaction createTransactionWithBlobs() {
BlobTestFixture blobTestFixture = new BlobTestFixture();
BlobsWithCommitments bwc = blobTestFixture.createBlobsWithCommitments(1);
return new TransactionTestFixture()
.to(Optional.of(Address.fromHexString("0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF")))
.type(TransactionType.BLOB)
.chainId(Optional.of(BigInteger.ONE))
.maxFeePerGas(Optional.of(Wei.of(15)))
.maxFeePerBlobGas(Optional.of(Wei.of(128)))
.maxPriorityFeePerGas(Optional.of(Wei.of(1)))
.blobsWithCommitments(Optional.of(bwc))
.versionedHashes(Optional.of(bwc.getVersionedHashes()))
.createTransaction(senderKeys);
}
} }

@ -23,7 +23,6 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@ -60,7 +59,7 @@ public class DomainObjectDecodeUtilsTest {
@Test @Test
public void testAccessListRLPSerDes() { public void testAccessListRLPSerDes() {
final BytesValueRLPOutput encoded = new BytesValueRLPOutput(); final BytesValueRLPOutput encoded = new BytesValueRLPOutput();
TransactionEncoder.encodeRLP(accessListTxn, encoded, EncodingContext.POOLED_TRANSACTION); TransactionEncoder.encodeForWire(accessListTxn, encoded);
Transaction decoded = Transaction decoded =
DomainObjectDecodeUtils.decodeRawTransaction(encoded.encoded().toHexString()); DomainObjectDecodeUtils.decodeRawTransaction(encoded.encoded().toHexString());
Assertions.assertThat(decoded.getAccessList().isPresent()).isTrue(); Assertions.assertThat(decoded.getAccessList().isPresent()).isTrue();
@ -69,8 +68,7 @@ public class DomainObjectDecodeUtilsTest {
@Test @Test
public void testAccessList2718OpaqueSerDes() { public void testAccessList2718OpaqueSerDes() {
final Bytes encoded = final Bytes encoded = TransactionEncoder.encodeOpaqueBytes(accessListTxn);
TransactionEncoder.encodeOpaqueBytes(accessListTxn, EncodingContext.POOLED_TRANSACTION);
Transaction decoded = DomainObjectDecodeUtils.decodeRawTransaction(encoded.toString()); Transaction decoded = DomainObjectDecodeUtils.decodeRawTransaction(encoded.toString());
Assertions.assertThat(decoded.getAccessList().isPresent()).isTrue(); Assertions.assertThat(decoded.getAccessList().isPresent()).isTrue();
Assertions.assertThat(decoded.getAccessList().map(List::size).get()).isEqualTo(1); Assertions.assertThat(decoded.getAccessList().map(List::size).get()).isEqualTo(1);

@ -50,7 +50,7 @@ import org.hyperledger.besu.ethereum.mainnet.WithdrawalsProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
import org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator; import org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.EvmAccount;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException;
@ -190,10 +190,10 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
final List<BlockHeader> ommers = maybeOmmers.orElse(selectOmmers()); final List<BlockHeader> ommers = maybeOmmers.orElse(selectOmmers());
maybeParentBeaconBlockRoot.ifPresent( if (maybeParentBeaconBlockRoot.isPresent()) {
bytes32 ->
ParentBeaconBlockRootHelper.storeParentBeaconBlockRoot( ParentBeaconBlockRootHelper.storeParentBeaconBlockRoot(
disposableWorldState.updater(), timestamp, bytes32)); disposableWorldState.updater(), timestamp, maybeParentBeaconBlockRoot.get());
}
throwIfStopped(); throwIfStopped();
final TransactionSelectionResults transactionResults = final TransactionSelectionResults transactionResults =
@ -466,9 +466,9 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
.getBlockProcessor() .getBlockProcessor()
.getCoinbaseReward(blockReward, header.getNumber(), ommers.size()); .getCoinbaseReward(blockReward, header.getNumber(), ommers.size());
final WorldUpdater updater = worldState.updater(); final WorldUpdater updater = worldState.updater();
final MutableAccount beneficiary = updater.getOrCreate(miningBeneficiary); final EvmAccount beneficiary = updater.getOrCreate(miningBeneficiary);
beneficiary.incrementBalance(coinbaseReward); beneficiary.getMutable().incrementBalance(coinbaseReward);
for (final BlockHeader ommerHeader : ommers) { for (final BlockHeader ommerHeader : ommers) {
if (ommerHeader.getNumber() - header.getNumber() > MAX_GENERATION) { if (ommerHeader.getNumber() - header.getNumber() > MAX_GENERATION) {
LOG.trace( LOG.trace(
@ -479,12 +479,12 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
return false; return false;
} }
final MutableAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase()); final EvmAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase());
final Wei ommerReward = final Wei ommerReward =
protocolSpec protocolSpec
.getBlockProcessor() .getBlockProcessor()
.getOmmerReward(blockReward, header.getNumber(), ommerHeader.getNumber()); .getOmmerReward(blockReward, header.getNumber(), ommerHeader.getNumber());
ommerCoinbase.incrementBalance(ommerReward); ommerCoinbase.getMutable().incrementBalance(ommerReward);
} }
updater.commit(); updater.commit();

@ -34,7 +34,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.testutil.TestClock;
import org.hyperledger.besu.util.number.Fraction;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.function.Function; import java.util.function.Function;
@ -65,7 +64,7 @@ public class LegacyFeeMarketBlockTransactionSelectorTest
final TransactionPoolConfiguration poolConf = final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder() ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(5) .txPoolMaxSize(5)
.txPoolLimitByAccountPercentage(Fraction.fromFloat(1f)) .txPoolLimitByAccountPercentage(1)
.build(); .build();
final PendingTransactions pendingTransactions = final PendingTransactions pendingTransactions =

@ -39,7 +39,6 @@ import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.testutil.TestClock;
import org.hyperledger.besu.util.number.Fraction;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.List; import java.util.List;
@ -73,7 +72,7 @@ public class LondonFeeMarketBlockTransactionSelectorTest
final TransactionPoolConfiguration poolConf = final TransactionPoolConfiguration poolConf =
ImmutableTransactionPoolConfiguration.builder() ImmutableTransactionPoolConfiguration.builder()
.txPoolMaxSize(5) .txPoolMaxSize(5)
.txPoolLimitByAccountPercentage(Fraction.fromFloat(1f)) .txPoolLimitByAccountPercentage(1)
.build(); .build();
final PendingTransactions pendingTransactions = final PendingTransactions pendingTransactions =
new BaseFeePendingTransactionsSorter( new BaseFeePendingTransactionsSorter(

@ -39,7 +39,7 @@ public class EntriesFromIntegrationTest {
public void shouldCollectStateEntries() { public void shouldCollectStateEntries() {
final MutableWorldState worldState = createInMemoryWorldStateArchive().getMutable(); final MutableWorldState worldState = createInMemoryWorldStateArchive().getMutable();
final WorldUpdater updater = worldState.updater(); final WorldUpdater updater = worldState.updater();
MutableAccount account = updater.getOrCreate(Address.fromHexString("0x56")); MutableAccount account = updater.getOrCreate(Address.fromHexString("0x56")).getMutable();
final Map<Bytes32, AccountStorageEntry> expectedValues = new TreeMap<>(); final Map<Bytes32, AccountStorageEntry> expectedValues = new TreeMap<>();
final int nodeCount = 100_000; final int nodeCount = 100_000;
final Random random = new Random(42989428249L); final Random random = new Random(42989428249L);
@ -49,19 +49,19 @@ public class EntriesFromIntegrationTest {
addExpectedValue( addExpectedValue(
account, account,
expectedValues, expectedValues,
UInt256.valueOf(random.nextLong(Long.MAX_VALUE)), UInt256.valueOf(Math.abs(random.nextLong())),
UInt256.valueOf(i * 10 + 1L)); UInt256.valueOf(i * 10 + 1));
} }
updater.commit(); updater.commit();
// Add some changes on top that AbstractWorldUpdater.UpdateTrackingAccount will have to merge. // Add some changes on top that AbstractWorldUpdater.UpdateTrackingAccount will have to merge.
account = worldState.updater().getOrCreate(Address.fromHexString("0x56")); account = worldState.updater().getOrCreate(Address.fromHexString("0x56")).getMutable();
for (int i = 0; i <= nodeCount; i++) { for (int i = 0; i <= nodeCount; i++) {
addExpectedValue( addExpectedValue(
account, account,
expectedValues, expectedValues,
UInt256.valueOf(random.nextLong(Long.MAX_VALUE)), UInt256.valueOf(Math.abs(random.nextLong())),
UInt256.valueOf(i * 10 + 1L)); UInt256.valueOf(i * 10 + 1));
} }
final Map<Bytes32, AccountStorageEntry> values = final Map<Bytes32, AccountStorageEntry> values =

@ -59,7 +59,7 @@ public class TransientStorageOperationBenchmark {
.blockHeader(blockHeader) .blockHeader(blockHeader)
.blockchain(blockchain) .blockchain(blockchain)
.build(); .build();
worldStateUpdater.getOrCreate(address).setBalance(Wei.of(1)); worldStateUpdater.getOrCreate(address).getMutable().setBalance(Wei.of(1));
worldStateUpdater.commit(); worldStateUpdater.commit();
return benchmarkFrame; return benchmarkFrame;

@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.hyperledger.besu.evm.ModificationNotAllowedException; import org.hyperledger.besu.evm.ModificationNotAllowedException;
import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.evm.account.EvmAccount;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount; import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount;
@ -40,9 +41,9 @@ import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
public class BonsaiAccount implements MutableAccount, AccountValue { public class BonsaiAccount implements MutableAccount, EvmAccount, AccountValue {
private final BonsaiWorldView context; private final BonsaiWorldView context;
private boolean mutable; private final boolean mutable;
private final Address address; private final Address address;
private final Hash addressHash; private final Hash addressHash;
@ -162,7 +163,7 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
@Override @Override
public void setNonce(final long value) { public void setNonce(final long value) {
if (!mutable) { if (!mutable) {
throw new ModificationNotAllowedException(); throw new UnsupportedOperationException("Account is immutable");
} }
nonce = value; nonce = value;
} }
@ -175,7 +176,7 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
@Override @Override
public void setBalance(final Wei value) { public void setBalance(final Wei value) {
if (!mutable) { if (!mutable) {
throw new ModificationNotAllowedException(); throw new UnsupportedOperationException("Account is immutable");
} }
balance = value; balance = value;
} }
@ -191,7 +192,7 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
@Override @Override
public void setCode(final Bytes code) { public void setCode(final Bytes code) {
if (!mutable) { if (!mutable) {
throw new ModificationNotAllowedException(); throw new UnsupportedOperationException("Account is immutable");
} }
this.code = code; this.code = code;
if (code == null || code.isEmpty()) { if (code == null || code.isEmpty()) {
@ -219,7 +220,7 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
@Override @Override
public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom( public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom(
final Bytes32 startKeyHash, final int limit) { final Bytes32 startKeyHash, final int limit) {
return context.getWorldStateStorage().storageEntriesFrom(this.addressHash, startKeyHash, limit); throw new RuntimeException("Bonsai Tries does not currently support enumerating storage");
} }
public Bytes serializeAccount() { public Bytes serializeAccount() {
@ -243,7 +244,7 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
@Override @Override
public void setStorageValue(final UInt256 key, final UInt256 value) { public void setStorageValue(final UInt256 key, final UInt256 value) {
if (!mutable) { if (!mutable) {
throw new ModificationNotAllowedException(); throw new UnsupportedOperationException("Account is immutable");
} }
updatedStorage.put(key, value); updatedStorage.put(key, value);
} }
@ -258,6 +259,15 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
return updatedStorage; return updatedStorage;
} }
@Override
public MutableAccount getMutable() throws ModificationNotAllowedException {
if (mutable) {
return this;
} else {
throw new ModificationNotAllowedException();
}
}
@Override @Override
public Hash getStorageRoot() { public Hash getStorageRoot() {
return storageRoot; return storageRoot;
@ -265,16 +275,11 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
public void setStorageRoot(final Hash storageRoot) { public void setStorageRoot(final Hash storageRoot) {
if (!mutable) { if (!mutable) {
throw new ModificationNotAllowedException(); throw new UnsupportedOperationException("Account is immutable");
} }
this.storageRoot = storageRoot; this.storageRoot = storageRoot;
} }
@Override
public void becomeImmutable() {
mutable = false;
}
@Override @Override
public String toString() { public String toString() {
return "AccountState{" return "AccountState{"

@ -102,8 +102,8 @@ public class BonsaiWorldStateProvider implements WorldStateArchive {
pluginContext); pluginContext);
this.blockchain = blockchain; this.blockchain = blockchain;
this.worldStateStorage = worldStateStorage; this.worldStateStorage = worldStateStorage;
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader;
this.persistedState = new BonsaiWorldState(this, worldStateStorage); this.persistedState = new BonsaiWorldState(this, worldStateStorage);
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader;
blockchain blockchain
.getBlockHeader(persistedState.getWorldStateBlockHash()) .getBlockHeader(persistedState.getWorldStateBlockHash())
.ifPresent( .ifPresent(

@ -1,68 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
package org.hyperledger.besu.ethereum.bonsai.storage;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import java.util.Optional;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
/** Acts as both a Hasher and PreImageStorage for Bonsai storage format. */
public interface BonsaiPreImageProxy extends WorldStatePreimageStorage {
/**
* If this value is not already present, save in preImage store and return the hash value.
*
* @param value value to hash
* @return Hash of value
*/
Hash hashAndSavePreImage(Bytes value);
/**
* A caching PreImageProxy suitable for ReferenceTestWorldState which saves hashes in an unbounded
* BiMap.
*/
class BonsaiReferenceTestPreImageProxy implements BonsaiPreImageProxy {
BiMap<Hash, Bytes> preImageCache = HashBiMap.create();
@Override
public synchronized Hash hashAndSavePreImage(final Bytes value) {
return preImageCache.inverse().computeIfAbsent(value, Hash::hash);
}
@Override
public Optional<UInt256> getStorageTrieKeyPreimage(final Bytes32 trieKey) {
return Optional.ofNullable(preImageCache.get(trieKey)).map(UInt256::fromBytes);
}
@Override
public Optional<Address> getAccountTrieKeyPreimage(final Bytes32 trieKey) {
return Optional.ofNullable(preImageCache.get(trieKey)).map(Address::wrap);
}
@Override
public Updater updater() {
throw new UnsupportedOperationException(
"BonsaiReferenceTestPreImageProxy does not implement an updater");
}
}
}

@ -31,7 +31,6 @@ import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;
@ -42,7 +41,6 @@ import org.hyperledger.besu.util.Subscribers;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NavigableMap;
import java.util.Optional; 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;
@ -55,6 +53,7 @@ import org.slf4j.LoggerFactory;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoCloseable { public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateKeyValueStorage.class); private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateKeyValueStorage.class);
// 0x776f726c64526f6f74 // 0x776f726c64526f6f74
@ -251,11 +250,6 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoC
composedWorldStateStorage, accountHash, startKeyHash, endKeyHash, max); composedWorldStateStorage, accountHash, startKeyHash, endKeyHash, max);
} }
public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom(
final Hash addressHash, final Bytes32 startKeyHash, final int limit) {
throw new RuntimeException("Bonsai Tries does not currently support enumerating storage");
}
@Override @Override
public Optional<Bytes> getNodeData(final Bytes location, final Bytes32 hash) { public Optional<Bytes> getNodeData(final Bytes location, final Bytes32 hash) {
return Optional.empty(); return Optional.empty();

@ -135,10 +135,10 @@ public abstract class FlatDbReaderStrategy {
final long max) { final long max) {
final Stream<Pair<Bytes32, Bytes>> pairStream = final Stream<Pair<Bytes32, Bytes>> pairStream =
storage storage
.streamFromKey( .streamFromKey(ACCOUNT_INFO_STATE, startKeyHash.toArrayUnsafe())
ACCOUNT_INFO_STATE, startKeyHash.toArrayUnsafe(), endKeyHash.toArrayUnsafe())
.limit(max) .limit(max)
.map(pair -> new Pair<>(Bytes32.wrap(pair.getKey()), Bytes.wrap(pair.getValue()))); .map(pair -> new Pair<>(Bytes32.wrap(pair.getKey()), Bytes.wrap(pair.getValue())))
.takeWhile(pair -> pair.getFirst().compareTo(endKeyHash) <= 0);
final TreeMap<Bytes32, Bytes> collected = final TreeMap<Bytes32, Bytes> collected =
pairStream.collect( pairStream.collect(
@ -157,14 +157,15 @@ public abstract class FlatDbReaderStrategy {
storage storage
.streamFromKey( .streamFromKey(
ACCOUNT_STORAGE_STORAGE, ACCOUNT_STORAGE_STORAGE,
Bytes.concatenate(accountHash, startKeyHash).toArrayUnsafe(), Bytes.concatenate(accountHash, startKeyHash).toArrayUnsafe())
Bytes.concatenate(accountHash, endKeyHash).toArrayUnsafe()) .takeWhile(pair -> Bytes.wrap(pair.getKey()).slice(0, Hash.SIZE).equals(accountHash))
.limit(max) .limit(max)
.map( .map(
pair -> pair ->
new Pair<>( new Pair<>(
Bytes32.wrap(Bytes.wrap(pair.getKey()).slice(Hash.SIZE)), Bytes32.wrap(Bytes.wrap(pair.getKey()).slice(Hash.SIZE)),
RLP.encodeValue(Bytes.wrap(pair.getValue()).trimLeadingZeros()))); RLP.encodeValue(Bytes.wrap(pair.getValue()).trimLeadingZeros())))
.takeWhile(pair -> pair.getFirst().compareTo(endKeyHash) <= 0);
final TreeMap<Bytes32, Bytes> collected = final TreeMap<Bytes32, Bytes> collected =
pairStream.collect( pairStream.collect(

@ -27,7 +27,6 @@ import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.bonsai.BonsaiAccount; import org.hyperledger.besu.ethereum.bonsai.BonsaiAccount;
import org.hyperledger.besu.ethereum.bonsai.BonsaiValue; import org.hyperledger.besu.ethereum.bonsai.BonsaiValue;
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.storage.BonsaiSnapshotWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiSnapshotWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber; import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber;
@ -66,52 +65,51 @@ public class BonsaiWorldState
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldState.class); private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldState.class);
protected BonsaiWorldStateKeyValueStorage worldStateStorage; private BonsaiWorldStateKeyValueStorage worldStateStorage;
protected final CachedMerkleTrieLoader cachedMerkleTrieLoader; private final BonsaiWorldStateProvider archive;
protected final TrieLogManager trieLogManager; private final BonsaiWorldStateUpdateAccumulator accumulator;
private BonsaiWorldStateUpdateAccumulator accumulator;
protected Hash worldStateRootHash; private Hash worldStateRootHash;
Hash worldStateBlockHash; Hash worldStateBlockHash;
private boolean isFrozen; private boolean isFrozen;
public BonsaiWorldState( public BonsaiWorldState(
final BonsaiWorldStateProvider archive, final BonsaiWorldStateProvider archive,
final BonsaiWorldStateKeyValueStorage worldStateStorage) { final BonsaiWorldStateKeyValueStorage worldStateStorage) {
this(worldStateStorage, archive.getCachedMerkleTrieLoader(), archive.getTrieLogManager()); this.archive = archive;
}
protected BonsaiWorldState(
final BonsaiWorldStateKeyValueStorage worldStateStorage,
final CachedMerkleTrieLoader cachedMerkleTrieLoader,
final TrieLogManager trieLogManager) {
this.worldStateStorage = worldStateStorage; this.worldStateStorage = worldStateStorage;
this.worldStateRootHash = worldStateRootHash =
Hash.wrap( Hash.wrap(
Bytes32.wrap(worldStateStorage.getWorldStateRootHash().orElse(Hash.EMPTY_TRIE_HASH))); Bytes32.wrap(worldStateStorage.getWorldStateRootHash().orElse(Hash.EMPTY_TRIE_HASH)));
this.worldStateBlockHash = worldStateBlockHash =
Hash.wrap(Bytes32.wrap(worldStateStorage.getWorldStateBlockHash().orElse(Hash.ZERO))); Hash.wrap(Bytes32.wrap(worldStateStorage.getWorldStateBlockHash().orElse(Hash.ZERO)));
this.accumulator = accumulator =
new BonsaiWorldStateUpdateAccumulator( new BonsaiWorldStateUpdateAccumulator(
this, this,
(addr, value) -> (addr, value) ->
cachedMerkleTrieLoader.preLoadAccount( archive
getWorldStateStorage(), worldStateRootHash, addr), .getCachedMerkleTrieLoader()
.preLoadAccount(getWorldStateStorage(), worldStateRootHash, addr),
(addr, value) -> (addr, value) ->
cachedMerkleTrieLoader.preLoadStorageSlot(getWorldStateStorage(), addr, value)); archive
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; .getCachedMerkleTrieLoader()
this.trieLogManager = trieLogManager; .preLoadStorageSlot(getWorldStateStorage(), addr, value));
} }
/** public BonsaiWorldState(
* Having a protected method to override the accumulator solves the chicken-egg problem of needing final BonsaiWorldStateProvider archive,
* a worldstate reference (this) when construction the Accumulator. final BonsaiWorldStateKeyValueStorage worldStateStorage,
* final BonsaiWorldStateUpdateAccumulator updater) {
* @param accumulator accumulator to use. this.archive = archive;
*/ this.worldStateStorage = worldStateStorage;
protected void setAccumulator(final BonsaiWorldStateUpdateAccumulator accumulator) { this.worldStateRootHash =
this.accumulator = accumulator; Hash.wrap(
Bytes32.wrap(worldStateStorage.getWorldStateRootHash().orElse(Hash.EMPTY_TRIE_HASH)));
this.worldStateBlockHash =
Hash.wrap(Bytes32.wrap(worldStateStorage.getWorldStateBlockHash().orElse(Hash.ZERO)));
this.accumulator = updater;
} }
/** /**
@ -132,6 +130,10 @@ public class BonsaiWorldState
return worldStateRootHash; return worldStateRootHash;
} }
public BonsaiWorldStateProvider getArchive() {
return archive;
}
@Override @Override
public boolean isPersisted() { public boolean isPersisted() {
return isPersisted(worldStateStorage); return isPersisted(worldStateStorage);
@ -187,7 +189,9 @@ public class BonsaiWorldState
final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie = final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie =
createTrie( createTrie(
(location, hash) -> (location, hash) ->
cachedMerkleTrieLoader.getAccountStateTrieNode(worldStateStorage, location, hash), archive
.getCachedMerkleTrieLoader()
.getAccountStateTrieNode(worldStateStorage, location, hash),
worldStateRootHash); worldStateRootHash);
// for manicured tries and composting, collect branches here (not implemented) // for manicured tries and composting, collect branches here (not implemented)
@ -219,7 +223,7 @@ public class BonsaiWorldState
final BonsaiAccount updatedAccount = bonsaiValue.getUpdated(); final BonsaiAccount updatedAccount = bonsaiValue.getUpdated();
try { try {
if (updatedAccount == null) { if (updatedAccount == null) {
final Hash addressHash = hashAndSavePreImage(accountKey); final Hash addressHash = Hash.hash(accountKey);
accountTrie.remove(addressHash); accountTrie.remove(addressHash);
maybeStateUpdater.ifPresent( maybeStateUpdater.ifPresent(
bonsaiUpdater -> bonsaiUpdater.removeAccountInfoState(addressHash)); bonsaiUpdater -> bonsaiUpdater.removeAccountInfoState(addressHash));
@ -228,7 +232,7 @@ public class BonsaiWorldState
final Bytes accountValue = updatedAccount.serializeAccount(); final Bytes accountValue = updatedAccount.serializeAccount();
maybeStateUpdater.ifPresent( maybeStateUpdater.ifPresent(
bonsaiUpdater -> bonsaiUpdater ->
bonsaiUpdater.putAccountInfoState(hashAndSavePreImage(accountKey), accountValue)); bonsaiUpdater.putAccountInfoState(Hash.hash(accountKey), accountValue));
accountTrie.put(addressHash, accountValue); accountTrie.put(addressHash, accountValue);
} }
} catch (MerkleTrieException e) { } catch (MerkleTrieException e) {
@ -273,7 +277,9 @@ public class BonsaiWorldState
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie = final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
createTrie( createTrie(
(location, key) -> (location, key) ->
cachedMerkleTrieLoader.getAccountStorageTrieNode( archive
.getCachedMerkleTrieLoader()
.getAccountStorageTrieNode(
worldStateStorage, updatedAddressHash, location, key), worldStateStorage, updatedAddressHash, location, key),
storageRoot); storageRoot);
@ -399,6 +405,7 @@ public class BonsaiWorldState
} }
saveTrieLog = saveTrieLog =
() -> { () -> {
final TrieLogManager trieLogManager = archive.getTrieLogManager();
trieLogManager.saveTrieLog(localCopy, newWorldStateRootHash, blockHeader, this); trieLogManager.saveTrieLog(localCopy, newWorldStateRootHash, blockHeader, this);
// not save a frozen state in the cache // not save a frozen state in the cache
if (!isFrozen) { if (!isFrozen) {
@ -619,9 +626,4 @@ public class BonsaiWorldState
// no op // no op
} }
} }
protected Hash hashAndSavePreImage(final Bytes value) {
// by default do not save has preImages
return Hash.hash(value);
}
} }

@ -27,9 +27,10 @@ import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStor
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.EvmAccount;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater; import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater;
import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount; import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount;
import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;
import org.hyperledger.besu.plugin.services.trielogs.TrieLogAccumulator; import org.hyperledger.besu.plugin.services.trielogs.TrieLogAccumulator;
@ -43,7 +44,6 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function; import java.util.function.Function;
import com.google.common.collect.ForwardingMap; import com.google.common.collect.ForwardingMap;
@ -115,37 +115,33 @@ public class BonsaiWorldStateUpdateAccumulator
} }
@Override @Override
public MutableAccount getAccount(final Address address) { public EvmAccount getAccount(final Address address) {
return super.getAccount(address); return super.getAccount(address);
} }
@Override @Override
public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) {
BonsaiValue<BonsaiAccount> bonsaiValue = accountsToUpdate.get(address); BonsaiValue<BonsaiAccount> bonsaiValue = accountsToUpdate.get(address);
if (bonsaiValue == null) { if (bonsaiValue == null) {
bonsaiValue = new BonsaiValue<>(null, null); bonsaiValue = new BonsaiValue<>(null, null);
accountsToUpdate.put(address, bonsaiValue); accountsToUpdate.put(address, bonsaiValue);
} else if (bonsaiValue.getUpdated() != null) { } else if (bonsaiValue.getUpdated() != null) {
if (bonsaiValue.getUpdated().isEmpty()) {
return track(new UpdateTrackingAccount<>(bonsaiValue.getUpdated()));
} else {
throw new IllegalStateException("Cannot create an account when one already exists"); throw new IllegalStateException("Cannot create an account when one already exists");
} }
}
final BonsaiAccount newAccount = final BonsaiAccount newAccount =
new BonsaiAccount( new BonsaiAccount(
this, this,
address, address,
hashAndSavePreImage(address), address.addressHash(),
nonce, nonce,
balance, balance,
Hash.EMPTY_TRIE_HASH, Hash.EMPTY_TRIE_HASH,
Hash.EMPTY, Hash.EMPTY,
true); true);
bonsaiValue.setUpdated(newAccount); bonsaiValue.setUpdated(newAccount);
return track(new UpdateTrackingAccount<>(newAccount)); return new WrappedEvmAccount(track(new UpdateTrackingAccount<>(newAccount)));
} }
@Override @Override
@ -180,15 +176,17 @@ public class BonsaiWorldStateUpdateAccumulator
final BonsaiValue<BonsaiAccount> bonsaiValue = accountsToUpdate.get(address); final BonsaiValue<BonsaiAccount> bonsaiValue = accountsToUpdate.get(address);
if (bonsaiValue == null) { if (bonsaiValue == null) {
final Account account; final Account account;
if (wrappedWorldView() if (wrappedWorldView() instanceof BonsaiWorldStateUpdateAccumulator) {
instanceof BonsaiWorldStateUpdateAccumulator bonsaiWorldStateUpdateAccumulator) { account =
account = bonsaiWorldStateUpdateAccumulator.loadAccount(address, bonsaiAccountFunction); ((BonsaiWorldStateUpdateAccumulator) wrappedWorldView())
.loadAccount(address, bonsaiAccountFunction);
} else { } else {
account = wrappedWorldView().get(address); account = wrappedWorldView().get(address);
} }
if (account instanceof BonsaiAccount bonsaiAccount) { BonsaiAccount mutableAccount = null;
BonsaiAccount mutableAccount = new BonsaiAccount(bonsaiAccount, this, true); if (account instanceof BonsaiAccount) {
accountsToUpdate.put(address, new BonsaiValue<>(bonsaiAccount, mutableAccount)); mutableAccount = new BonsaiAccount((BonsaiAccount) account, this, true);
accountsToUpdate.put(address, new BonsaiValue<>((BonsaiAccount) account, mutableAccount));
return mutableAccount; return mutableAccount;
} else { } else {
// add the empty read in accountsToUpdate // add the empty read in accountsToUpdate
@ -292,19 +290,6 @@ public class BonsaiWorldStateUpdateAccumulator
final BonsaiAccount updatedAccount; final BonsaiAccount updatedAccount;
final BonsaiValue<BonsaiAccount> updatedAccountValue = final BonsaiValue<BonsaiAccount> updatedAccountValue =
accountsToUpdate.get(updatedAddress); accountsToUpdate.get(updatedAddress);
final Map<StorageSlotKey, BonsaiValue<UInt256>> pendingStorageUpdates =
storageToUpdate.computeIfAbsent(
updatedAddress,
k ->
new StorageConsumingMap<>(
updatedAddress, new ConcurrentHashMap<>(), storagePreloader));
if (tracked.getStorageWasCleared()) {
storageToClear.add(updatedAddress);
pendingStorageUpdates.clear();
}
if (tracked.getWrappedAccount() == null) { if (tracked.getWrappedAccount() == null) {
updatedAccount = new BonsaiAccount(this, tracked); updatedAccount = new BonsaiAccount(this, tracked);
tracked.setWrappedAccount(updatedAccount); tracked.setWrappedAccount(updatedAccount);
@ -324,17 +309,6 @@ public class BonsaiWorldStateUpdateAccumulator
} }
if (tracked.getStorageWasCleared()) { if (tracked.getStorageWasCleared()) {
updatedAccount.clearStorage(); updatedAccount.clearStorage();
wrappedWorldView()
.getAllAccountStorage(updatedAddress, updatedAccount.getStorageRoot())
.forEach(
(keyHash, entryValue) -> {
final StorageSlotKey storageSlotKey =
new StorageSlotKey(Hash.wrap(keyHash), Optional.empty());
final UInt256 value = UInt256.fromBytes(RLP.decodeOne(entryValue));
pendingStorageUpdates.put(
storageSlotKey, new BonsaiValue<>(value, null, true));
});
updatedAccount.setStorageRoot(Hash.EMPTY_TRIE_HASH);
} }
tracked.getUpdatedStorage().forEach(updatedAccount::setStorageValue); tracked.getUpdatedStorage().forEach(updatedAccount::setStorageValue);
} }
@ -357,12 +331,24 @@ public class BonsaiWorldStateUpdateAccumulator
pendingCode.setUpdated(updatedAccount.getCode()); pendingCode.setUpdated(updatedAccount.getCode());
} }
// This is especially to avoid unnecessary computation for withdrawals and // This is especially to avoid unnecessary computation for withdrawals
// self-destruct beneficiaries
if (updatedAccount.getUpdatedStorage().isEmpty()) { if (updatedAccount.getUpdatedStorage().isEmpty()) {
return; return;
} }
final StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>>
pendingStorageUpdates =
storageToUpdate.computeIfAbsent(
updatedAddress,
__ ->
new StorageConsumingMap<>(
updatedAddress, new ConcurrentHashMap<>(), storagePreloader));
if (tracked.getStorageWasCleared()) {
storageToClear.add(updatedAddress);
pendingStorageUpdates.clear();
}
final TreeSet<Map.Entry<UInt256, UInt256>> entries = final TreeSet<Map.Entry<UInt256, UInt256>> entries =
new TreeSet<>(Map.Entry.comparingByKey()); new TreeSet<>(Map.Entry.comparingByKey());
entries.addAll(updatedAccount.getUpdatedStorage().entrySet()); entries.addAll(updatedAccount.getUpdatedStorage().entrySet());
@ -371,7 +357,7 @@ public class BonsaiWorldStateUpdateAccumulator
entries.forEach( entries.forEach(
storageUpdate -> { storageUpdate -> {
final UInt256 keyUInt = storageUpdate.getKey(); final UInt256 keyUInt = storageUpdate.getKey();
final Hash slotHash = hashAndSavePreImage(keyUInt); final Hash slotHash = Hash.hash(keyUInt);
final StorageSlotKey slotKey = final StorageSlotKey slotKey =
new StorageSlotKey(slotHash, Optional.of(keyUInt)); new StorageSlotKey(slotHash, Optional.of(keyUInt));
final UInt256 value = storageUpdate.getValue(); final UInt256 value = storageUpdate.getValue();
@ -415,8 +401,7 @@ public class BonsaiWorldStateUpdateAccumulator
@Override @Override
public UInt256 getStorageValue(final Address address, final UInt256 slotKey) { public UInt256 getStorageValue(final Address address, final UInt256 slotKey) {
StorageSlotKey storageSlotKey = StorageSlotKey storageSlotKey = new StorageSlotKey(Hash.hash(slotKey), Optional.of(slotKey));
new StorageSlotKey(hashAndSavePreImage(slotKey), Optional.of(slotKey));
return getStorageValueByStorageSlotKey(address, storageSlotKey).orElse(UInt256.ZERO); return getStorageValueByStorageSlotKey(address, storageSlotKey).orElse(UInt256.ZERO);
} }
@ -433,8 +418,9 @@ public class BonsaiWorldStateUpdateAccumulator
} }
try { try {
final Optional<UInt256> valueUInt = final Optional<UInt256> valueUInt =
(wrappedWorldView() instanceof BonsaiWorldState bonsaiWorldState) (wrappedWorldView() instanceof BonsaiWorldState)
? bonsaiWorldState.getStorageValueByStorageSlotKey( ? ((BonsaiWorldState) wrappedWorldView())
.getStorageValueByStorageSlotKey(
() -> () ->
Optional.ofNullable(loadAccount(address, BonsaiValue::getPrior)) Optional.ofNullable(loadAccount(address, BonsaiValue::getPrior))
.map(BonsaiAccount::getStorageRoot), .map(BonsaiAccount::getStorageRoot),
@ -460,7 +446,7 @@ public class BonsaiWorldStateUpdateAccumulator
public UInt256 getPriorStorageValue(final Address address, final UInt256 storageKey) { public UInt256 getPriorStorageValue(final Address address, final UInt256 storageKey) {
// TODO maybe log the read into the trie layer? // TODO maybe log the read into the trie layer?
StorageSlotKey storageSlotKey = StorageSlotKey storageSlotKey =
new StorageSlotKey(hashAndSavePreImage(storageKey), Optional.of(storageKey)); new StorageSlotKey(Hash.hash(storageKey), Optional.of(storageKey));
final Map<StorageSlotKey, BonsaiValue<UInt256>> localAccountStorage = final Map<StorageSlotKey, BonsaiValue<UInt256>> localAccountStorage =
storageToUpdate.get(address); storageToUpdate.get(address);
if (localAccountStorage != null) { if (localAccountStorage != null) {
@ -509,43 +495,53 @@ public class BonsaiWorldStateUpdateAccumulator
} }
public void rollForward(final TrieLog layer) { public void rollForward(final TrieLog layer) {
layer layer.getAccountChanges().entrySet().stream()
.getAccountChanges()
.forEach( .forEach(
(address, change) -> entry ->
rollAccountChange(address, change.getPrior(), change.getUpdated())); rollAccountChange(
layer entry.getKey(), entry.getValue().getPrior(), entry.getValue().getUpdated()));
.getCodeChanges() layer.getCodeChanges().entrySet().stream()
.forEach( .forEach(
(address, change) -> rollCodeChange(address, change.getPrior(), change.getUpdated())); entry ->
layer rollCodeChange(
.getStorageChanges() entry.getKey(), entry.getValue().getPrior(), entry.getValue().getUpdated()));
layer.getStorageChanges().entrySet().stream()
.forEach(
entry ->
entry
.getValue()
.forEach( .forEach(
(address, storage) ->
storage.forEach(
(storageSlotKey, value) -> (storageSlotKey, value) ->
rollStorageChange( rollStorageChange(
address, storageSlotKey, value.getPrior(), value.getUpdated()))); entry.getKey(),
storageSlotKey,
value.getPrior(),
value.getUpdated())));
} }
public void rollBack(final TrieLog layer) { public void rollBack(final TrieLog layer) {
layer layer.getAccountChanges().entrySet().stream()
.getAccountChanges()
.forEach( .forEach(
(address, change) -> entry ->
rollAccountChange(address, change.getUpdated(), change.getPrior())); rollAccountChange(
layer entry.getKey(), entry.getValue().getUpdated(), entry.getValue().getPrior()));
.getCodeChanges() layer.getCodeChanges().entrySet().stream()
.forEach( .forEach(
(address, change) -> rollCodeChange(address, change.getUpdated(), change.getPrior())); entry ->
layer rollCodeChange(
.getStorageChanges() entry.getKey(), entry.getValue().getUpdated(), entry.getValue().getPrior()));
layer.getStorageChanges().entrySet().stream()
.forEach(
entry ->
entry
.getValue()
.forEach( .forEach(
(address, storage) ->
storage.forEach(
(storageSlotKey, value) -> (storageSlotKey, value) ->
rollStorageChange( rollStorageChange(
address, storageSlotKey, value.getUpdated(), value.getPrior()))); entry.getKey(),
storageSlotKey,
value.getUpdated(),
value.getPrior())));
} }
private void rollAccountChange( private void rollAccountChange(
@ -602,7 +598,8 @@ public class BonsaiWorldStateUpdateAccumulator
final Address address, final BonsaiValue<BonsaiAccount> defaultValue) { final Address address, final BonsaiValue<BonsaiAccount> defaultValue) {
try { try {
final Account parentAccount = wrappedWorldView().get(address); final Account parentAccount = wrappedWorldView().get(address);
if (parentAccount instanceof BonsaiAccount account) { if (parentAccount instanceof BonsaiAccount) {
final BonsaiAccount account = (BonsaiAccount) parentAccount;
final BonsaiValue<BonsaiAccount> loadedAccountValue = final BonsaiValue<BonsaiAccount> loadedAccountValue =
new BonsaiValue<>(new BonsaiAccount(account), account); new BonsaiValue<>(new BonsaiAccount(account), account);
accountsToUpdate.put(address, loadedAccountValue); accountsToUpdate.put(address, loadedAccountValue);
@ -637,7 +634,7 @@ public class BonsaiWorldStateUpdateAccumulator
} }
if (codeValue == null) { if (codeValue == null) {
if ((expectedCode == null || expectedCode.isEmpty()) && replacementCode != null) { if ((expectedCode == null || expectedCode.size() == 0) && replacementCode != null) {
codeToUpdate.put(address, new BonsaiValue<>(null, replacementCode)); codeToUpdate.put(address, new BonsaiValue<>(null, replacementCode));
} else { } else {
throw new IllegalStateException( throw new IllegalStateException(
@ -775,11 +772,11 @@ public class BonsaiWorldStateUpdateAccumulator
public static class AccountConsumingMap<T> extends ForwardingMap<Address, T> { public static class AccountConsumingMap<T> extends ForwardingMap<Address, T> {
private final ConcurrentMap<Address, T> accounts; private final ConcurrentHashMap<Address, T> accounts;
private final Consumer<T> consumer; private final Consumer<T> consumer;
public AccountConsumingMap( public AccountConsumingMap(
final ConcurrentMap<Address, T> accounts, final Consumer<T> consumer) { final ConcurrentHashMap<Address, T> accounts, final Consumer<T> consumer) {
this.accounts = accounts; this.accounts = accounts;
this.consumer = consumer; this.consumer = consumer;
} }
@ -804,11 +801,11 @@ public class BonsaiWorldStateUpdateAccumulator
private final Address address; private final Address address;
private final ConcurrentMap<K, T> storages; private final ConcurrentHashMap<K, T> storages;
private final Consumer<K> consumer; private final Consumer<K> consumer;
public StorageConsumingMap( public StorageConsumingMap(
final Address address, final ConcurrentMap<K, T> storages, final Consumer<K> consumer) { final Address address, final ConcurrentHashMap<K, T> storages, final Consumer<K> consumer) {
this.address = address; this.address = address;
this.storages = storages; this.storages = storages;
this.consumer = consumer; this.consumer = consumer;
@ -833,9 +830,4 @@ public class BonsaiWorldStateUpdateAccumulator
public interface Consumer<T> { public interface Consumer<T> {
void process(final Address address, T value); void process(final Address address, T value);
} }
protected Hash hashAndSavePreImage(final Bytes bytes) {
// by default do not save hash preImages
return Hash.hash(bytes);
}
} }

@ -48,6 +48,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.OptionalLong; import java.util.OptionalLong;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
@ -85,7 +86,8 @@ public final class GenesisState {
*/ */
public static GenesisState fromConfig( public static GenesisState fromConfig(
final GenesisConfigFile config, final ProtocolSchedule protocolSchedule) { final GenesisConfigFile config, final ProtocolSchedule protocolSchedule) {
final List<GenesisAccount> genesisAccounts = parseAllocations(config).toList(); final List<GenesisAccount> genesisAccounts =
parseAllocations(config).collect(Collectors.toList());
final Block block = final Block block =
new Block( new Block(
buildHeader(config, calculateGenesisStateHash(genesisAccounts), protocolSchedule), buildHeader(config, calculateGenesisStateHash(genesisAccounts), protocolSchedule),
@ -122,7 +124,7 @@ public final class GenesisState {
final WorldUpdater updater = target.updater(); final WorldUpdater updater = target.updater();
genesisAccounts.forEach( genesisAccounts.forEach(
genesisAccount -> { genesisAccount -> {
final MutableAccount account = updater.getOrCreate(genesisAccount.address); final MutableAccount account = updater.getOrCreate(genesisAccount.address).getMutable();
account.setNonce(genesisAccount.nonce); account.setNonce(genesisAccount.nonce);
account.setBalance(genesisAccount.balance); account.setBalance(genesisAccount.balance);
account.setCode(genesisAccount.code); account.setCode(genesisAccount.code);

@ -35,9 +35,7 @@ import org.hyperledger.besu.datatypes.Sha256Hash;
import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@ -128,7 +126,7 @@ public class Transaction
} }
public static Transaction readFrom(final RLPInput rlpInput) { public static Transaction readFrom(final RLPInput rlpInput) {
return TransactionDecoder.decodeRLP(rlpInput, EncodingContext.BLOCK_BODY); return TransactionDecoder.decodeForWire(rlpInput);
} }
/** /**
@ -191,15 +189,14 @@ public class Transaction
if (versionedHashes.isPresent() || maxFeePerBlobGas.isPresent()) { if (versionedHashes.isPresent() || maxFeePerBlobGas.isPresent()) {
checkArgument( checkArgument(
transactionType.supportsBlob(), transactionType.supportsBlob(),
"Must not specify blob versioned hashes or max fee per blob gas for transaction not supporting it"); "Must not specify blob versioned hashes of max fee per blob gas for transaction not supporting it");
} }
if (transactionType.supportsBlob()) { if (transactionType.supportsBlob()) {
checkArgument( checkArgument(
versionedHashes.isPresent(), "Must specify blob versioned hashes for blob transaction"); versionedHashes.isPresent(), "Must specify blob versioned hashes for blob transaction");
checkArgument( checkArgument(
!versionedHashes.get().isEmpty(), !versionedHashes.get().isEmpty(), "Blob transaction must have at least one blob");
"Blob transaction must have at least one versioned hash");
checkArgument( checkArgument(
maxFeePerBlobGas.isPresent(), "Must specify max fee per blob gas for blob transaction"); maxFeePerBlobGas.isPresent(), "Must specify max fee per blob gas for blob transaction");
} }
@ -615,7 +612,7 @@ public class Transaction
* @param out the output to write the transaction to * @param out the output to write the transaction to
*/ */
public void writeTo(final RLPOutput out) { public void writeTo(final RLPOutput out) {
TransactionEncoder.encodeRLP(this, out, EncodingContext.BLOCK_BODY); TransactionEncoder.encodeForWire(this, out);
} }
@Override @Override
@ -678,17 +675,18 @@ public class Transaction
} }
private void memoizeHashAndSize() { private void memoizeHashAndSize() {
final Bytes bytes = TransactionEncoder.encodeOpaqueBytes(this, EncodingContext.BLOCK_BODY); final Bytes bytes = TransactionEncoder.encodeOpaqueBytes(this);
hash = Hash.hash(bytes); hash = Hash.hash(bytes);
if (transactionType.supportsBlob()) { if (transactionType.supportsBlob()) {
if (getBlobsWithCommitments().isPresent()) { if (getBlobsWithCommitments().isPresent()) {
final Bytes pooledBytes = size = TransactionEncoder.encodeOpaqueBytes(this).size();
TransactionEncoder.encodeOpaqueBytes(this, EncodingContext.POOLED_TRANSACTION);
size = pooledBytes.size();
return;
} }
} else {
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
TransactionEncoder.encodeForWire(transactionType, bytes, rlpOutput);
size = rlpOutput.encodedSize();
} }
size = bytes.size();
} }
/** /**
@ -969,7 +967,7 @@ public class Transaction
rlpOutput.writeBytes(to.map(Bytes::copy).orElse(Bytes.EMPTY)); rlpOutput.writeBytes(to.map(Bytes::copy).orElse(Bytes.EMPTY));
rlpOutput.writeUInt256Scalar(value); rlpOutput.writeUInt256Scalar(value);
rlpOutput.writeBytes(payload); rlpOutput.writeBytes(payload);
AccessListTransactionEncoder.writeAccessList(rlpOutput, accessList); TransactionEncoder.writeAccessList(rlpOutput, accessList);
} }
private static Bytes blobPreimage( private static Bytes blobPreimage(
@ -1020,7 +1018,7 @@ public class Transaction
RLP.encode( RLP.encode(
rlpOutput -> { rlpOutput -> {
rlpOutput.startList(); rlpOutput.startList();
AccessListTransactionEncoder.encodeAccessListInner( TransactionEncoder.encodeAccessListInner(
chainId, nonce, gasPrice, gasLimit, to, value, payload, accessList, rlpOutput); chainId, nonce, gasPrice, gasLimit, to, value, payload, accessList, rlpOutput);
rlpOutput.endList(); rlpOutput.endList();
}); });
@ -1092,26 +1090,10 @@ public class Transaction
sb.append("value=").append(getValue()).append(", "); sb.append("value=").append(getValue()).append(", ");
sb.append("sig=").append(getSignature()).append(", "); sb.append("sig=").append(getSignature()).append(", ");
if (chainId.isPresent()) sb.append("chainId=").append(getChainId().get()).append(", "); if (chainId.isPresent()) sb.append("chainId=").append(getChainId().get()).append(", ");
sb.append("payload=").append(getPayload());
if (transactionType.equals(TransactionType.ACCESS_LIST)) { if (transactionType.equals(TransactionType.ACCESS_LIST)) {
sb.append("accessList=").append(maybeAccessList).append(", "); sb.append(", ").append("accessList=").append(maybeAccessList);
}
if (versionedHashes.isPresent()) {
final List<VersionedHash> vhs = versionedHashes.get();
if (!vhs.isEmpty()) {
sb.append("versionedHashes=[");
sb.append(
vhs.get(0)
.toString()); // can't be empty if present, as this is checked in the constructor
for (int i = 1; i < vhs.size(); i++) {
sb.append(", ").append(vhs.get(i).toString());
} }
sb.append("], ");
}
}
if (transactionType.supportsBlob() && this.blobsWithCommitments.isPresent()) {
sb.append("numberOfBlobs=").append(blobsWithCommitments.get().getBlobs().size()).append(", ");
}
sb.append("payload=").append(getPayload());
return sb.append("}").toString(); return sb.append("}").toString();
} }

@ -1,74 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.math.BigInteger;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
class AccessListTransactionDecoder {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
public static Transaction decode(final RLPInput rlpInput) {
rlpInput.enterList();
final Transaction.Builder preSignatureTransactionBuilder =
Transaction.builder()
.type(TransactionType.ACCESS_LIST)
.chainId(BigInteger.valueOf(rlpInput.readLongScalar()))
.nonce(rlpInput.readLongScalar())
.gasPrice(Wei.of(rlpInput.readUInt256Scalar()))
.gasLimit(rlpInput.readLongScalar())
.to(
rlpInput.readBytes(
addressBytes -> addressBytes.size() == 0 ? null : Address.wrap(addressBytes)))
.value(Wei.of(rlpInput.readUInt256Scalar()))
.payload(rlpInput.readBytes())
.accessList(
rlpInput.readList(
accessListEntryRLPInput -> {
accessListEntryRLPInput.enterList();
final AccessListEntry accessListEntry =
new AccessListEntry(
Address.wrap(accessListEntryRLPInput.readBytes()),
accessListEntryRLPInput.readList(RLPInput::readBytes32));
accessListEntryRLPInput.leaveList();
return accessListEntry;
}));
final byte recId = (byte) rlpInput.readIntScalar();
final Transaction transaction =
preSignatureTransactionBuilder
.signature(
SIGNATURE_ALGORITHM
.get()
.createSignature(
rlpInput.readUInt256Scalar().toUnsignedBigInteger(),
rlpInput.readUInt256Scalar().toUnsignedBigInteger(),
recId))
.build();
rlpInput.leaveList();
return transaction;
}
}

@ -1,109 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import static org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignature;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
public class AccessListTransactionEncoder {
public static void encode(final Transaction transaction, final RLPOutput rlpOutput) {
rlpOutput.startList();
encodeAccessListInner(
transaction.getChainId(),
transaction.getNonce(),
transaction.getGasPrice().orElseThrow(),
transaction.getGasLimit(),
transaction.getTo(),
transaction.getValue(),
transaction.getPayload(),
transaction
.getAccessList()
.orElseThrow(
() ->
new IllegalStateException(
"Developer error: access list should be guaranteed to be present")),
rlpOutput);
rlpOutput.writeIntScalar(transaction.getSignature().getRecId());
writeSignature(transaction, rlpOutput);
rlpOutput.endList();
}
public static void encodeAccessListInner(
final Optional<BigInteger> chainId,
final long nonce,
final Wei gasPrice,
final long gasLimit,
final Optional<Address> to,
final Wei value,
final Bytes payload,
final List<AccessListEntry> accessList,
final RLPOutput rlpOutput) {
rlpOutput.writeBigIntegerScalar(chainId.orElseThrow());
rlpOutput.writeLongScalar(nonce);
rlpOutput.writeUInt256Scalar(gasPrice);
rlpOutput.writeLongScalar(gasLimit);
rlpOutput.writeBytes(to.map(Bytes::copy).orElse(Bytes.EMPTY));
rlpOutput.writeUInt256Scalar(value);
rlpOutput.writeBytes(payload);
/*
Access List encoding should look like this
where hex strings represent raw bytes
[
[
"0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
[
"0x0000000000000000000000000000000000000000000000000000000000000003",
"0x0000000000000000000000000000000000000000000000000000000000000007"
]
],
[
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
[]
]
] */
writeAccessList(rlpOutput, Optional.of(accessList));
}
public static void writeAccessList(
final RLPOutput out, final Optional<List<AccessListEntry>> accessListEntries) {
if (accessListEntries.isEmpty()) {
out.writeEmptyList();
} else {
out.writeList(
accessListEntries.get(),
(accessListEntry, accessListEntryRLPOutput) -> {
accessListEntryRLPOutput.startList();
out.writeBytes(accessListEntry.address());
out.writeList(
accessListEntry.storageKeys(),
(storageKeyBytes, storageKeyBytesRLPOutput) ->
storageKeyBytesRLPOutput.writeBytes(storageKeyBytes));
accessListEntryRLPOutput.endList();
});
}
}
}

@ -1,50 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import org.hyperledger.besu.datatypes.Blob;
import org.hyperledger.besu.datatypes.KZGCommitment;
import org.hyperledger.besu.datatypes.KZGProof;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.util.List;
/**
* Class responsible for decoding blob transactions from the transaction pool. Blob transactions
* have two network representations. During transaction gossip responses (PooledTransactions), the
* EIP-2718 TransactionPayload of the blob transaction is wrapped to become: rlp([tx_payload_body,
* blobs, commitments, proofs]).
*/
public class BlobPooledTransactionDecoder {
/**
* Decodes a blob transaction from the provided RLP input.
*
* @param input the RLP input to decode
* @return the decoded transaction
*/
public static Transaction decode(final RLPInput input) {
input.enterList();
final Transaction.Builder builder = Transaction.builder();
BlobTransactionDecoder.readTransactionPayloadInner(builder, input);
List<Blob> blobs = input.readList(Blob::readFrom);
List<KZGCommitment> commitments = input.readList(KZGCommitment::readFrom);
List<KZGProof> proofs = input.readList(KZGProof::readFrom);
input.leaveList();
builder.kzgBlobs(commitments, blobs, proofs);
return builder.build();
}
}

@ -1,47 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import static org.slf4j.LoggerFactory.getLogger;
import org.hyperledger.besu.datatypes.Blob;
import org.hyperledger.besu.datatypes.KZGCommitment;
import org.hyperledger.besu.datatypes.KZGProof;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.security.InvalidParameterException;
import org.slf4j.Logger;
public class BlobPooledTransactionEncoder {
private static final Logger LOG = getLogger(BlobPooledTransactionEncoder.class);
static final String NO_BLOBS_ERROR =
"Transaction with no blobsWithCommitments cannot be encoded for Pooled Transaction";
public static void encode(final Transaction transaction, final RLPOutput out) {
LOG.trace("Encoding transaction with blobs {}", transaction);
var blobsWithCommitments = transaction.getBlobsWithCommitments();
if (blobsWithCommitments.isEmpty() || blobsWithCommitments.get().getBlobs().isEmpty()) {
throw new InvalidParameterException(NO_BLOBS_ERROR);
}
out.startList();
BlobTransactionEncoder.encode(transaction, out);
out.writeList(blobsWithCommitments.get().getBlobs(), Blob::writeTo);
out.writeList(blobsWithCommitments.get().getKzgCommitments(), KZGCommitment::writeTo);
out.writeList(blobsWithCommitments.get().getKzgProofs(), KZGProof::writeTo);
out.endList();
}
}

@ -18,12 +18,16 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry; import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Blob;
import org.hyperledger.besu.datatypes.KZGCommitment;
import org.hyperledger.besu.datatypes.KZGProof;
import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
@ -32,15 +36,17 @@ public class BlobTransactionDecoder {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM = private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance); Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
/** static Transaction decode(final RLPInput input) {
* Decodes a blob transaction from the provided RLP input.
*
* @param input the RLP input to decode
* @return the decoded transaction
*/
public static Transaction decode(final RLPInput input) {
Transaction transaction; Transaction transaction;
input.enterList();
// BlobTransactionNetworkWrapper
if (input.nextIsList()) {
transaction = readNetworkWrapperInner(input);
} else {
transaction = readTransactionPayload(input); transaction = readTransactionPayload(input);
}
input.leaveList();
return transaction; return transaction;
} }
@ -50,17 +56,8 @@ public class BlobTransactionDecoder {
return builder.build(); return builder.build();
} }
/** private static void readTransactionPayloadInner(
* Reads the payload of a blob transaction from the provided RLP input. final Transaction.Builder builder, final RLPInput input) {
*
* <p>[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data,
* access_list, max_fee_per_blob_gas, blob_versioned_hashes, y_parity, r, s]
*
* @param builder the transaction builder
* @param input the RLP input to read from
*/
static void readTransactionPayloadInner(final Transaction.Builder builder, final RLPInput input) {
input.enterList();
builder builder
.type(TransactionType.BLOB) .type(TransactionType.BLOB)
.chainId(input.readBigIntegerScalar()) .chainId(input.readBigIntegerScalar())
@ -94,6 +91,18 @@ public class BlobTransactionDecoder {
input.readUInt256Scalar().toUnsignedBigInteger(), input.readUInt256Scalar().toUnsignedBigInteger(),
input.readUInt256Scalar().toUnsignedBigInteger(), input.readUInt256Scalar().toUnsignedBigInteger(),
recId)); recId));
}
private static Transaction readNetworkWrapperInner(final RLPInput input) {
final Transaction.Builder builder = Transaction.builder();
input.enterList();
readTransactionPayloadInner(builder, input);
input.leaveList(); input.leaveList();
List<Blob> blobs = input.readList(Blob::readFrom);
List<KZGCommitment> commitments = input.readList(KZGCommitment::readFrom);
List<KZGProof> proofs = input.readList(KZGProof::readFrom);
builder.kzgBlobs(commitments, blobs, proofs);
return builder.build();
} }
} }

@ -14,17 +14,25 @@
*/ */
package org.hyperledger.besu.ethereum.core.encoding; package org.hyperledger.besu.ethereum.core.encoding;
import static org.slf4j.LoggerFactory.getLogger;
import org.hyperledger.besu.datatypes.Blob;
import org.hyperledger.besu.datatypes.KZGCommitment;
import org.hyperledger.besu.datatypes.KZGProof;
import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.util.List; import java.util.List;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
public class BlobTransactionEncoder { public class BlobTransactionEncoder {
private static final Logger LOG = getLogger(BlobTransactionEncoder.class);
public static void encode(final Transaction transaction, final RLPOutput out) { public static void encodeEIP4844(final Transaction transaction, final RLPOutput out) {
out.startList(); out.startList();
out.writeBigIntegerScalar(transaction.getChainId().orElseThrow()); out.writeBigIntegerScalar(transaction.getChainId().orElseThrow());
out.writeLongScalar(transaction.getNonce()); out.writeLongScalar(transaction.getNonce());
@ -34,7 +42,7 @@ public class BlobTransactionEncoder {
out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY));
out.writeUInt256Scalar(transaction.getValue()); out.writeUInt256Scalar(transaction.getValue());
out.writeBytes(transaction.getPayload()); out.writeBytes(transaction.getPayload());
AccessListTransactionEncoder.writeAccessList(out, transaction.getAccessList()); TransactionEncoder.writeAccessList(out, transaction.getAccessList());
out.writeUInt256Scalar(transaction.getMaxFeePerBlobGas().orElseThrow()); out.writeUInt256Scalar(transaction.getMaxFeePerBlobGas().orElseThrow());
out.startList(); out.startList();
transaction transaction
@ -49,6 +57,29 @@ public class BlobTransactionEncoder {
out.endList(); out.endList();
} }
private static void encodeEIP4844Network(final Transaction transaction, final RLPOutput out) {
LOG.trace("Encoding transaction with blobs {}", transaction);
out.startList();
var blobsWithCommitments = transaction.getBlobsWithCommitments().orElseThrow();
encodeEIP4844(transaction, out);
out.writeList(blobsWithCommitments.getBlobs(), Blob::writeTo);
out.writeList(blobsWithCommitments.getKzgCommitments(), KZGCommitment::writeTo);
out.writeList(blobsWithCommitments.getKzgProofs(), KZGProof::writeTo);
out.endList();
}
public static void encodeForWireNetwork(
final Transaction transaction, final RLPOutput rlpOutput) {
rlpOutput.writeBytes(encodeOpaqueBytesNetwork(transaction));
}
private static Bytes encodeOpaqueBytesNetwork(final Transaction transaction) {
return Bytes.concatenate(
Bytes.of(transaction.getType().getSerializedType()),
RLP.encode(rlpOutput -> encodeEIP4844Network(transaction, rlpOutput)));
}
public static void writeBlobVersionedHashes( public static void writeBlobVersionedHashes(
final RLPOutput rlpOutput, final List<VersionedHash> versionedHashes) { final RLPOutput rlpOutput, final List<VersionedHash> versionedHashes) {
rlpOutput.writeList(versionedHashes, (h, out) -> out.writeBytes(h.toBytes())); rlpOutput.writeList(versionedHashes, (h, out) -> out.writeBytes(h.toBytes()));

@ -1,74 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.math.BigInteger;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
public class EIP1559TransactionDecoder {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
public static Transaction decode(final RLPInput input) {
input.enterList();
final BigInteger chainId = input.readBigIntegerScalar();
final Transaction.Builder builder =
Transaction.builder()
.type(TransactionType.EIP1559)
.chainId(chainId)
.nonce(input.readLongScalar())
.maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar()))
.maxFeePerGas(Wei.of(input.readUInt256Scalar()))
.gasLimit(input.readLongScalar())
.to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v)))
.value(Wei.of(input.readUInt256Scalar()))
.payload(input.readBytes())
.accessList(
input.readList(
accessListEntryRLPInput -> {
accessListEntryRLPInput.enterList();
final AccessListEntry accessListEntry =
new AccessListEntry(
Address.wrap(accessListEntryRLPInput.readBytes()),
accessListEntryRLPInput.readList(RLPInput::readBytes32));
accessListEntryRLPInput.leaveList();
return accessListEntry;
}));
final byte recId = (byte) input.readIntScalar();
final Transaction transaction =
builder
.signature(
SIGNATURE_ALGORITHM
.get()
.createSignature(
input.readUInt256Scalar().toUnsignedBigInteger(),
input.readUInt256Scalar().toUnsignedBigInteger(),
recId))
.build();
input.leaveList();
return transaction;
}
}

@ -1,41 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import static org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder.writeAccessList;
import static org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignatureAndRecoveryId;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.apache.tuweni.bytes.Bytes;
public class EIP1559TransactionEncoder {
public static void encode(final Transaction transaction, final RLPOutput out) {
out.startList();
out.writeBigIntegerScalar(transaction.getChainId().orElseThrow());
out.writeLongScalar(transaction.getNonce());
out.writeUInt256Scalar(transaction.getMaxPriorityFeePerGas().orElseThrow());
out.writeUInt256Scalar(transaction.getMaxFeePerGas().orElseThrow());
out.writeLongScalar(transaction.getGasLimit());
out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY));
out.writeUInt256Scalar(transaction.getValue());
out.writeBytes(transaction.getPayload());
writeAccessList(out, transaction.getAccessList());
writeSignatureAndRecoveryId(transaction, out);
out.endList();
}
}

@ -1,41 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
/**
* Enum representing the context in which a transaction is being encoded. This context is used to
* determine the appropriate encoding strategy for a transaction.
*
* <p>The context can be one of the following:
*
* <ul>
* <li>{@link #BLOCK_BODY}: The transaction is part of a block body. This context is used when
* encoding transactions for inclusion in a block.
* <li>{@link #POOLED_TRANSACTION}: The transaction is part of a transaction pool. This context is
* used when encoding transactions that are currently in the transaction pool, waiting to be
* included in a block. It is also used when encoding transactions for RPC calls related to
* the transaction pool.
* </ul>
*/
public enum EncodingContext {
/** Represents the context where the transaction is part of a block body. */
BLOCK_BODY,
/**
* Represents the context where the transaction is part of a transaction pool. This context is
* also used when encoding transactions for RPC calls related to the transaction pool.
*/
POOLED_TRANSACTION,
}

@ -1,76 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_BASE;
import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_MIN;
import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE;
import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE_PLUS_1;
import static org.hyperledger.besu.ethereum.core.Transaction.TWO;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.math.BigInteger;
import java.util.Optional;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
public class FrontierTransactionDecoder {
// Supplier for the signature algorithm
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
public static Transaction decode(final RLPInput input) {
input.enterList();
final Transaction.Builder builder =
Transaction.builder()
.type(TransactionType.FRONTIER)
.nonce(input.readLongScalar())
.gasPrice(Wei.of(input.readUInt256Scalar()))
.gasLimit(input.readLongScalar())
.to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v)))
.value(Wei.of(input.readUInt256Scalar()))
.payload(input.readBytes());
final BigInteger v = input.readBigIntegerScalar();
final byte recId;
Optional<BigInteger> chainId = Optional.empty();
if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) {
recId = v.subtract(REPLAY_UNPROTECTED_V_BASE).byteValueExact();
} else if (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0) {
chainId = Optional.of(v.subtract(REPLAY_PROTECTED_V_BASE).divide(TWO));
recId = v.subtract(TWO.multiply(chainId.get()).add(REPLAY_PROTECTED_V_BASE)).byteValueExact();
} else {
throw new RuntimeException(
String.format("An unsupported encoded `v` value of %s was found", v));
}
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger();
final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, recId);
input.leaveList();
chainId.ifPresent(builder::chainId);
return builder.signature(signature).build();
}
}

@ -1,36 +0,0 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import static org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignatureAndV;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.apache.tuweni.bytes.Bytes;
public class FrontierTransactionEncoder {
public static void encode(final Transaction transaction, final RLPOutput out) {
out.startList();
out.writeLongScalar(transaction.getNonce());
out.writeUInt256Scalar(transaction.getGasPrice().orElseThrow());
out.writeLongScalar(transaction.getGasLimit());
out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY));
out.writeUInt256Scalar(transaction.getValue());
out.writeBytes(transaction.getPayload());
writeSignatureAndV(transaction, out);
out.endList();
}
}

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

Loading…
Cancel
Save