Merge branch 'main' into add_worldupdater_to_traceEndblock

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>
pull/7386/head
Daniel Lehrner 4 months ago
commit 032c7fd2d5
  1. 20
      .github/ISSUE_TEMPLATE/release-checklist.md
  2. 20
      CHANGELOG.md
  3. 32
      acceptance-tests/tests/build.gradle
  4. 193
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/PragueAcceptanceTestHelper.java
  5. 125
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/SetCodeTransactionAcceptanceTest.java
  6. 112
      acceptance-tests/tests/src/test/resources/dev/dev_prague.json
  7. 2
      besu/src/main/java/org/hyperledger/besu/Runner.java
  8. 30
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  9. 52
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  10. 37
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java
  11. 10
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java
  12. 20
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  13. 4
      besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java
  14. 9
      besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java
  15. 4
      besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java
  16. 4
      besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java
  17. 4
      besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java
  18. 4
      besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
  19. 7
      besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java
  20. 18
      besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java
  21. 14
      besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java
  22. 48
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  23. 3
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  24. 2
      besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java
  25. 8
      besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java
  26. 74
      besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommandTest.java
  27. 1
      besu/src/test/resources/complete_config.toml
  28. 1
      besu/src/test/resources/everything_config.toml
  29. 23
      consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java
  30. 21
      consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java
  31. 4
      consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java
  32. 4
      consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java
  33. 12
      consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java
  34. 5
      consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java
  35. 5
      consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java
  36. 4
      consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java
  37. 23
      consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java
  38. 5
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java
  39. 4
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java
  40. 5
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java
  41. 19
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java
  42. 20
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java
  43. 33
      consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java
  44. 5
      consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java
  45. 4
      consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java
  46. 34
      consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java
  47. 5
      consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java
  48. 5
      consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java
  49. 30
      crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java
  50. 50
      crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java
  51. 82
      datatypes/src/main/java/org/hyperledger/besu/datatypes/SetCodeAuthorization.java
  52. 2
      datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java
  53. 14
      datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java
  54. 18
      datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java
  55. 5
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java
  56. 14
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java
  57. 9
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePayloadStatusResult.java
  58. 12
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java
  59. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java
  60. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java
  61. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java
  62. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java
  63. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java
  64. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java
  65. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java
  66. 21
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java
  67. 2
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java
  68. 3
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/ProcessingResultTransactionSelector.java
  69. 4
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java
  70. 41
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java
  71. 5
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java
  72. 5
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java
  73. 24
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java
  74. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainDataPruner.java
  75. 260
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SetCodeAuthorization.java
  76. 89
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
  77. 116
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoder.java
  78. 89
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoder.java
  79. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java
  80. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
  81. 25
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java
  82. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java
  83. 95
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java
  84. 88
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AuthorityProcessor.java
  85. 125
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java
  86. 42
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java
  87. 209
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java
  88. 276
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
  89. 56
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
  90. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
  91. 32
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java
  92. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java
  93. 199
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/MainnetParallelBlockProcessor.java
  94. 268
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessor.java
  95. 133
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedTransactionContext.java
  96. 114
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetector.java
  97. 20
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateMutableWorldStateUpdater.java
  98. 44
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoopBonsaiCachedMerkleTrieLoader.java
  99. 12
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java
  100. 12
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -8,8 +8,8 @@ assignees: ''
---
- [ ] Confirm anything outstanding for release with other maintainers on #besu-release in Discord
- [ ] Notify maintainers about updating changelog for in-flight PRs
- [ ] Update changelog if necessary, and merge a PR for it to main
- [ ] Notify maintainers about updating changelog for in-flight PRs
- [ ] Optional: for hotfixes, create a release branch and cherry-pick, e.g. `release-<version>-hotfix`
- [ ] Optional: create a PR into main from the hotfix branch to see the CI checks pass
- [ ] On the appropriate branch/commit, create a calver tag for the release candidate, format example: `24.4.0-RC2`
@ -18,18 +18,14 @@ assignees: ''
- [ ] Sign off burn-in; convey burn-in results in #besu-release in Discord
- [ ] Using the same git sha, create a calver tag for the FULL RELEASE, example format `24.4.0`
- [ ] Using the FULL RELEASE tag, create a release in github to trigger the workflows. Once published:
- makes the release "latest" in github
- this is now public and notifies subscribed users
- makes the release "latest" in github
- publishes artefacts and version-specific docker tags
- publishes the docker `latest` tag variants
- [ ] Draft homebrew PR
- [ ] Draft documentation release
- [ ] Ensure binary SHAs are correct on the release page
- [ ] Docker release startup test:
- `docker run hyperledger/besu:<version>`
- `docker run hyperledger/besu:<version>-arm64`
- `docker run --platform linux/amd64 hyperledger/besu:<version>-amd64`
- `docker run --pull=always hyperledger/besu:latest` (check version is <version>)
- [ ] Merge homebrew PR
- [ ] Publish Docs Release
- [ ] Check binary SHAs are correct on the release page
- [ ] Check "Container Verify" GitHub workflow has run successfully
- [ ] Create homebrew release - run https://github.com/hyperledger/homebrew-besu/actions/workflows/update-version.yml
- [ ] Create besu-docs release - https://github.com/hyperledger/besu-docs/releases/new
- Copy release notes from besu
- If publishing the release in github doesn't automatically trigger this workflow, then manually run https://github.com/hyperledger/besu-docs/actions/workflows/update-version.yml
- [ ] Social announcements

@ -2,21 +2,39 @@
## Next release
### Upcoming Breaking Changes
- Receipt compaction will be enabled by default in a future version of Besu. After this change it will not be possible to downgrade to the previous Besu version.
- --Xbonsai-limit-trie-logs-enabled is deprecated, use --bonsai-limit-trie-logs-enabled instead
- --Xbonsai-trie-logs-pruning-window-size is deprecated, use --bonsai-trie-logs-pruning-window-size instead
- `besu storage x-trie-log` subcommand is deprecated, use `besu storage trie-log` instead
### Breaking Changes
- Remove deprecated sync modes (X_SNAP and X_CHECKPOINT). Use SNAP and CHECKPOINT instead [#7309](https://github.com/hyperledger/besu/pull/7309)
- Remove PKI-backed QBFT (deprecated in 24.5.1) Other forms of QBFT remain unchanged. [#7293](https://github.com/hyperledger/besu/pull/7293)
- Do not maintain connections to PoA bootnodes [#7358](https://github.com/hyperledger/besu/pull/7358). See [#7314](https://github.com/hyperledger/besu/pull/7314) for recommended alternative behaviour.
- Added world state to traceEndBlock [#7386](https://github.com/hyperledger/besu/pull/7386)
### Additions and Improvements
- `--Xsnapsync-bft-enabled` option enables experimental support for snap sync with IBFT/QBFT permissioned Bonsai-DB chains [#7140](https://github.com/hyperledger/besu/pull/7140)
- Add support to load external profiles using `--profile` [#7265](https://github.com/hyperledger/besu/issues/7265)
- `privacy-nonce-always-increments` option enables private transactions to always increment the nonce, even if the transaction is invalid [#6593](https://github.com/hyperledger/besu/pull/6593)
- Add `block-test` subcommand to the evmtool which runs blockchain reference tests [#7310](https://github.com/hyperledger/besu/pull/7310)
- Added `block-test` subcommand to the evmtool which runs blockchain reference tests [#7293](https://github.com/hyperledger/besu/pull/7293)
- removed PKI backed QBFT [#7310](https://github.com/hyperledger/besu/pull/7310)
- Implement gnark-crypto for eip-2537 [#7316](https://github.com/hyperledger/besu/pull/7316)
- Improve blob size transaction selector [#7312](https://github.com/hyperledger/besu/pull/7312)
- Added EIP-7702 [#7237](https://github.com/hyperledger/besu/pull/7237)
- Implement gnark-crypto for eip-196 [#7262](https://github.com/hyperledger/besu/pull/7262)
- Add trie log pruner metrics [#7352](https://github.com/hyperledger/besu/pull/7352)
- Force bonsai-limit-trie-logs-enabled=false when sync-mode=FULL instead of startup error [#7357](https://github.com/hyperledger/besu/pull/7357)
- `--Xbonsai-parallel-tx-processing-enabled` option enables executing transactions in parallel during block processing for Bonsai nodes
- Reduce default trie log pruning window size from 30,000 to 5,000 [#7365](https://github.com/hyperledger/besu/pull/7365)
- Add option `--poa-discovery-retry-bootnodes` for PoA networks to always use bootnodes during peer refresh, not just on first start [#7314](https://github.com/hyperledger/besu/pull/7314)
### Bug fixes
- Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323)
- Prevent Besu from starting up with sync-mode=FULL and bonsai-limit-trie-logs-enabled=true for private networks [#7357](https://github.com/hyperledger/besu/pull/7357)
- Add 30 second timeout to trie log pruner preload [#7365](https://github.com/hyperledger/besu/pull/7365)
- Avoid executing pruner preload during trie log subcommands [#7366](https://github.com/hyperledger/besu/pull/7366)
## 24.7.0

@ -122,39 +122,11 @@ task acceptanceTest(type: Test) {
doFirst { mkdir "${buildDir}/jvmErrorLogs" }
}
task acceptanceTestMainnet(type: Test) {
inputs.property "integration.date", LocalTime.now() // so it runs at every invocation
exclude '**/bft/**'
exclude '**/clique/**'
exclude '**/permissioning/**'
exclude '**/privacy/**'
useJUnitPlatform {}
dependsOn(rootProject.installDist)
setSystemProperties(test.getSystemProperties())
systemProperty 'acctests.runBesuAsProcess', 'true'
systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security"
mustRunAfter rootProject.subprojects*.test
description = 'Runs MAINNET Besu acceptance tests (excluding permissioning, privacy and some other stable features).'
group = 'verification'
jvmArgs "-XX:ErrorFile=${buildDir}/jvmErrorLogs/java_err_pid%p.log"
testLogging {
exceptionFormat = 'full'
showStackTraces = true
showStandardStreams = Boolean.getBoolean('acctests.showStandardStreams')
showExceptions = true
showCauses = true
}
doFirst { mkdir "${buildDir}/jvmErrorLogs" }
}
task acceptanceTestNotPrivacy(type: Test) {
inputs.property "integration.date", LocalTime.now() // so it runs at every invocation
exclude '**/privacy/**'
exclude '**/permissioning/**'
exclude '**/bftsoak/**'
useJUnitPlatform {}
@ -164,7 +136,7 @@ task acceptanceTestNotPrivacy(type: Test) {
systemProperty 'acctests.runBesuAsProcess', 'true'
systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security"
mustRunAfter rootProject.subprojects*.test
description = 'Runs MAINNET Besu acceptance tests (excluding privacy since they run nightly, and are being refactored).'
description = 'Runs MAINNET Besu acceptance tests (excluding specific non-mainnet suites).'
group = 'verification'
jvmArgs "-XX:ErrorFile=${buildDir}/jvmErrorLogs/java_err_pid%p.log"

@ -0,0 +1,193 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.ethereum;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions;
import java.io.IOException;
import java.util.Optional;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.web3j.protocol.core.methods.response.EthBlock;
public class PragueAcceptanceTestHelper {
protected static final MediaType MEDIA_TYPE_JSON =
MediaType.parse("application/json; charset=utf-8");
private final OkHttpClient httpClient;
private final ObjectMapper mapper;
private final BesuNode besuNode;
private final EthTransactions ethTransactions;
private long blockTimeStamp = 0;
PragueAcceptanceTestHelper(final BesuNode besuNode, final EthTransactions ethTransactions) {
this.besuNode = besuNode;
this.ethTransactions = ethTransactions;
httpClient = new OkHttpClient();
mapper = new ObjectMapper();
}
public void buildNewBlock() throws IOException {
final EthBlock.Block block = besuNode.execute(ethTransactions.block());
blockTimeStamp += 1;
final Call buildBlockRequest =
createEngineCall(createForkChoiceRequest(block.getHash(), blockTimeStamp));
final String payloadId;
try (final Response buildBlockResponse = buildBlockRequest.execute()) {
payloadId =
mapper
.readTree(buildBlockResponse.body().string())
.get("result")
.get("payloadId")
.asText();
assertThat(payloadId).isNotEmpty();
}
waitFor(500);
final Call getPayloadRequest = createEngineCall(createGetPayloadRequest(payloadId));
final ObjectNode executionPayload;
final String newBlockHash;
final String parentBeaconBlockRoot;
try (final Response getPayloadResponse = getPayloadRequest.execute()) {
assertThat(getPayloadResponse.code()).isEqualTo(200);
executionPayload =
(ObjectNode)
mapper
.readTree(getPayloadResponse.body().string())
.get("result")
.get("executionPayload");
newBlockHash = executionPayload.get("blockHash").asText();
parentBeaconBlockRoot = executionPayload.remove("parentBeaconBlockRoot").asText();
assertThat(newBlockHash).isNotEmpty();
}
final Call newPayloadRequest =
createEngineCall(
createNewPayloadRequest(executionPayload.toString(), parentBeaconBlockRoot));
try (final Response newPayloadResponse = newPayloadRequest.execute()) {
assertThat(newPayloadResponse.code()).isEqualTo(200);
}
final Call moveChainAheadRequest = createEngineCall(createForkChoiceRequest(newBlockHash));
try (final Response moveChainAheadResponse = moveChainAheadRequest.execute()) {
assertThat(moveChainAheadResponse.code()).isEqualTo(200);
}
}
private Call createEngineCall(final String request) {
return httpClient.newCall(
new Request.Builder()
.url(besuNode.engineRpcUrl().get())
.post(RequestBody.create(request, MEDIA_TYPE_JSON))
.build());
}
private String createForkChoiceRequest(final String blockHash) {
return createForkChoiceRequest(blockHash, null);
}
private String createForkChoiceRequest(final String parentBlockHash, final Long timeStamp) {
final Optional<Long> maybeTimeStamp = Optional.ofNullable(timeStamp);
String forkChoiceRequest =
"{"
+ " \"jsonrpc\": \"2.0\","
+ " \"method\": \"engine_forkchoiceUpdatedV3\","
+ " \"params\": ["
+ " {"
+ " \"headBlockHash\": \""
+ parentBlockHash
+ "\","
+ " \"safeBlockHash\": \""
+ parentBlockHash
+ "\","
+ " \"finalizedBlockHash\": \""
+ parentBlockHash
+ "\""
+ " }";
if (maybeTimeStamp.isPresent()) {
forkChoiceRequest +=
" ,{"
+ " \"timestamp\": \""
+ Long.toHexString(maybeTimeStamp.get())
+ "\","
+ " \"prevRandao\": \"0x0000000000000000000000000000000000000000000000000000000000000000\","
+ " \"suggestedFeeRecipient\": \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\","
+ " \"withdrawals\": [],"
+ " \"parentBeaconBlockRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\""
+ " }";
}
forkChoiceRequest += " ]," + " \"id\": 67" + "}";
return forkChoiceRequest;
}
private String createGetPayloadRequest(final String payloadId) {
return "{"
+ " \"jsonrpc\": \"2.0\","
+ " \"method\": \"engine_getPayloadV4\","
+ " \"params\": [\""
+ payloadId
+ "\"],"
+ " \"id\": 67"
+ "}";
}
private String createNewPayloadRequest(
final String executionPayload, final String parentBeaconBlockRoot) {
return "{"
+ " \"jsonrpc\": \"2.0\","
+ " \"method\": \"engine_newPayloadV4\","
+ " \"params\": ["
+ executionPayload
+ ",[],"
+ "\""
+ parentBeaconBlockRoot
+ "\""
+ "],"
+ " \"id\": 67"
+ "}";
}
private static void waitFor(final long durationMilliSeconds) {
try {
Thread.sleep(durationMilliSeconds);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}

@ -0,0 +1,125 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.ethereum;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.SetCodeAuthorization;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase {
private static final String GENESIS_FILE = "/dev/dev_prague.json";
private static final SECP256K1 secp256k1 = new SECP256K1();
public static final Address SEND_ALL_ETH_CONTRACT_ADDRESS =
Address.fromHexStringStrict("0000000000000000000000000000000000009999");
private final Account authorizer =
accounts.createAccount(
Address.fromHexStringStrict("8da48afC965480220a3dB9244771bd3afcB5d895"));
public static final Bytes AUTHORIZER_PRIVATE_KEY =
Bytes.fromHexString("11f2e7b6a734ab03fa682450e0d4681d18a944f8b83c99bf7b9b4de6c0f35ea1");
private final Account transactionSponsor =
accounts.createAccount(
Address.fromHexStringStrict("a05b21E5186Ce93d2a226722b85D6e550Ac7D6E3"));
public static final Bytes TRANSACTION_SPONSOR_PRIVATE_KEY =
Bytes.fromHexString("3a4ff6d22d7502ef2452368165422861c01a0f72f851793b372b87888dc3c453");
private BesuNode besuNode;
private PragueAcceptanceTestHelper testHelper;
@BeforeEach
void setUp() throws IOException {
besuNode = besu.createExecutionEngineGenesisNode("besuNode", GENESIS_FILE);
cluster.start(besuNode);
testHelper = new PragueAcceptanceTestHelper(besuNode, ethTransactions);
}
/**
* At the beginning of the test both the authorizer and the transaction sponsor have a balance of
* 90000 ETH. The authorizer creates an authorization for a contract that send all its ETH to any
* given address. The transaction sponsor created a 7702 transaction with it and sends all the ETH
* from the authorizer to itself. The authorizer balance should be 0 and the transaction sponsor
* balance should be 180000 ETH minus the transaction costs.
*/
@Test
public void shouldTransferAllEthOfAuthorizerToSponsor() throws IOException {
// 7702 transaction
final org.hyperledger.besu.datatypes.SetCodeAuthorization authorization =
SetCodeAuthorization.builder()
.chainId(BigInteger.valueOf(20211))
.address(SEND_ALL_ETH_CONTRACT_ADDRESS)
.signAndBuild(
secp256k1.createKeyPair(
secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger())));
final Transaction tx =
Transaction.builder()
.type(TransactionType.SET_CODE)
.chainId(BigInteger.valueOf(20211))
.nonce(0)
.maxPriorityFeePerGas(Wei.of(1000000000))
.maxFeePerGas(Wei.fromHexString("0x02540BE400"))
.gasLimit(1000000)
.to(Address.fromHexStringStrict(authorizer.getAddress()))
.value(Wei.ZERO)
.payload(Bytes32.leftPad(Bytes.fromHexString(transactionSponsor.getAddress())))
.accessList(List.of())
.setCodeTransactionPayloads(List.of(authorization))
.signAndBuild(
secp256k1.createKeyPair(
secp256k1.createPrivateKey(
TRANSACTION_SPONSOR_PRIVATE_KEY.toUnsignedBigInteger())));
final String txHash =
besuNode.execute(ethTransactions.sendRawTransaction(tx.encoded().toHexString()));
testHelper.buildNewBlock();
Optional<TransactionReceipt> maybeTransactionReceipt =
besuNode.execute(ethTransactions.getTransactionReceipt(txHash));
assertThat(maybeTransactionReceipt).isPresent();
cluster.verify(authorizer.balanceEquals(0));
final String gasPriceWithout0x =
maybeTransactionReceipt.get().getEffectiveGasPrice().substring(2);
final BigInteger txCost =
maybeTransactionReceipt.get().getGasUsed().multiply(new BigInteger(gasPriceWithout0x, 16));
BigInteger expectedSponsorBalance = new BigInteger("180000000000000000000000").subtract(txCost);
cluster.verify(transactionSponsor.balanceEquals(Amount.wei(expectedSponsorBalance)));
}
}

File diff suppressed because one or more lines are too long

@ -253,7 +253,7 @@ public class Runner implements AutoCloseable {
try {
shutdown.await();
} catch (final InterruptedException e) {
LOG.debug("Interrupted while waiting for service " + serviceName + " to stop", e);
LOG.debug("Interrupted while waiting for service {} to stop {}", serviceName, e);
Thread.currentThread().interrupt();
}
}

@ -195,6 +195,7 @@ public class RunnerBuilder {
private boolean legacyForkIdEnabled;
private Optional<EnodeDnsConfiguration> enodeDnsConfiguration;
private List<SubnetInfo> allowedSubnets = new ArrayList<>();
private boolean poaDiscoveryRetryBootnodes = true;
/** Instantiates a new Runner builder. */
public RunnerBuilder() {}
@ -603,6 +604,17 @@ public class RunnerBuilder {
return this;
}
/**
* Flag to indicate if peer table refreshes should always query bootnodes
*
* @param poaDiscoveryRetryBootnodes whether to always query bootnodes
* @return the runner builder
*/
public RunnerBuilder poaDiscoveryRetryBootnodes(final boolean poaDiscoveryRetryBootnodes) {
this.poaDiscoveryRetryBootnodes = poaDiscoveryRetryBootnodes;
return this;
}
/**
* Build Runner instance.
*
@ -625,6 +637,8 @@ public class RunnerBuilder {
bootstrap = ethNetworkConfig.bootNodes();
}
discoveryConfiguration.setBootnodes(bootstrap);
discoveryConfiguration.setIncludeBootnodesOnPeerRefresh(
besuController.getGenesisConfigOptions().isPoa() && poaDiscoveryRetryBootnodes);
LOG.info("Resolved {} bootnodes.", bootstrap.size());
LOG.debug("Bootnodes = {}", bootstrap);
discoveryConfiguration.setDnsDiscoveryURL(ethNetworkConfig.dnsDiscoveryUrl());
@ -694,6 +708,7 @@ public class RunnerBuilder {
final boolean fallbackEnabled = natMethod == NatMethod.AUTO || natMethodFallbackEnabled;
final NatService natService = new NatService(buildNatManager(natMethod), fallbackEnabled);
final NetworkBuilder inactiveNetwork = caps -> new NoopP2PNetwork();
final NetworkBuilder activeNetwork =
caps -> {
return DefaultP2PNetwork.builder()
@ -792,20 +807,7 @@ public class RunnerBuilder {
LOG.debug("added ethash observer: {}", stratumServer.get());
}
final Stream<EnodeURL> maintainedPeers;
if (besuController.getGenesisConfigOptions().isPoa()) {
// In a permissioned chain Besu should maintain connections to both static nodes and
// bootnodes, which includes retries periodically
maintainedPeers =
sanitizePeers(
network,
Stream.concat(staticNodes.stream(), bootnodes.stream()).collect(Collectors.toList()));
LOG.debug("Added bootnodes to the maintained peer list");
} else {
// In a public chain only maintain connections to static nodes
maintainedPeers = sanitizePeers(network, staticNodes);
}
maintainedPeers
sanitizePeers(network, staticNodes)
.map(DefaultPeer::fromEnodeURL)
.forEach(peerNetwork::addMaintainedConnectionPeer);

@ -139,6 +139,7 @@ import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract;
import org.hyperledger.besu.evm.precompile.BigIntegerModularExponentiationPrecompiledContract;
import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract;
@ -513,6 +514,19 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
}
// Boolean option to set that in a PoA network the bootnodes should always be queried during
// peer table refresh. If this flag is disabled bootnodes are only sent FINDN requests on first
// startup, meaning that an offline bootnode or network outage at the client can prevent it
// discovering any peers without a restart.
@Option(
names = {"--poa-discovery-retry-bootnodes"},
description =
"Always use of bootnodes for discovery in PoA networks. Disabling this reverts "
+ " to the same behaviour as non-PoA networks, where neighbours are only discovered from bootnodes on first startup."
+ "(default: ${DEFAULT-VALUE})",
arity = "1")
private final Boolean poaDiscoveryRetryBootnodes = true;
private Collection<Bytes> bannedNodeIds = new ArrayList<>();
// Used to discover the default IP of the client.
@ -1574,7 +1588,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private void validateDataStorageOptions() {
dataStorageOptions.validate(commandLine, syncMode);
dataStorageOptions.validate(commandLine);
}
private void validateRequiredOptions() {
@ -1901,6 +1915,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.privacyParameters(privacyParameters())
.clock(Clock.systemUTC())
.isRevertReasonEnabled(isRevertReasonEnabled)
.isParallelTxProcessingEnabled(
dataStorageConfiguration.getUnstable().isParallelTxProcessingEnabled())
.storageProvider(storageProvider)
.gasLimitCalculator(
miningParametersSupplier.get().getTargetGasLimit().isPresent()
@ -2231,10 +2247,41 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
return miningParameters;
}
private DataStorageConfiguration getDataStorageConfiguration() {
/**
* Get the data storage configuration
*
* @return the data storage configuration
*/
public DataStorageConfiguration getDataStorageConfiguration() {
if (dataStorageConfiguration == null) {
dataStorageConfiguration = dataStorageOptions.toDomainObject();
}
if (SyncMode.FULL.equals(getDefaultSyncModeIfNotSet())
&& DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())
&& dataStorageConfiguration.getBonsaiLimitTrieLogsEnabled()) {
if (CommandLineUtils.isOptionSet(
commandLine, DataStorageOptions.BONSAI_LIMIT_TRIE_LOGS_ENABLED)) {
throw new ParameterException(
commandLine,
String.format(
"Cannot enable %s with --sync-mode=%s and --data-storage-format=%s. You must set %s or use a different sync-mode",
DataStorageOptions.BONSAI_LIMIT_TRIE_LOGS_ENABLED,
SyncMode.FULL,
DataStorageFormat.BONSAI,
DataStorageOptions.BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false"));
}
dataStorageConfiguration =
ImmutableDataStorageConfiguration.copyOf(dataStorageConfiguration)
.withBonsaiLimitTrieLogsEnabled(false);
logger.warn(
"Forcing {}, since it cannot be enabled with --sync-mode={} and --data-storage-format={}.",
DataStorageOptions.BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false",
SyncMode.FULL,
DataStorageFormat.BONSAI);
}
return dataStorageConfiguration;
}
@ -2322,6 +2369,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.rpcEndpointService(rpcEndpointServiceImpl)
.enodeDnsConfiguration(getEnodeDnsConfiguration())
.allowedSubnets(p2PDiscoveryOptionGroup.allowedSubnets)
.poaDiscoveryRetryBootnodes(p2PDiscoveryOptionGroup.poaDiscoveryRetryBootnodes)
.build();
addShutdownHook(runner);

@ -24,7 +24,6 @@ import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
@ -63,7 +62,8 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
arity = "1")
private Long bonsaiMaxLayersToLoad = DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD;
private static final String BONSAI_LIMIT_TRIE_LOGS_ENABLED = "--bonsai-limit-trie-logs-enabled";
/** The bonsai limit trie logs enabled option name */
public static final String BONSAI_LIMIT_TRIE_LOGS_ENABLED = "--bonsai-limit-trie-logs-enabled";
/** The bonsai trie logs pruning window size. */
public static final String BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE =
@ -122,6 +122,14 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
"Enables code storage using code hash instead of by account hash. (default: ${DEFAULT-VALUE})")
private boolean bonsaiCodeUsingCodeHashEnabled = DEFAULT_BONSAI_CODE_USING_CODE_HASH_ENABLED;
@CommandLine.Option(
hidden = true,
names = {"--Xbonsai-parallel-tx-processing-enabled"},
arity = "1",
description =
"Enables parallelization of transactions to optimize processing speed by concurrently loading and executing necessary data in advance. (default: ${DEFAULT-VALUE})")
private Boolean isParallelTxProcessingEnabled = false;
/** Default Constructor. */
Unstable() {}
}
@ -139,19 +147,10 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
* Validates the data storage options
*
* @param commandLine the full commandLine to check all the options specified by the user
* @param syncMode the sync mode
*/
public void validate(final CommandLine commandLine, final SyncMode syncMode) {
if (DataStorageFormat.BONSAI == dataStorageFormat && bonsaiLimitTrieLogsEnabled) {
if (SyncMode.FULL == syncMode) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
"Cannot enable %s with sync-mode %s. You must set %s or use a different sync-mode",
BONSAI_LIMIT_TRIE_LOGS_ENABLED,
SyncMode.FULL,
BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false"));
}
public void validate(final CommandLine commandLine) {
if (DataStorageFormat.BONSAI == dataStorageFormat) {
if (bonsaiLimitTrieLogsEnabled) {
if (bonsaiMaxLayersToLoad < MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT) {
throw new CommandLine.ParameterException(
commandLine,
@ -178,6 +177,13 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
bonsaiMaxLayersToLoad));
}
}
} else {
if (unstableOptions.isParallelTxProcessingEnabled) {
throw new CommandLine.ParameterException(
commandLine,
"Transaction parallelization is not supported unless operating in a 'diffbased' mode, such as Bonsai.");
}
}
}
/**
@ -198,6 +204,8 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
domainObject.getUnstable().getBonsaiFullFlatDbEnabled();
dataStorageOptions.unstableOptions.bonsaiCodeUsingCodeHashEnabled =
domainObject.getUnstable().getBonsaiCodeStoredByCodeHashEnabled();
dataStorageOptions.unstableOptions.isParallelTxProcessingEnabled =
domainObject.getUnstable().isParallelTxProcessingEnabled();
return dataStorageOptions;
}
@ -214,6 +222,7 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
ImmutableDataStorageConfiguration.Unstable.builder()
.bonsaiFullFlatDbEnabled(unstableOptions.bonsaiFullFlatDbEnabled)
.bonsaiCodeStoredByCodeHashEnabled(unstableOptions.bonsaiCodeUsingCodeHashEnabled)
.isParallelTxProcessingEnabled(unstableOptions.isParallelTxProcessingEnabled)
.build())
.build();
}

@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogPruner;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.io.IOException;
@ -82,7 +83,14 @@ public class TrieLogSubCommand implements Runnable {
}
private static BesuController createBesuController() {
return parentCommand.besuCommand.buildController();
final DataStorageConfiguration config = parentCommand.besuCommand.getDataStorageConfiguration();
// disable limit trie logs to avoid preloading during subcommand execution
return parentCommand
.besuCommand
.getControllerBuilder()
.dataStorageConfiguration(
ImmutableDataStorageConfiguration.copyOf(config).withBonsaiLimitTrieLogsEnabled(false))
.build();
}
@Command(

@ -203,6 +203,9 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
private int numberOfBlocksToCache = 0;
/** whether parallel transaction processing is enabled or not */
protected boolean isParallelTxProcessingEnabled;
/** Instantiates a new Besu controller builder. */
protected BesuControllerBuilder() {}
@ -512,6 +515,20 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
return this;
}
/**
* Sets whether parallel transaction processing is enabled. When parallel transaction processing
* is enabled, transactions within a block can be processed in parallel and potentially improving
* performance
*
* @param isParallelTxProcessingEnabled true to enable parallel transaction
* @return the besu controller
*/
public BesuControllerBuilder isParallelTxProcessingEnabled(
final boolean isParallelTxProcessingEnabled) {
this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled;
return this;
}
/**
* Build besu controller.
*
@ -793,7 +810,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
scheduler::executeServiceTask,
dataStorageConfiguration.getBonsaiMaxLayersToLoad(),
dataStorageConfiguration.getBonsaiTrieLogPruningWindowSize(),
isProofOfStake);
isProofOfStake,
metricsSystem);
trieLogPruner.initialize();
return trieLogPruner;

@ -136,7 +136,9 @@ public class CliqueBesuControllerBuilder extends BesuControllerBuilder {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
@Override

@ -358,6 +358,15 @@ public class ConsensusScheduleBesuControllerBuilder extends BesuControllerBuilde
return super.isRevertReasonEnabled(isRevertReasonEnabled);
}
@Override
public BesuControllerBuilder isParallelTxProcessingEnabled(
final boolean isParallelTxProcessingEnabled) {
besuControllerBuilderSchedule
.values()
.forEach(b -> b.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled));
return super.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled);
}
@Override
public BesuControllerBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) {
besuControllerBuilderSchedule.values().forEach(b -> b.gasLimitCalculator(gasLimitCalculator));

@ -291,7 +291,9 @@ public class IbftBesuControllerBuilder extends BftBesuControllerBuilder {
bftExtraDataCodec().get(),
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
@Override

@ -99,7 +99,9 @@ public class MainnetBesuControllerBuilder extends BesuControllerBuilder {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
@Override

@ -177,7 +177,9 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder {
privacyParameters,
isRevertReasonEnabled,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
@Override

@ -329,7 +329,9 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
bftExtraDataCodec().get(),
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
@Override

@ -374,6 +374,13 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder {
return propagateConfig(z -> z.isRevertReasonEnabled(isRevertReasonEnabled));
}
@Override
public BesuControllerBuilder isParallelTxProcessingEnabled(
final boolean isParallelTxProcessingEnabled) {
super.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled);
return propagateConfig(z -> z.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled));
}
@Override
public BesuControllerBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) {
super.gasLimitCalculator(gasLimitCalculator);

@ -379,22 +379,20 @@ public class BesuPluginContextImpl implements BesuContext, PluginVersionsProvide
plugin ->
summary.add(
String.format(
" - %s (Version: %s)",
plugin.getClass().getSimpleName(), plugin.getVersion())));
" - %s (%s)", plugin.getClass().getSimpleName(), plugin.getVersion())));
}
// Identify and log detected but not registered (skipped) plugins
List<String> skippedPlugins =
detectedPlugins.stream()
.filter(plugin -> !registeredPlugins.contains(plugin))
.map(plugin -> plugin.getClass().getSimpleName())
.toList();
List<BesuPlugin> skippedPlugins =
detectedPlugins.stream().filter(plugin -> !registeredPlugins.contains(plugin)).toList();
if (!skippedPlugins.isEmpty()) {
summary.add("Skipped Plugins:");
summary.add("Detected but not registered:");
skippedPlugins.forEach(
pluginName ->
summary.add(String.format(" - %s (Detected but not registered)", pluginName)));
plugin ->
summary.add(
String.format(
" - %s (%s)", plugin.getClass().getSimpleName(), plugin.getVersion())));
}
summary.add(
String.format(

@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.mainnet.DefaultProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.util.Collection;
import java.util.List;
@ -177,12 +178,21 @@ public class ForkIdsNetworkConfigTest {
new MilestoneStreamingProtocolSchedule(
(DefaultProtocolSchedule)
MainnetProtocolSchedule.fromConfig(
configOptions, MiningParameters.MINING_DISABLED, new BadBlockManager()));
configOptions,
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem()));
MilestoneStreamingProtocolSchedule postMergeProtocolSchedule =
new MilestoneStreamingProtocolSchedule(
(DefaultProtocolSchedule)
MergeProtocolSchedule.create(
configOptions, false, MiningParameters.MINING_DISABLED, new BadBlockManager()));
configOptions,
false,
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem()));
final MilestoneStreamingTransitionProtocolSchedule schedule =
new MilestoneStreamingTransitionProtocolSchedule(
preMergeProtocolSchedule, postMergeProtocolSchedule);

@ -65,6 +65,7 @@ import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract;
import org.hyperledger.besu.metrics.StandardMetricCategory;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import org.hyperledger.besu.util.number.Fraction;
import org.hyperledger.besu.util.number.Percentage;
import org.hyperledger.besu.util.number.PositiveNumber;
@ -804,6 +805,28 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void poaDiscoveryRetryBootnodesValueTrueMustBeUsed() {
parseCommand("--poa-discovery-retry-bootnodes", "true");
verify(mockRunnerBuilder).poaDiscoveryRetryBootnodes(eq(true));
verify(mockRunnerBuilder).build();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void poaDiscoveryRetryBootnodesValueFalseMustBeUsed() {
parseCommand("--poa-discovery-retry-bootnodes", "false");
verify(mockRunnerBuilder).poaDiscoveryRetryBootnodes(eq(false));
verify(mockRunnerBuilder).build();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void callingWithBootnodesOptionButNoValueMustPassEmptyBootnodeList() {
parseCommand("--bootnodes");
@ -1281,13 +1304,34 @@ public class BesuCommandTest extends CommandTestAbstract {
}
@Test
public void parsesInvalidDefaultBonsaiLimitTrieLogsWhenFullSyncEnabled() {
public void bonsaiLimitTrieLogsDisabledWhenFullSyncEnabled() {
parseCommand("--sync-mode=FULL");
verify(mockControllerBuilder)
.dataStorageConfiguration(dataStorageConfigurationArgumentCaptor.capture());
final DataStorageConfiguration dataStorageConfiguration =
dataStorageConfigurationArgumentCaptor.getValue();
assertThat(dataStorageConfiguration.getDataStorageFormat()).isEqualTo(BONSAI);
assertThat(dataStorageConfiguration.getBonsaiLimitTrieLogsEnabled()).isFalse();
verify(mockLogger)
.warn(
"Forcing {}, since it cannot be enabled with --sync-mode={} and --data-storage-format={}.",
"--bonsai-limit-trie-logs-enabled=false",
SyncMode.FULL,
DataStorageFormat.BONSAI);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void parsesInvalidWhenFullSyncAndBonsaiLimitTrieLogsExplicitlyTrue() {
parseCommand("--sync-mode=FULL", "--bonsai-limit-trie-logs-enabled=true");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains("Cannot enable --bonsai-limit-trie-logs-enabled with sync-mode FULL");
.contains(
"Cannot enable --bonsai-limit-trie-logs-enabled with --sync-mode=FULL and --data-storage-format=BONSAI. You must set --bonsai-limit-trie-logs-enabled=false or use a different sync-mode");
}
@Test

@ -276,6 +276,8 @@ public abstract class CommandTestAbstract {
when(mockControllerBuilder.privacyParameters(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.clock(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.isRevertReasonEnabled(false)).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.isParallelTxProcessingEnabled(false))
.thenReturn(mockControllerBuilder);
when(mockControllerBuilder.storageProvider(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.gasLimitCalculator(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.requiredBlocks(any())).thenReturn(mockControllerBuilder);
@ -348,6 +350,7 @@ public abstract class CommandTestAbstract {
when(mockRunnerBuilder.apiConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.enodeDnsConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.allowedSubnets(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.poaDiscoveryRetryBootnodes(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.build()).thenReturn(mockRunner);
final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();

@ -413,7 +413,7 @@ public class TransactionPoolOptionsTest
@Test
public void maxPrioritizedTxsPerTypeWrongTxType() {
internalTestFailure(
"Invalid value for option '--tx-pool-max-prioritized-by-type' (MAP<TYPE,INTEGER>): expected one of [FRONTIER, ACCESS_LIST, EIP1559, BLOB] (case-insensitive) but was 'WRONG_TYPE'",
"Invalid value for option '--tx-pool-max-prioritized-by-type' (MAP<TYPE,INTEGER>): expected one of [FRONTIER, ACCESS_LIST, EIP1559, BLOB, SET_CODE] (case-insensitive) but was 'WRONG_TYPE'",
"--tx-pool-max-prioritized-by-type",
"WRONG_TYPE=1");
}

@ -55,14 +55,6 @@ public class DataStorageOptionsTest
"--bonsai-limit-trie-logs-enabled=false");
}
@Test
public void bonsaiTrieLogPruningWindowSizeShouldBePositive2() {
internalTestFailure(
"Cannot enable --bonsai-limit-trie-logs-enabled with sync-mode FULL. You must set --bonsai-limit-trie-logs-enabled=false or use a different sync-mode",
"--sync-mode",
"FULL");
}
@Test
public void bonsaiTrieLogPruningWindowSizeShouldBePositive() {
internalTestFailure(

@ -0,0 +1,74 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.subcommands.storage;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import org.hyperledger.besu.cli.CommandTestAbstract;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import java.util.List;
import org.junit.jupiter.api.Test;
class TrieLogSubCommandTest extends CommandTestAbstract {
@Test
void limitTrieLogsDefaultDisabledForAllSubcommands() {
assertTrieLogSubcommand("prune");
assertTrieLogSubcommand("count");
assertTrieLogSubcommand("import");
assertTrieLogSubcommand("export");
}
@Test
void limitTrieLogsDisabledForAllSubcommands() {
assertTrieLogSubcommandWithExplicitLimitEnabled("prune");
assertTrieLogSubcommandWithExplicitLimitEnabled("count");
assertTrieLogSubcommandWithExplicitLimitEnabled("import");
assertTrieLogSubcommandWithExplicitLimitEnabled("export");
}
private void assertTrieLogSubcommand(final String trieLogSubcommand) {
parseCommand("storage", "trie-log", trieLogSubcommand);
assertConfigurationIsDisabledBySubcommand();
}
private void assertTrieLogSubcommandWithExplicitLimitEnabled(final String trieLogSubcommand) {
parseCommand("--bonsai-limit-trie-logs-enabled=true", "storage", "trie-log", trieLogSubcommand);
assertConfigurationIsDisabledBySubcommand();
}
private void assertConfigurationIsDisabledBySubcommand() {
verify(mockControllerBuilder, atLeastOnce())
.dataStorageConfiguration(dataStorageConfigurationArgumentCaptor.capture());
final List<DataStorageConfiguration> configs =
dataStorageConfigurationArgumentCaptor.getAllValues();
assertThat(configs.get(0).getBonsaiLimitTrieLogsEnabled()).isTrue();
assertThat(configs.get(1).getBonsaiLimitTrieLogsEnabled()).isFalse();
}
@Test
void limitTrieLogsDefaultEnabledForBesuMainCommand() {
parseCommand();
verify(mockControllerBuilder, atLeastOnce())
.dataStorageConfiguration(dataStorageConfigurationArgumentCaptor.capture());
final List<DataStorageConfiguration> configs =
dataStorageConfigurationArgumentCaptor.getAllValues();
assertThat(configs).allMatch(DataStorageConfiguration::getBonsaiLimitTrieLogsEnabled);
}
}

@ -6,6 +6,7 @@ data-path="/opt/besu" # Path
# network
discovery-enabled=false
poa-discovery-retry-bootnodes=true
bootnodes=[
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567",
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567",

@ -29,6 +29,7 @@ nat-method="NONE"
Xnat-kube-service-name="besu"
Xnat-method-fallback-enabled=true
discovery-enabled=false
poa-discovery-retry-bootnodes=true
bootnodes=[
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567",
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567",

@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder;
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.math.BigInteger;
import java.util.HashMap;
@ -64,6 +65,9 @@ public class CliqueProtocolSchedule {
* @param evmConfiguration the evm configuration
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled
* @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying
* calls
* @return the protocol schedule
*/
public static ProtocolSchedule create(
@ -74,7 +78,9 @@ public class CliqueProtocolSchedule {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
final CliqueConfigOptions cliqueConfig = config.getCliqueConfigOptions();
@ -110,7 +116,9 @@ public class CliqueProtocolSchedule {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager)
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem)
.createProtocolSchedule();
}
@ -124,6 +132,9 @@ public class CliqueProtocolSchedule {
* @param evmConfiguration the evm configuration
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled
* @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying
* calls
* @return the protocol schedule
*/
@VisibleForTesting
@ -134,7 +145,9 @@ public class CliqueProtocolSchedule {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return create(
config,
forksSchedule,
@ -143,7 +156,9 @@ public class CliqueProtocolSchedule {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
private static ProtocolSpecBuilder applyCliqueSpecificModifications(

@ -37,6 +37,7 @@ import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.time.Instant;
import java.util.List;
@ -68,7 +69,9 @@ public class CliqueProtocolScheduleTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockHeader(blockHeader(1));
final ProtocolSpec tangerineWhistleSpec = protocolSchedule.getByBlockHeader(blockHeader(2));
@ -92,7 +95,9 @@ public class CliqueProtocolScheduleTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager())
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.getByBlockHeader(blockHeader(0));
assertThat(homestead.getName()).isEqualTo("Frontier");
@ -116,7 +121,9 @@ public class CliqueProtocolScheduleTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager()))
new BadBlockManager(),
false,
new NoOpMetricsSystem()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Epoch length in config must be greater than zero");
}
@ -136,7 +143,9 @@ public class CliqueProtocolScheduleTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager()))
new BadBlockManager(),
false,
new NoOpMetricsSystem()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Epoch length in config must be greater than zero");
}
@ -160,7 +169,9 @@ public class CliqueProtocolScheduleTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
BlockHeader emptyFrontierParent =
headerBuilder

@ -106,7 +106,9 @@ public class CliqueBlockCreatorTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final Address otherAddress = Util.publicKeyToAddress(otherKeyPair.getPublicKey());
validatorList.add(otherAddress);

@ -105,7 +105,9 @@ public class CliqueMinerExecutorTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
cliqueEthContext = mock(EthContext.class, RETURNS_DEEP_STUBS);
blockHeaderBuilder = new BlockHeaderTestFixture();
}

@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder;
import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.math.BigInteger;
import java.util.HashMap;
@ -58,6 +59,9 @@ public abstract class BaseBftProtocolScheduleBuilder {
* @param evmConfiguration the evm configuration
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @param metricsSystem metricsSystem A metricSystem instance to be able to expose metrics in the
* underlying calls
* @return the protocol schedule
*/
public BftProtocolSchedule createProtocolSchedule(
@ -68,7 +72,9 @@ public abstract class BaseBftProtocolScheduleBuilder {
final BftExtraDataCodec bftExtraDataCodec,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
final Map<Long, Function<ProtocolSpecBuilder, ProtocolSpecBuilder>> specMap = new HashMap<>();
forksSchedule
@ -90,7 +96,9 @@ public abstract class BaseBftProtocolScheduleBuilder {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager)
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem)
.createProtocolSchedule();
return new BftProtocolSchedule((DefaultProtocolSchedule) protocolSchedule);
}

@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.math.BigInteger;
import java.util.List;
@ -177,7 +178,9 @@ public class CombinedProtocolScheduleFactoryTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
return new BftProtocolSchedule(
(DefaultProtocolSchedule) protocolScheduleBuilder.createProtocolSchedule());

@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.math.BigInteger;
import java.util.List;
@ -245,7 +246,9 @@ public class BaseBftProtocolScheduleBuilderTest {
bftExtraDataCodec,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
}
private BftConfigOptions createBftConfig(final BigInteger blockReward) {

@ -333,7 +333,9 @@ public class TestContextBuilder {
IBFT_EXTRA_DATA_ENCODER,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
/////////////////////////////////////////////////////////////////////////////////////
// From here down is BASICALLY taken from IbftBesuController

@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator;
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.util.Optional;
@ -46,6 +47,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
* @param evmConfiguration the evm configuration
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled
* @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying
* calls
* @return the protocol schedule
*/
public static BftProtocolSchedule create(
@ -56,7 +60,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
final BftExtraDataCodec bftExtraDataCodec,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return new IbftProtocolScheduleBuilder()
.createProtocolSchedule(
config,
@ -66,7 +72,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
bftExtraDataCodec,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
/**
@ -78,6 +86,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
* @param evmConfiguration the evm configuration
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying
* calls
* @return the protocol schedule
*/
public static BftProtocolSchedule create(
@ -86,7 +97,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
final BftExtraDataCodec bftExtraDataCodec,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return create(
config,
forksSchedule,
@ -95,7 +108,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
bftExtraDataCodec,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
@Override

@ -45,6 +45,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.math.BigInteger;
import java.util.Collection;
@ -103,7 +104,9 @@ public class IbftProtocolScheduleTest {
bftExtraDataCodec,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
}
private boolean validateHeader(

@ -121,7 +121,9 @@ public class BftBlockCreatorTest {
bftExtraDataEncoder,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final ProtocolContext protContext =
new ProtocolContext(
blockchain,

@ -79,6 +79,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.util.Subscribers;
import java.math.BigInteger;
@ -184,7 +185,9 @@ public class IbftBlockHeightManagerTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
ProtocolSchedule protocolSchedule =
new BftProtocolSchedule(

@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.math.BigInteger;
import java.util.HashMap;
@ -49,19 +50,24 @@ public class MergeProtocolSchedule {
* @param isRevertReasonEnabled the is revert reason enabled
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @return the protocol schedule
*/
public static ProtocolSchedule create(
final GenesisConfigOptions config,
final boolean isRevertReasonEnabled,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return create(
config,
PrivacyParameters.DEFAULT,
isRevertReasonEnabled,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
/**
@ -72,6 +78,7 @@ public class MergeProtocolSchedule {
* @param isRevertReasonEnabled the is revert reason enabled
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @return the protocol schedule
*/
public static ProtocolSchedule create(
@ -79,7 +86,9 @@ public class MergeProtocolSchedule {
final PrivacyParameters privacyParameters,
final boolean isRevertReasonEnabled,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
Map<Long, Function<ProtocolSpecBuilder, ProtocolSpecBuilder>> postMergeModifications =
new HashMap<>();
@ -98,7 +107,9 @@ public class MergeProtocolSchedule {
isRevertReasonEnabled,
EvmConfiguration.DEFAULT,
miningParameters,
badBlockManager)
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem)
.createProtocolSchedule();
}

@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.math.BigInteger;
import java.util.Optional;
@ -65,17 +66,30 @@ public class TransitionProtocolSchedule implements ProtocolSchedule {
* milestone starting points
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @return an initialised TransitionProtocolSchedule using post-merge defaults
*/
public static TransitionProtocolSchedule fromConfig(
final GenesisConfigOptions genesisConfigOptions,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
ProtocolSchedule preMergeProtocolSchedule =
MainnetProtocolSchedule.fromConfig(genesisConfigOptions, miningParameters, badBlockManager);
MainnetProtocolSchedule.fromConfig(
genesisConfigOptions,
miningParameters,
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
ProtocolSchedule postMergeProtocolSchedule =
MergeProtocolSchedule.create(
genesisConfigOptions, false, miningParameters, badBlockManager);
genesisConfigOptions,
false,
miningParameters,
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
return new TransitionProtocolSchedule(
preMergeProtocolSchedule, postMergeProtocolSchedule, PostMergeContext.get());
}

@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.evm.operation.InvalidOperation;
import org.hyperledger.besu.evm.operation.PrevRanDaoOperation;
import org.hyperledger.besu.evm.operation.Push0Operation;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.math.BigInteger;
@ -48,7 +49,12 @@ public class MergeProtocolScheduleTest {
final GenesisConfigOptions config = GenesisConfigFile.fromConfig(jsonInput).getConfigOptions();
final ProtocolSchedule protocolSchedule =
MergeProtocolSchedule.create(
config, false, MiningParameters.MINING_DISABLED, new BadBlockManager());
config,
false,
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockHeader(blockHeader(1));
final ProtocolSpec londonSpec = protocolSchedule.getByBlockHeader(blockHeader(1559));
@ -64,7 +70,12 @@ public class MergeProtocolScheduleTest {
final GenesisConfigOptions config = GenesisConfigFile.mainnet().getConfigOptions();
final ProtocolSchedule protocolSchedule =
MergeProtocolSchedule.create(
config, false, MiningParameters.MINING_DISABLED, new BadBlockManager());
config,
false,
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final long lastParisBlockNumber = 17034869L;
final ProtocolSpec parisSpec =
@ -100,7 +111,12 @@ public class MergeProtocolScheduleTest {
final GenesisConfigOptions config = GenesisConfigFile.fromConfig(jsonInput).getConfigOptions();
final ProtocolSchedule protocolSchedule =
MergeProtocolSchedule.create(
config, false, MiningParameters.MINING_DISABLED, new BadBlockManager());
config,
false,
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final ProtocolSpec parisSpec =
protocolSchedule.getByBlockHeader(
@ -128,7 +144,12 @@ public class MergeProtocolScheduleTest {
final GenesisConfigOptions config = GenesisConfigFile.mainnet().getConfigOptions();
final ProtocolSchedule protocolSchedule =
MergeProtocolSchedule.create(
config, false, MiningParameters.MINING_DISABLED, new BadBlockManager());
config,
false,
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final long lastParisBlockNumber = 17034869L;
final ProtocolSpec parisSpec =
@ -160,7 +181,9 @@ public class MergeProtocolScheduleTest {
GenesisConfigFile.DEFAULT.getConfigOptions(),
false,
MiningParameters.MINING_DISABLED,
new BadBlockManager())
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.getByBlockHeader(blockHeader(0));
assertThat(london.getName()).isEqualTo("Paris");

@ -21,6 +21,7 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.io.IOException;
import java.net.URI;
@ -56,6 +57,8 @@ public interface MergeGenesisConfigHelper {
getPosGenesisConfigFile().getConfigOptions(),
false,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
}
}

@ -437,7 +437,9 @@ public class TestContextBuilder {
BFT_EXTRA_DATA_ENCODER,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final BftValidatorOverrides validatorOverrides = convertBftForks(qbftForks);
final TransactionSimulator transactionSimulator =

@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.util.Optional;
@ -50,6 +51,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
* @param evmConfiguration the evm configuration
* @param miningParameters The mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying
* calls
* @return the protocol schedule
*/
public static BftProtocolSchedule create(
@ -60,7 +64,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
final BftExtraDataCodec bftExtraDataCodec,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return new QbftProtocolScheduleBuilder()
.createProtocolSchedule(
config,
@ -70,7 +76,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
bftExtraDataCodec,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
/**
@ -82,6 +90,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
* @param evmConfiguration the evm configuration
* @param miningParameters The mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying
* calls
* @return the protocol schedule
*/
public static BftProtocolSchedule create(
@ -90,7 +101,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
final BftExtraDataCodec bftExtraDataCodec,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return create(
config,
qbftForksSchedule,
@ -99,7 +112,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
bftExtraDataCodec,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
/**
@ -111,6 +126,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
* @param bftExtraDataCodec the bft extra data codec
* @param miningParameters The mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying
* calls
* @return the protocol schedule
*/
public static ProtocolSchedule create(
@ -119,7 +137,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
final boolean isRevertReasonEnabled,
final BftExtraDataCodec bftExtraDataCodec,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return create(
config,
qbftForksSchedule,
@ -128,7 +148,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder
bftExtraDataCodec,
EvmConfiguration.DEFAULT,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
@Override

@ -41,6 +41,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.math.BigInteger;
import java.util.Collection;
@ -138,7 +139,9 @@ public class QbftProtocolScheduleTest {
bftExtraDataCodec,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
}
private boolean validateHeader(

@ -78,6 +78,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.util.Subscribers;
import java.math.BigInteger;
@ -184,7 +185,9 @@ public class QbftBlockHeightManagerTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
ProtocolSchedule protocolSchedule =
new BftProtocolSchedule(

@ -34,6 +34,13 @@ public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable
super(new Blake2bfDigest());
}
@Override
public Blake2bfMessageDigest clone() throws CloneNotSupportedException {
Blake2bfMessageDigest cloned = (Blake2bfMessageDigest) super.clone();
cloned.digest = ((Blake2bfDigest) this.digest).clone();
return cloned;
}
/**
* Implementation of the `F` compression function of the Blake2b cryptographic hash function.
*
@ -43,7 +50,7 @@ public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable
*
* <p>Optimized for 64-bit platforms
*/
public static class Blake2bfDigest implements Digest {
public static class Blake2bfDigest implements Digest, Cloneable {
/** The constant MESSAGE_LENGTH_BYTES. */
public static final int MESSAGE_LENGTH_BYTES = 213;
@ -71,18 +78,18 @@ public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable
// buffer which holds serialized input for this compression function
// [ 4 bytes for rounds ][ 64 bytes for h ][ 128 bytes for m ]
// [ 8 bytes for t_0 ][ 8 bytes for t_1 ][ 1 byte for f ]
private final byte[] buffer;
private byte[] buffer;
private int bufferPos;
// deserialized inputs for f compression
private final long[] h;
private final long[] m;
private final long[] t;
private long[] h;
private long[] m;
private long[] t;
private boolean f;
private long rounds; // unsigned integer represented as long
private final long[] v;
private long[] v;
private static boolean useNative;
static {
@ -112,6 +119,17 @@ public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable
v = new long[16];
}
@Override
public Blake2bfDigest clone() throws CloneNotSupportedException {
Blake2bfDigest cloned = (Blake2bfDigest) super.clone();
cloned.buffer = this.buffer.clone();
cloned.h = this.h.clone();
cloned.m = this.m.clone();
cloned.t = this.t.clone();
cloned.v = this.v.clone();
return cloned;
}
/** Disable native. */
public static void disableNative() {
useNative = false;

@ -17,6 +17,13 @@ package org.hyperledger.besu.crypto;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.IntStream;
import org.bouncycastle.util.Pack;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -29,6 +36,16 @@ import org.junit.jupiter.params.provider.CsvFileSource;
*/
public class Blake2bfMessageDigestTest {
private static final SecureRandom SECURE_RANDOM;
static {
try {
SECURE_RANDOM = SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private Blake2bfMessageDigest messageDigest;
// output when input is all 0
@ -124,6 +141,39 @@ public class Blake2bfMessageDigestTest {
.isInstanceOf(IllegalArgumentException.class);
}
@SuppressWarnings("unchecked")
@Test
public void testDigestThreadSafety() throws ExecutionException, InterruptedException {
final byte[] input = new byte[213];
;
SECURE_RANDOM.nextBytes(input);
int numberOfHashes = 10;
CompletableFuture<byte[]>[] futures =
IntStream.range(0, numberOfHashes)
.mapToObj(
i ->
CompletableFuture.supplyAsync(
() -> {
try {
MessageDigest clonedDigest = messageDigest.clone();
clonedDigest.update(input);
byte[] digest = clonedDigest.digest();
return digest;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}))
.toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).get();
byte[] expectedHash = futures[0].get();
for (CompletableFuture<byte[]> future : futures) {
assertThat(expectedHash).isEqualTo(future.get());
}
}
@ParameterizedTest
@CsvFileSource(resources = "eip152TestCases.csv", numLinesToSkip = 1)
public void eip152TestCases(final String hexIn, final String hexExpected) {

@ -0,0 +1,82 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.datatypes;
import org.hyperledger.besu.crypto.SECPSignature;
import java.math.BigInteger;
import java.util.Optional;
/**
* SetCodeAuthorization is a data structure that represents the authorization to set code on a EOA
* account.
*/
public interface SetCodeAuthorization {
/**
* Return the chain id.
*
* @return chain id
*/
BigInteger chainId();
/**
* Return the address of the account which code will be used.
*
* @return address
*/
Address address();
/**
* Return the signature.
*
* @return signature
*/
SECPSignature signature();
/**
* Return the authorizer address.
*
* @return authorizer address of the EOA which will load the code into its account
*/
Optional<Address> authorizer();
/**
* Return a valid nonce or empty otherwise. A nonce is valid if the size of the list is exactly 1
*
* @return all the optional nonce
*/
Optional<Long> nonce();
/**
* Return the recovery id.
*
* @return byte
*/
byte v();
/**
* Return the r value of the signature.
*
* @return r value
*/
BigInteger r();
/**
* Return the s value of the signature.
*
* @return s value
*/
BigInteger s();
}

@ -94,7 +94,7 @@ public class StorageSlotKey implements Comparable<StorageSlotKey> {
@Override
public int hashCode() {
return Objects.hash(slotHash.hashCode());
return slotHash.hashCode();
}
@Override

@ -234,4 +234,18 @@ public interface Transaction {
* @return the size in bytes of the encoded transaction.
*/
int getSize();
/**
* Returns the set code transaction payload if this transaction is a 7702 transaction.
*
* @return the set code transaction payloads
*/
Optional<List<SetCodeAuthorization>> getAuthorizationList();
/**
* Returns the size of the authorization list.
*
* @return the size of the authorization list
*/
int authorizationListSize();
}

@ -27,10 +27,12 @@ public enum TransactionType {
/** Eip1559 transaction type. */
EIP1559(0x02),
/** Blob transaction type. */
BLOB(0x03);
BLOB(0x03),
/** Eip7702 transaction type. */
SET_CODE(0x04);
private static final Set<TransactionType> ACCESS_LIST_SUPPORTED_TRANSACTION_TYPES =
Set.of(ACCESS_LIST, EIP1559, BLOB);
Set.of(ACCESS_LIST, EIP1559, BLOB, SET_CODE);
private static final EnumSet<TransactionType> LEGACY_FEE_MARKET_TRANSACTION_TYPES =
EnumSet.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST);
@ -83,7 +85,8 @@ public enum TransactionType {
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB
TransactionType.BLOB,
TransactionType.SET_CODE
})
.filter(transactionType -> transactionType.typeValue == serializedTypeValue)
.findFirst()
@ -128,4 +131,13 @@ public enum TransactionType {
public boolean supportsBlob() {
return this.equals(BLOB);
}
/**
* Does transaction type require code.
*
* @return the boolean
*/
public boolean requiresSetCode() {
return this.equals(SET_CODE);
}
}

@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.util.RawBlockIterator;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.net.URL;
import java.nio.file.Paths;
@ -46,7 +47,9 @@ public class BlockchainImporter {
MainnetProtocolSchedule.fromConfig(
GenesisConfigFile.fromConfig(genesisJson).getConfigOptions(),
MiningParameters.newDefault(),
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final BlockHeaderFunctions blockHeaderFunctions =
ScheduleBasedBlockHeaderFunctions.create(protocolSchedule);
blocks = new ArrayList<>();

@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory;
public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated {
private final Optional<ScheduledProtocolSpec.Hardfork> cancun;
private final Optional<ScheduledProtocolSpec.Hardfork> supportedHardFork;
private static final Logger LOG = LoggerFactory.getLogger(EngineForkchoiceUpdatedV3.class);
public EngineForkchoiceUpdatedV3(
@ -43,7 +43,11 @@ public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated {
final MergeMiningCoordinator mergeCoordinator,
final EngineCallListener engineCallListener) {
super(vertx, protocolSchedule, protocolContext, mergeCoordinator, engineCallListener);
this.cancun = protocolSchedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Cancun"));
this.supportedHardFork =
protocolSchedule.hardforkFor(
s ->
s.fork().name().equalsIgnoreCase("Cancun")
|| s.fork().name().equalsIgnoreCase("Prague"));
}
@Override
@ -77,12 +81,12 @@ public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated {
@Override
protected ValidationResult<RpcErrorType> validateForkSupported(final long blockTimestamp) {
if (protocolSchedule.isPresent()) {
if (cancun.isPresent() && blockTimestamp >= cancun.get().milestone()) {
if (supportedHardFork.isPresent() && blockTimestamp >= supportedHardFork.get().milestone()) {
return ValidationResult.valid();
} else {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK,
"Cancun configured to start at timestamp: " + cancun.get().milestone());
"Cancun configured to start at timestamp: " + supportedHardFork.get().milestone());
}
} else {
return ValidationResult.invalid(
@ -99,7 +103,7 @@ public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated {
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
} else if (payloadAttributes.getTimestamp().longValue() == 0) {
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
} else if (payloadAttributes.getTimestamp() < cancun.get().milestone()) {
} else if (payloadAttributes.getTimestamp() < supportedHardFork.get().milestone()) {
return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.UNSUPPORTED_FORK));
} else {
return Optional.empty();

@ -19,7 +19,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngin
import java.util.Optional;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonPropertyOrder({"status", "latestValidHash", "validationError"})
@ -28,10 +30,11 @@ public class EnginePayloadStatusResult {
Optional<Hash> latestValidHash;
Optional<String> validationError;
@JsonCreator
public EnginePayloadStatusResult(
final EngineStatus status,
final Hash latestValidHash,
final Optional<String> validationError) {
@JsonProperty("status") final EngineStatus status,
@JsonProperty("latestValidHash") final Hash latestValidHash,
@JsonProperty("errorMessage") final Optional<String> validationError) {
this.status = status;
this.latestValidHash = Optional.ofNullable(latestValidHash);
this.validationError = validationError;

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.SetCodeAuthorization;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
@ -30,6 +31,7 @@ import org.apache.tuweni.bytes.Bytes;
@JsonPropertyOrder({
"accessList",
"authorizationList",
"blockHash",
"blockNumber",
"chainId",
@ -91,6 +93,9 @@ public class TransactionCompleteResult implements TransactionResult {
@JsonInclude(JsonInclude.Include.NON_NULL)
private final List<VersionedHash> versionedHashes;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final List<SetCodeAuthorization> authorizationList;
public TransactionCompleteResult(final TransactionWithMetadata tx) {
final Transaction transaction = tx.getTransaction();
final TransactionType transactionType = transaction.getType();
@ -126,6 +131,7 @@ public class TransactionCompleteResult implements TransactionResult {
this.v =
(transactionType == TransactionType.ACCESS_LIST
|| transactionType == TransactionType.EIP1559)
|| transactionType == TransactionType.SET_CODE
? Quantity.create(transaction.getYParity())
: null;
}
@ -133,6 +139,7 @@ public class TransactionCompleteResult implements TransactionResult {
this.r = Quantity.create(transaction.getR());
this.s = Quantity.create(transaction.getS());
this.versionedHashes = transaction.getVersionedHashes().orElse(null);
this.authorizationList = transaction.getAuthorizationList().orElse(null);
}
@JsonGetter(value = "accessList")
@ -246,4 +253,9 @@ public class TransactionCompleteResult implements TransactionResult {
public List<VersionedHash> getVersionedHashes() {
return versionedHashes;
}
@JsonGetter(value = "authorizationList")
public List<SetCodeAuthorization> getAuthorizationList() {
return authorizationList;
}
}

@ -109,7 +109,9 @@ public class JsonRpcHttpServiceHostAllowlistTest {
MainnetProtocolSchedule.fromConfig(
new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID),
MiningParameters.MINING_DISABLED,
new BadBlockManager()),
new BadBlockManager(),
false,
new NoOpMetricsSystem()),
mock(ProtocolContext.class),
mock(FilterManager.class),
mock(TransactionPool.class),

@ -138,7 +138,11 @@ public class JsonRpcHttpServiceLoginTest {
blockchainQueries,
synchronizer,
MainnetProtocolSchedule.fromConfig(
genesisConfigOptions, MiningParameters.MINING_DISABLED, new BadBlockManager()),
genesisConfigOptions,
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem()),
mock(ProtocolContext.class),
mock(FilterManager.class),
mock(TransactionPool.class),

@ -118,7 +118,9 @@ public class JsonRpcHttpServiceTestBase {
new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID),
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager()),
new BadBlockManager(),
false,
new NoOpMetricsSystem()),
mock(ProtocolContext.class),
mock(FilterManager.class),
mock(TransactionPool.class),

@ -123,7 +123,9 @@ public class JsonRpcHttpServiceTlsClientAuthTest {
MainnetProtocolSchedule.fromConfig(
new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID),
MiningParameters.MINING_DISABLED,
new BadBlockManager()),
new BadBlockManager(),
false,
new NoOpMetricsSystem()),
mock(ProtocolContext.class),
mock(FilterManager.class),
mock(TransactionPool.class),

@ -111,7 +111,9 @@ class JsonRpcHttpServiceTlsMisconfigurationTest {
MainnetProtocolSchedule.fromConfig(
new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID),
MiningParameters.MINING_DISABLED,
new BadBlockManager()),
new BadBlockManager(),
false,
new NoOpMetricsSystem()),
mock(ProtocolContext.class),
mock(FilterManager.class),
mock(TransactionPool.class),

@ -112,7 +112,9 @@ public class JsonRpcHttpServiceTlsTest {
MainnetProtocolSchedule.fromConfig(
new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID),
MiningParameters.MINING_DISABLED,
new BadBlockManager()),
new BadBlockManager(),
false,
new NoOpMetricsSystem()),
mock(ProtocolContext.class),
mock(FilterManager.class),
mock(TransactionPool.class),

@ -176,7 +176,9 @@ public class WebSocketServiceLoginTest {
MainnetProtocolSchedule.fromConfig(
genesisConfigOptions,
MiningParameters.MINING_DISABLED,
new BadBlockManager()),
new BadBlockManager(),
false,
new NoOpMetricsSystem()),
mock(ProtocolContext.class),
mock(FilterManager.class),
mock(TransactionPool.class),

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.blockcreation.txselection;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.INVALID_TX_EVALUATION_TOO_LONG;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.TX_EVALUATION_TOO_LONG;
@ -419,11 +420,14 @@ public class BlockTransactionSelector {
final var pendingTransaction = evaluationContext.getPendingTransaction();
// check if this tx took too much to evaluate, and in case remove it from the pool
// check if this tx took too much to evaluate, and in case it was invalid remove it from the
// pool, otherwise penalize it.
final TransactionSelectionResult actualResult =
isTimeout.get()
? transactionTookTooLong(evaluationContext)
? TX_EVALUATION_TOO_LONG
? transactionTookTooLong(evaluationContext, selectionResult)
? selectionResult.discard()
? INVALID_TX_EVALUATION_TOO_LONG
: TX_EVALUATION_TOO_LONG
: BLOCK_SELECTION_TIMEOUT
: selectionResult;
@ -441,16 +445,21 @@ public class BlockTransactionSelector {
return actualResult;
}
private boolean transactionTookTooLong(final TransactionEvaluationContext evaluationContext) {
private boolean transactionTookTooLong(
final TransactionEvaluationContext evaluationContext,
final TransactionSelectionResult selectionResult) {
final var evaluationTimer = evaluationContext.getEvaluationTimer();
if (evaluationTimer.elapsed(TimeUnit.MILLISECONDS) > blockTxsSelectionMaxTime) {
LOG.atWarn()
.setMessage(
"Transaction {} is too late for inclusion, evaluated in {} that is over the max limit of {}ms"
+ ", removing it from the pool")
"Transaction {} is too late for inclusion, with result {}, evaluated in {} that is over the max limit of {}ms"
+ ", {}")
.addArgument(evaluationContext.getPendingTransaction()::getHash)
.addArgument(selectionResult)
.addArgument(evaluationTimer)
.addArgument(blockTxsSelectionMaxTime)
.addArgument(
selectionResult.discard() ? "removing it from the pool" : "penalizing it in the pool")
.log();
return true;
}

@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory;
/**
* This class extends AbstractTransactionSelector and provides a specific implementation for
* evaluating transactions based on blobs size. It checks if a transaction supports blobs, and if
* so, checks that there is enough remaining data gas in the block to fit the blobs of the tx.
* so, checks that there is enough remaining blob gas in the block to fit the blobs of the tx.
*/
public class BlobSizeTransactionSelector extends AbstractTransactionSelector {
private static final Logger LOG = LoggerFactory.getLogger(BlobSizeTransactionSelector.class);

@ -110,7 +110,8 @@ public class ProcessingResultTransactionSelector extends AbstractTransactionSele
* @return True if the invalid reason is transient, false otherwise.
*/
private boolean isTransientValidationError(final TransactionInvalidReason invalidReason) {
return invalidReason.equals(TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE)
return invalidReason.equals(TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE)
|| invalidReason.equals(TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE)
|| invalidReason.equals(TransactionInvalidReason.NONCE_TOO_HIGH);
}
}

@ -395,7 +395,9 @@ abstract class AbstractBlockCreatorTest {
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager())
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.createProtocolSchedule())
.build();

@ -18,8 +18,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.awaitility.Awaitility.await;
import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME;
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE;
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.NONCE_TOO_LOW;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.INVALID_TX_EVALUATION_TOO_LONG;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.TX_EVALUATION_TOO_LONG;
@ -223,7 +224,9 @@ public abstract class AbstractBlockTransactionSelectorTest {
GenesisConfigFile.fromResource("/dev.json").getConfigOptions(),
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager());
new BadBlockManager(),
false,
new NoOpMetricsSystem());
final MainnetTransactionProcessor mainnetTransactionProcessor =
protocolSchedule.getByBlockHeader(blockHeader(0)).getTransactionProcessor();
@ -294,7 +297,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
final Transaction tx = createTransaction(i, Wei.of(7), 100_000);
transactionsToInject.add(tx);
if (i == 1) {
ensureTransactionIsInvalid(tx, TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE);
ensureTransactionIsInvalid(tx, TransactionInvalidReason.NONCE_TOO_LOW);
} else {
ensureTransactionIsValid(tx);
}
@ -309,8 +312,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
.containsOnly(
entry(
invalidTx,
TransactionSelectionResult.invalid(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE.name())));
TransactionSelectionResult.invalid(TransactionInvalidReason.NONCE_TOO_LOW.name())));
assertThat(results.getSelectedTransactions().size()).isEqualTo(4);
assertThat(results.getSelectedTransactions().contains(invalidTx)).isFalse();
assertThat(results.getReceipts().size()).isEqualTo(4);
@ -566,8 +568,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
ensureTransactionIsValid(validTransaction, 21_000, 0);
final Transaction invalidTransaction = createTransaction(3, Wei.of(10), 21_000);
ensureTransactionIsInvalid(
invalidTransaction, TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE);
ensureTransactionIsInvalid(invalidTransaction, TransactionInvalidReason.NONCE_TOO_LOW);
transactionPool.addRemoteTransactions(List.of(validTransaction, invalidTransaction));
@ -580,8 +581,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
.containsOnly(
entry(
invalidTransaction,
TransactionSelectionResult.invalid(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE.name())));
TransactionSelectionResult.invalid(TransactionInvalidReason.NONCE_TOO_LOW.name())));
}
@Test
@ -946,7 +946,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
@ParameterizedTest
@MethodSource("subsetOfPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOver")
public void pendingTransactionsThatTakesTooLongToEvaluateIsDroppedFromThePool(
public void pendingTransactionsThatTakesTooLongToEvaluateIsPenalized(
final boolean isPoa,
final boolean preProcessingTooLate,
final boolean processingTooLate,
@ -959,7 +959,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
postProcessingTooLate,
900,
TX_EVALUATION_TOO_LONG,
true);
false);
}
private void internalBlockSelectionTimeoutSimulation(
@ -1083,7 +1083,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
500,
BLOCK_SELECTION_TIMEOUT,
false,
UPFRONT_COST_EXCEEDS_BALANCE);
NONCE_TOO_LOW);
}
@ParameterizedTest
@ -1100,9 +1100,9 @@ public abstract class AbstractBlockTransactionSelectorTest {
processingTooLate,
postProcessingTooLate,
900,
TX_EVALUATION_TOO_LONG,
INVALID_TX_EVALUATION_TOO_LONG,
true,
UPFRONT_COST_EXCEEDS_BALANCE);
NONCE_TOO_LOW);
}
private void internalBlockSelectionTimeoutSimulationInvalidTxs(
@ -1421,15 +1421,17 @@ public abstract class AbstractBlockTransactionSelectorTest {
private static class PluginTransactionSelectionResult extends TransactionSelectionResult {
private enum PluginStatus implements Status {
PLUGIN_INVALID(false, true),
PLUGIN_INVALID_TRANSIENT(false, false);
PLUGIN_INVALID(false, true, false),
PLUGIN_INVALID_TRANSIENT(false, false, true);
private final boolean stop;
private final boolean discard;
private final boolean penalize;
PluginStatus(final boolean stop, final boolean discard) {
PluginStatus(final boolean stop, final boolean discard, final boolean penalize) {
this.stop = stop;
this.discard = discard;
this.penalize = penalize;
}
@Override
@ -1441,6 +1443,11 @@ public abstract class AbstractBlockTransactionSelectorTest {
public boolean discard() {
return discard;
}
@Override
public boolean penalize() {
return penalize;
}
}
public static final TransactionSelectionResult GENERIC_PLUGIN_INVALID_TRANSIENT =

@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.testutil.TestClock;
import org.hyperledger.besu.util.number.Fraction;
@ -60,7 +61,9 @@ public class LegacyFeeMarketBlockTransactionSelectorTest
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager())
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.createProtocolSchedule();
}

@ -43,6 +43,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.hyperledger.besu.testutil.TestClock;
import org.hyperledger.besu.util.number.Fraction;
@ -71,7 +72,9 @@ public class LondonFeeMarketBlockTransactionSelectorTest
false,
EvmConfiguration.DEFAULT,
MiningParameters.MINING_DISABLED,
new BadBlockManager())
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.createProtocolSchedule();
}

@ -97,8 +97,10 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest {
PrivacyParameters.DEFAULT,
false,
EvmConfiguration.DEFAULT,
miningParameters,
new BadBlockManager())
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.createProtocolSchedule())
.build();
@ -158,8 +160,10 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest {
PrivacyParameters.DEFAULT,
false,
EvmConfiguration.DEFAULT,
miningParameters,
new BadBlockManager())
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.createProtocolSchedule())
.build();
@ -209,8 +213,10 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest {
PrivacyParameters.DEFAULT,
false,
EvmConfiguration.DEFAULT,
miningParameters,
new BadBlockManager())
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.createProtocolSchedule();
final ExecutionContextTestFixture executionContextTestFixture =
ExecutionContextTestFixture.builder(genesisConfigFile)
@ -285,8 +291,10 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest {
PrivacyParameters.DEFAULT,
false,
EvmConfiguration.DEFAULT,
miningParameters,
new BadBlockManager())
MiningParameters.MINING_DISABLED,
new BadBlockManager(),
false,
new NoOpMetricsSystem())
.createProtocolSchedule();
final ExecutionContextTestFixture executionContextTestFixture =
ExecutionContextTestFixture.builder(genesisConfigFile)

@ -76,7 +76,7 @@ public class ChainDataPruner implements BlockAddedObserver {
if (event.isNewCanonicalHead() && blocksToBePruned >= pruningFrequency) {
long currentRetainedBlock = blockNumber - currentPruningMark + 1;
while (currentRetainedBlock > blocksToRetain) {
LOG.debug("Pruning chain data with block height of " + currentPruningMark);
LOG.debug("Pruning chain data with block height of {}", currentPruningMark);
pruneChainDataAtBlock(pruningTransaction, currentPruningMark);
currentPruningMark++;
currentRetainedBlock = blockNumber - currentPruningMark;

@ -0,0 +1,260 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core;
import org.hyperledger.besu.crypto.KeyPair;
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.Hash;
import org.hyperledger.besu.ethereum.core.encoding.SetCodeTransactionEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;
public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetCodeAuthorization {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
public static final Bytes MAGIC = Bytes.fromHexString("05");
private final BigInteger chainId;
private final Address address;
private final Optional<Long> nonce;
private final SECPSignature signature;
private Optional<Address> authorizer = Optional.empty();
private boolean isAuthorityComputed = false;
/**
* An access list entry as defined in EIP-7702
*
* @param chainId can be either the current chain id or zero
* @param address the address from which the code will be set into the EOA account
* @param nonce an optional nonce after which this auth expires
* @param signature the signature of the EOA account which will be used to set the code
*/
public SetCodeAuthorization(
final BigInteger chainId,
final Address address,
final Optional<Long> nonce,
final SECPSignature signature) {
this.chainId = chainId;
this.address = address;
this.nonce = nonce;
this.signature = signature;
}
/**
* Create access list entry.
*
* @param chainId can be either the current chain id or zero
* @param address the address from which the code will be set into the EOA account
* @param nonces the list of nonces
* @param v the recovery id
* @param r the r value of the signature
* @param s the s value of the signature
* @return SetCodeTransactionEntry
*/
@JsonCreator
public static org.hyperledger.besu.datatypes.SetCodeAuthorization createSetCodeAuthorizationEntry(
@JsonProperty("chainId") final BigInteger chainId,
@JsonProperty("address") final Address address,
@JsonProperty("nonce") final List<Long> nonces,
@JsonProperty("v") final byte v,
@JsonProperty("r") final BigInteger r,
@JsonProperty("s") final BigInteger s) {
return new SetCodeAuthorization(
chainId,
address,
Optional.ofNullable(nonces.get(0)),
SIGNATURE_ALGORITHM.get().createSignature(r, s, v));
}
@JsonProperty("chainId")
@Override
public BigInteger chainId() {
return chainId;
}
@JsonProperty("address")
@Override
public Address address() {
return address;
}
@JsonProperty("signature")
@Override
public SECPSignature signature() {
return signature;
}
@Override
public Optional<Address> authorizer() {
if (!isAuthorityComputed) {
authorizer = computeAuthority();
isAuthorityComputed = true;
}
return authorizer;
}
@Override
public Optional<Long> nonce() {
return nonce;
}
@JsonProperty("v")
@Override
public byte v() {
return signature.getRecId();
}
@JsonProperty("r")
@Override
public BigInteger r() {
return signature.getR();
}
@JsonProperty("s")
@Override
public BigInteger s() {
return signature.getS();
}
private Optional<Address> computeAuthority() {
BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
SetCodeTransactionEncoder.encodeSingleSetCodeWithoutSignature(this, rlpOutput);
final Hash hash = Hash.hash(Bytes.concatenate(MAGIC, rlpOutput.encoded()));
return SIGNATURE_ALGORITHM
.get()
.recoverPublicKeyFromSignature(hash, signature)
.map(Address::extract);
}
/**
* Create set code authorization with a builder.
*
* @return SetCodeAuthorization.Builder
*/
public static Builder builder() {
return new Builder();
}
/** Builder for SetCodeAuthorization. */
public static class Builder {
private BigInteger chainId = BigInteger.ZERO;
private Address address;
private Optional<Long> nonce = Optional.empty();
private SECPSignature signature;
/** Create a new builder. */
protected Builder() {}
/**
* Set the optional chain id.
*
* @param chainId the chain id
* @return this builder
*/
public Builder chainId(final BigInteger chainId) {
this.chainId = chainId;
return this;
}
/**
* Set the address of the authorized smart contract.
*
* @param address the address
* @return this builder
*/
public Builder address(final Address address) {
this.address = address;
return this;
}
/**
* Set the optional nonce.
*
* @param nonce the optional nonce.
* @return this builder
*/
public Builder nonces(final Optional<Long> nonce) {
this.nonce = nonce;
return this;
}
/**
* Set the signature of the authorizer account.
*
* @param signature the signature
* @return this builder
*/
public Builder signature(final SECPSignature signature) {
this.signature = signature;
return this;
}
/**
* Sign the authorization with the given key pair and return the authorization.
*
* @param keyPair the key pair
* @return SetCodeAuthorization
*/
public org.hyperledger.besu.datatypes.SetCodeAuthorization signAndBuild(final KeyPair keyPair) {
final BytesValueRLPOutput output = new BytesValueRLPOutput();
output.startList();
output.writeBigIntegerScalar(chainId);
output.writeBytes(address);
output.startList();
nonce.ifPresent(output::writeLongScalar);
output.endList();
output.endList();
signature(
SIGNATURE_ALGORITHM
.get()
.sign(Hash.hash(Bytes.concatenate(MAGIC, output.encoded())), keyPair));
return build();
}
/**
* Build the authorization.
*
* @return SetCodeAuthorization
*/
public org.hyperledger.besu.datatypes.SetCodeAuthorization build() {
if (address == null) {
throw new IllegalStateException("Address must be set");
}
if (signature == null) {
throw new IllegalStateException("Signature must be set");
}
return new SetCodeAuthorization(chainId, address, nonce, signature);
}
}
}

@ -31,6 +31,7 @@ import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.KZGCommitment;
import org.hyperledger.besu.datatypes.KZGProof;
import org.hyperledger.besu.datatypes.SetCodeAuthorization;
import org.hyperledger.besu.datatypes.Sha256Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
@ -38,6 +39,7 @@ 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.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.SetCodeTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@ -122,6 +124,7 @@ public class Transaction
private final Optional<List<VersionedHash>> versionedHashes;
private final Optional<BlobsWithCommitments> blobsWithCommitments;
private final Optional<List<SetCodeAuthorization>> maybeAuthorizationList;
public static Builder builder() {
return new Builder();
@ -177,7 +180,8 @@ public class Transaction
final Address sender,
final Optional<BigInteger> chainId,
final Optional<List<VersionedHash>> versionedHashes,
final Optional<BlobsWithCommitments> blobsWithCommitments) {
final Optional<BlobsWithCommitments> blobsWithCommitments,
final Optional<List<SetCodeAuthorization>> maybeAuthorizationList) {
if (!forCopy) {
if (transactionType.requiresChainId()) {
@ -213,6 +217,12 @@ public class Transaction
checkArgument(
maxFeePerBlobGas.isPresent(), "Must specify max fee per blob gas for blob transaction");
}
if (transactionType.requiresSetCode()) {
checkArgument(
maybeAuthorizationList.isPresent(),
"Must specify set code transaction payload for set code transaction");
}
}
this.transactionType = transactionType;
@ -231,6 +241,7 @@ public class Transaction
this.chainId = chainId;
this.versionedHashes = versionedHashes;
this.blobsWithCommitments = blobsWithCommitments;
this.maybeAuthorizationList = maybeAuthorizationList;
}
/**
@ -462,6 +473,7 @@ public class Transaction
payload,
maybeAccessList,
versionedHashes.orElse(null),
maybeAuthorizationList,
chainId);
}
return hashNoSignature;
@ -668,6 +680,16 @@ public class Transaction
return blobsWithCommitments;
}
@Override
public Optional<List<SetCodeAuthorization>> getAuthorizationList() {
return maybeAuthorizationList;
}
@Override
public int authorizationListSize() {
return maybeAuthorizationList.map(List::size).orElse(0);
}
/**
* Return the list of transaction hashes extracted from the collection of Transaction passed as
* argument
@ -692,6 +714,7 @@ public class Transaction
final Bytes payload,
final Optional<List<AccessListEntry>> accessList,
final List<VersionedHash> versionedHashes,
final Optional<List<SetCodeAuthorization>> authorizationList,
final Optional<BigInteger> chainId) {
if (transactionType.requiresChainId()) {
checkArgument(chainId.isPresent(), "Transaction type %s requires chainId", transactionType);
@ -736,6 +759,21 @@ public class Transaction
new IllegalStateException(
"Developer error: the transaction should be guaranteed to have an access list here")),
chainId);
case SET_CODE ->
setCodePreimage(
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gasLimit,
to,
value,
payload,
chainId,
accessList,
authorizationList.orElseThrow(
() ->
new IllegalStateException(
"Developer error: the transaction should be guaranteed to have a set code payload here")));
};
return keccak256(preimage);
}
@ -873,6 +911,38 @@ public class Transaction
return Bytes.concatenate(Bytes.of(TransactionType.ACCESS_LIST.getSerializedType()), encode);
}
private static Bytes setCodePreimage(
final long nonce,
final Wei maxPriorityFeePerGas,
final Wei maxFeePerGas,
final long gasLimit,
final Optional<Address> to,
final Wei value,
final Bytes payload,
final Optional<BigInteger> chainId,
final Optional<List<AccessListEntry>> accessList,
final List<SetCodeAuthorization> authorizationList) {
final Bytes encoded =
RLP.encode(
rlpOutput -> {
rlpOutput.startList();
eip1559PreimageFields(
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gasLimit,
to,
value,
payload,
chainId,
accessList,
rlpOutput);
SetCodeTransactionEncoder.encodeSetCodeInner(authorizationList, rlpOutput);
rlpOutput.endList();
});
return Bytes.concatenate(Bytes.of(TransactionType.SET_CODE.getSerializedType()), encoded);
}
@Override
public boolean equals(final Object other) {
if (!(other instanceof Transaction that)) {
@ -1040,7 +1110,8 @@ public class Transaction
sender,
chainId,
detachedVersionedHashes,
detachedBlobsWithCommitments);
detachedBlobsWithCommitments,
maybeAuthorizationList);
// copy also the computed fields, to avoid to recompute them
copiedTx.sender = this.sender;
@ -1108,6 +1179,7 @@ public class Transaction
protected Optional<BigInteger> v = Optional.empty();
protected List<VersionedHash> versionedHashes = null;
private BlobsWithCommitments blobsWithCommitments;
protected Optional<List<SetCodeAuthorization>> setCodeTransactionPayloads = Optional.empty();
public Builder copiedFrom(final Transaction toCopy) {
this.transactionType = toCopy.transactionType;
@ -1126,6 +1198,7 @@ public class Transaction
this.chainId = toCopy.chainId;
this.versionedHashes = toCopy.versionedHashes.orElse(null);
this.blobsWithCommitments = toCopy.blobsWithCommitments.orElse(null);
this.setCodeTransactionPayloads = toCopy.maybeAuthorizationList;
return this;
}
@ -1219,6 +1292,8 @@ public class Transaction
transactionType = TransactionType.EIP1559;
} else if (accessList.isPresent()) {
transactionType = TransactionType.ACCESS_LIST;
} else if (setCodeTransactionPayloads.isPresent()) {
transactionType = TransactionType.SET_CODE;
} else {
transactionType = TransactionType.FRONTIER;
}
@ -1248,7 +1323,8 @@ public class Transaction
sender,
chainId,
Optional.ofNullable(versionedHashes),
Optional.ofNullable(blobsWithCommitments));
Optional.ofNullable(blobsWithCommitments),
setCodeTransactionPayloads);
}
public Transaction signAndBuild(final KeyPair keys) {
@ -1275,6 +1351,7 @@ public class Transaction
payload,
accessList,
versionedHashes,
setCodeTransactionPayloads,
chainId),
keys);
}
@ -1298,5 +1375,11 @@ public class Transaction
this.blobsWithCommitments = blobsWithCommitments;
return this;
}
public Builder setCodeTransactionPayloads(
final List<SetCodeAuthorization> setCodeTransactionEntries) {
this.setCodeTransactionPayloads = Optional.ofNullable(setCodeTransactionEntries);
return this;
}
}
}

@ -0,0 +1,116 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.core.encoding;
import org.hyperledger.besu.crypto.SECPSignature;
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.SetCodeAuthorization;
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 SetCodeTransactionDecoder {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private SetCodeTransactionDecoder() {
// private constructor
}
public static Transaction decode(final RLPInput input) {
input.enterList();
final BigInteger chainId = input.readBigIntegerScalar();
final Transaction.Builder builder =
Transaction.builder()
.type(TransactionType.SET_CODE)
.chainId(chainId)
.nonce(input.readLongScalar())
.maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar()))
.maxFeePerGas(Wei.of(input.readUInt256Scalar()))
.gasLimit(input.readLongScalar())
.to(input.readBytes(v -> v.isEmpty() ? 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;
}))
.setCodeTransactionPayloads(
input.readList(
setCodeTransactionPayloadsRLPInput ->
decodeInnerPayload(setCodeTransactionPayloadsRLPInput)));
final byte recId = (byte) input.readUnsignedByteScalar();
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger();
input.leaveList();
final Transaction transaction =
builder.signature(SIGNATURE_ALGORITHM.get().createSignature(r, s, recId)).build();
return transaction;
}
public static org.hyperledger.besu.datatypes.SetCodeAuthorization decodeInnerPayload(
final RLPInput input) {
input.enterList();
final BigInteger chainId = input.readBigIntegerScalar();
final Address address = Address.wrap(input.readBytes());
Optional<Long> nonce = Optional.empty();
if (!input.nextIsList()) {
throw new IllegalArgumentException("Optional nonce must be an list, but isn't");
}
final long noncesSize = input.nextSize();
input.enterList();
if (noncesSize == 1) {
nonce = Optional.ofNullable(input.readLongScalar());
} else if (noncesSize > 1) {
throw new IllegalArgumentException("Nonce list may only have 1 member, if any");
}
input.leaveList();
final byte yParity = (byte) input.readUnsignedByteScalar();
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger();
input.leaveList();
final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, yParity);
return new SetCodeAuthorization(chainId, address, nonce, signature);
}
}

@ -0,0 +1,89 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.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.datatypes.SetCodeAuthorization;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
public class SetCodeTransactionEncoder {
private SetCodeTransactionEncoder() {
// private constructor
}
public static void encodeSetCodeInner(
final List<SetCodeAuthorization> payloads, final RLPOutput rlpOutput) {
rlpOutput.startList();
payloads.forEach(payload -> encodeSingleSetCode(payload, rlpOutput));
rlpOutput.endList();
}
public static void encodeSingleSetCodeWithoutSignature(
final SetCodeAuthorization payload, final RLPOutput rlpOutput) {
rlpOutput.startList();
encodeAuthorizationDetails(payload, rlpOutput);
rlpOutput.endList();
}
public static void encodeSingleSetCode(
final SetCodeAuthorization payload, final RLPOutput rlpOutput) {
rlpOutput.startList();
encodeAuthorizationDetails(payload, rlpOutput);
rlpOutput.writeIntScalar(payload.signature().getRecId());
rlpOutput.writeBigIntegerScalar(payload.signature().getR());
rlpOutput.writeBigIntegerScalar(payload.signature().getS());
rlpOutput.endList();
}
private static void encodeAuthorizationDetails(
final SetCodeAuthorization payload, final RLPOutput rlpOutput) {
rlpOutput.writeBigIntegerScalar(payload.chainId());
rlpOutput.writeBytes(payload.address().copy());
rlpOutput.startList();
payload.nonce().ifPresent(rlpOutput::writeLongScalar);
rlpOutput.endList();
}
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());
encodeSetCodeInner(
transaction
.getAuthorizationList()
.orElseThrow(
() ->
new IllegalStateException(
"Developer error: the transaction should be guaranteed to have a set code payload here")),
out);
writeSignatureAndRecoveryId(transaction, out);
out.endList();
}
}

@ -40,7 +40,9 @@ public class TransactionDecoder {
TransactionType.EIP1559,
EIP1559TransactionDecoder::decode,
TransactionType.BLOB,
BlobTransactionDecoder::decode);
BlobTransactionDecoder::decode,
TransactionType.SET_CODE,
SetCodeTransactionDecoder::decode);
private static final ImmutableMap<TransactionType, Decoder> POOLED_TRANSACTION_DECODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionDecoder::decode);

@ -39,7 +39,9 @@ public class TransactionEncoder {
TransactionType.EIP1559,
EIP1559TransactionEncoder::encode,
TransactionType.BLOB,
BlobTransactionEncoder::encode);
BlobTransactionEncoder::encode,
TransactionType.SET_CODE,
SetCodeTransactionEncoder::encode);
private static final ImmutableMap<TransactionType, Encoder> POOLED_TRANSACTION_ENCODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode);

@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
/** A ProtocolSchedule which behaves similarly to MainNet, but with a much reduced difficulty. */
public class FixedDifficultyProtocolSchedule {
@ -32,7 +33,9 @@ public class FixedDifficultyProtocolSchedule {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return new ProtocolScheduleBuilder(
config,
ProtocolSpecAdapters.create(
@ -43,7 +46,9 @@ public class FixedDifficultyProtocolSchedule {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager)
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem)
.createProtocolSchedule();
}
@ -52,27 +57,35 @@ public class FixedDifficultyProtocolSchedule {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return create(
config,
PrivacyParameters.DEFAULT,
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
public static ProtocolSchedule create(
final GenesisConfigOptions config,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return create(
config,
PrivacyParameters.DEFAULT,
false,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
}

@ -79,8 +79,7 @@ public class ForkIdManager {
.sorted()
.collect(Collectors.toUnmodifiableList());
final List<Long> allForkNumbers =
Stream.concat(blockNumberForks.stream(), timestampForks.stream())
.collect(Collectors.toList());
Stream.concat(blockNumberForks.stream(), timestampForks.stream()).toList();
this.forkNext = createForkIds();
this.allForkIds =
Stream.concat(blockNumbersForkIds.stream(), timestampsForkIds.stream())
@ -93,7 +92,7 @@ public class ForkIdManager {
public ForkId getForkIdForChainHead() {
if (legacyEth64) {
return blockNumbersForkIds.isEmpty()
? null
? new ForkId(genesisHashCrc, 0)
: blockNumbersForkIds.get(blockNumbersForkIds.size() - 1);
}
final BlockHeader header = chainHeadSupplier.get();

@ -38,6 +38,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorld
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@ -110,15 +111,7 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
protocolSpec.getBlockHashProcessor().processBlockHashes(blockchain, worldState, blockHeader);
final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(blockHeader, blockchain);
for (final Transaction transaction : transactions) {
if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) {
return new BlockProcessingResult(Optional.empty(), "provided gas insufficient");
}
final WorldUpdater worldStateUpdater = worldState.updater();
final Address miningBeneficiary =
miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);
final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);
Optional<BlockHeader> maybeParentHeader =
blockchain.getBlockHeader(blockHeader.getParentHash());
@ -133,34 +126,52 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
calculateExcessBlobGasForParent(protocolSpec, parentHeader)))
.orElse(Wei.ZERO);
final TransactionProcessingResult result =
transactionProcessor.processTransaction(
worldStateUpdater,
final Optional<PreprocessingContext> preProcessingContext =
runBlockPreProcessing(
worldState,
privateMetadataUpdater,
blockHeader,
transaction,
transactions,
miningBeneficiary,
OperationTracer.NO_TRACING,
blockHashLookup,
true,
TransactionValidationParams.processingBlock(),
privateMetadataUpdater,
blobGasPrice);
if (result.isInvalid()) {
for (int i = 0; i < transactions.size(); i++) {
final Transaction transaction = transactions.get(i);
if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) {
return new BlockProcessingResult(Optional.empty(), "provided gas insufficient");
}
final WorldUpdater blockUpdater = worldState.updater();
TransactionProcessingResult transactionProcessingResult =
getTransactionProcessingResult(
preProcessingContext,
worldState,
blockUpdater,
privateMetadataUpdater,
blockHeader,
blobGasPrice,
miningBeneficiary,
transaction,
i,
blockHashLookup);
if (transactionProcessingResult.isInvalid()) {
String errorMessage =
MessageFormat.format(
"Block processing error: transaction invalid {0}. Block {1} Transaction {2}",
result.getValidationResult().getErrorMessage(),
transactionProcessingResult.getValidationResult().getErrorMessage(),
blockHeader.getHash().toHexString(),
transaction.getHash().toHexString());
LOG.info(errorMessage);
if (worldState instanceof BonsaiWorldState) {
((BonsaiWorldStateUpdateAccumulator) worldStateUpdater).reset();
((BonsaiWorldStateUpdateAccumulator) blockUpdater).reset();
}
return new BlockProcessingResult(Optional.empty(), errorMessage);
}
worldStateUpdater.commit();
currentGasUsed += transaction.getGasLimit() - result.getGasRemaining();
blockUpdater.commit();
currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining();
if (transaction.getVersionedHashes().isPresent()) {
currentBlobGasUsed +=
(transaction.getVersionedHashes().get().size() * CancunGasCalculator.BLOB_GAS_PER_BLOB);
@ -168,7 +179,7 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
final TransactionReceipt transactionReceipt =
transactionReceiptFactory.create(
transaction.getType(), result, worldState, currentGasUsed);
transaction.getType(), transactionProcessingResult, worldState, currentGasUsed);
receipts.add(transactionReceipt);
}
if (blockHeader.getBlobGasUsed().isPresent()
@ -235,6 +246,41 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
Optional.of(new BlockProcessingOutputs(worldState, receipts, maybeRequests)));
}
protected Optional<PreprocessingContext> runBlockPreProcessing(
final MutableWorldState worldState,
final PrivateMetadataUpdater privateMetadataUpdater,
final BlockHeader blockHeader,
final List<Transaction> transactions,
final Address miningBeneficiary,
final BlockHashOperation.BlockHashLookup blockHashLookup,
final Wei blobGasPrice) {
return Optional.empty();
}
protected TransactionProcessingResult getTransactionProcessingResult(
final Optional<PreprocessingContext> preProcessingContext,
final MutableWorldState worldState,
final WorldUpdater blockUpdater,
final PrivateMetadataUpdater privateMetadataUpdater,
final BlockHeader blockHeader,
final Wei blobGasPrice,
final Address miningBeneficiary,
final Transaction transaction,
final int location,
final BlockHashLookup blockHashLookup) {
return transactionProcessor.processTransaction(
blockUpdater,
blockHeader,
transaction,
miningBeneficiary,
OperationTracer.NO_TRACING,
blockHashLookup,
true,
TransactionValidationParams.processingBlock(),
privateMetadataUpdater,
blobGasPrice);
}
protected boolean hasAvailableBlockBudget(
final BlockHeader blockHeader, final Transaction transaction, final long currentGasUsed) {
final long remainingGasBudget = blockHeader.getGasLimit() - currentGasUsed;
@ -261,4 +307,7 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
final BlockHeader header,
final List<BlockHeader> ommers,
final boolean skipZeroBlockRewards);
public interface PreprocessingContext {}
;
}

@ -0,0 +1,88 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.AccountState;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.math.BigInteger;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AuthorityProcessor {
private static final Logger LOG = LoggerFactory.getLogger(AuthorityProcessor.class);
private final Optional<BigInteger> maybeChainId;
public AuthorityProcessor(final Optional<BigInteger> maybeChainId) {
this.maybeChainId = maybeChainId;
}
public void addContractToAuthority(
final WorldUpdater worldUpdater,
final AuthorizedCodeService authorizedCodeService,
final Transaction transaction) {
transaction
.getAuthorizationList()
.get()
.forEach(
payload ->
payload
.authorizer()
.ifPresent(
authorityAddress -> {
LOG.trace("Set code authority: {}", authorityAddress);
if (maybeChainId.isPresent()
&& !payload.chainId().equals(BigInteger.ZERO)
&& !maybeChainId.get().equals(payload.chainId())) {
return;
}
final Optional<MutableAccount> maybeAccount =
Optional.ofNullable(worldUpdater.getAccount(authorityAddress));
final long accountNonce =
maybeAccount.map(AccountState::getNonce).orElse(0L);
if (payload.nonce().isPresent()
&& !payload.nonce().get().equals(accountNonce)) {
return;
}
if (authorizedCodeService.hasAuthorizedCode(authorityAddress)) {
return;
}
Optional<Account> codeAccount =
Optional.ofNullable(worldUpdater.get(payload.address()));
final Bytes code;
if (codeAccount.isPresent()) {
code = codeAccount.get().getCode();
} else {
code = Bytes.EMPTY;
}
authorizedCodeService.addAuthorizedCode(authorityAddress, code);
}));
}
}

@ -38,6 +38,7 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.processor.ContractCreationProcessor;
import org.hyperledger.besu.evm.processor.MessageCallProcessor;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.math.BigInteger;
import java.util.Collections;
@ -54,16 +55,23 @@ public class ClassicProtocolSpecs {
}
public static ProtocolSpecBuilder classicRecoveryInitDefinition(
final EvmConfiguration evmConfiguration) {
return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return MainnetProtocolSpecs.homesteadDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.blockHeaderValidatorBuilder(
feeMarket -> MainnetBlockHeaderValidator.createClassicValidator())
.name("ClassicRecoveryInit");
}
public static ProtocolSpecBuilder tangerineWhistleDefinition(
final Optional<BigInteger> chainId, final EvmConfiguration evmConfiguration) {
return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration)
final Optional<BigInteger> chainId,
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return MainnetProtocolSpecs.homesteadDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.isReplayProtectionSupported(true)
.gasCalculator(TangerineWhistleGasCalculator::new)
.transactionValidatorFactoryBuilder(
@ -74,8 +82,12 @@ public class ClassicProtocolSpecs {
}
public static ProtocolSpecBuilder dieHardDefinition(
final Optional<BigInteger> chainId, final EvmConfiguration evmConfiguration) {
return tangerineWhistleDefinition(chainId, evmConfiguration)
final Optional<BigInteger> chainId,
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return tangerineWhistleDefinition(
chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.gasCalculator(DieHardGasCalculator::new)
.difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_PAUSED)
.name("DieHard");
@ -84,8 +96,11 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder gothamDefinition(
final Optional<BigInteger> chainId,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return dieHardDefinition(chainId, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return dieHardDefinition(
chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.blockReward(MAX_BLOCK_REWARD)
.difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_DELAYED)
.blockProcessorBuilder(
@ -109,8 +124,15 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder defuseDifficultyBombDefinition(
final Optional<BigInteger> chainId,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return gothamDefinition(
chainId,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED)
.transactionValidatorFactoryBuilder(
(evm, gasLimitCalculator, feeMarket) ->
@ -123,8 +145,15 @@ public class ClassicProtocolSpecs {
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return gothamDefinition(
chainId,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.evmBuilder(MainnetEVMs::byzantium)
.evmConfiguration(evmConfiguration)
.gasCalculator(SpuriousDragonGasCalculator::new)
@ -163,8 +192,16 @@ public class ClassicProtocolSpecs {
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return atlantisDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return atlantisDefinition(
chainId,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.evmBuilder(MainnetEVMs::constantinople)
.gasCalculator(PetersburgGasCalculator::new)
.evmBuilder(MainnetEVMs::constantinople)
@ -176,8 +213,16 @@ public class ClassicProtocolSpecs {
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return aghartaDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return aghartaDefinition(
chainId,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.gasCalculator(IstanbulGasCalculator::new)
.evmBuilder(
(gasCalculator, evmConfig) ->
@ -191,8 +236,16 @@ public class ClassicProtocolSpecs {
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return phoenixDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return phoenixDefinition(
chainId,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.blockHeaderValidatorBuilder(
feeMarket ->
MainnetBlockHeaderValidator.createPgaBlockHeaderValidator(
@ -228,8 +281,16 @@ public class ClassicProtocolSpecs {
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return thanosDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return thanosDefinition(
chainId,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.gasCalculator(BerlinGasCalculator::new)
.transactionValidatorFactoryBuilder(
(evm, gasLimitCalculator, feeMarket) ->
@ -250,8 +311,16 @@ public class ClassicProtocolSpecs {
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return magnetoDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return magnetoDefinition(
chainId,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.gasCalculator(LondonGasCalculator::new)
.contractCreationProcessorBuilder(
evm ->
@ -264,8 +333,16 @@ public class ClassicProtocolSpecs {
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return mystiqueDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return mystiqueDefinition(
chainId,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
// EIP-3860
.gasCalculator(ShanghaiGasCalculator::new)
// EIP-3855

@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyCalculators;
import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.math.BigInteger;
import java.util.function.Function;
@ -40,6 +41,8 @@ public class MainnetProtocolSchedule {
* @param evmConfiguration how to configure the EVMs jumpdest cache
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled
* @param metricsSystem A metricSystem instance to expose metrics in the underlying calls
* @return A configured mainnet protocol schedule
*/
public static ProtocolSchedule fromConfig(
@ -48,7 +51,9 @@ public class MainnetProtocolSchedule {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
if (FixedDifficultyCalculators.isFixedDifficultyInConfig(config)) {
return FixedDifficultyProtocolSchedule.create(
config,
@ -56,7 +61,9 @@ public class MainnetProtocolSchedule {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
return new ProtocolScheduleBuilder(
config,
@ -66,7 +73,9 @@ public class MainnetProtocolSchedule {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager)
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem)
.createProtocolSchedule();
}
@ -79,6 +88,7 @@ public class MainnetProtocolSchedule {
* @param evmConfiguration how to configure the EVMs jumpdest cache
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @return A configured mainnet protocol schedule
*/
public static ProtocolSchedule fromConfig(
@ -86,14 +96,18 @@ public class MainnetProtocolSchedule {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return fromConfig(
config,
PrivacyParameters.DEFAULT,
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
/**
@ -104,20 +118,25 @@ public class MainnetProtocolSchedule {
* @param evmConfiguration size of
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @return A configured mainnet protocol schedule
*/
public static ProtocolSchedule fromConfig(
final GenesisConfigOptions config,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return fromConfig(
config,
PrivacyParameters.DEFAULT,
false,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
/**
@ -127,18 +146,23 @@ public class MainnetProtocolSchedule {
* starting points
* @param miningParameters the mining parameters
* @param badBlockManager the cache to use to keep invalid blocks
* @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled.
* @return A configured mainnet protocol schedule
*/
public static ProtocolSchedule fromConfig(
final GenesisConfigOptions config,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return fromConfig(
config,
PrivacyParameters.DEFAULT,
false,
EvmConfiguration.DEFAULT,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.math.BigInteger;
import java.util.Optional;
@ -29,118 +30,209 @@ public class MainnetProtocolSpecFactory {
private final OptionalLong ecip1017EraRounds;
private final EvmConfiguration evmConfiguration;
private final MiningParameters miningParameters;
private final boolean isParallelTxProcessingEnabled;
private final MetricsSystem metricsSystem;
public MainnetProtocolSpecFactory(
final Optional<BigInteger> chainId,
final boolean isRevertReasonEnabled,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
this.chainId = chainId;
this.isRevertReasonEnabled = isRevertReasonEnabled;
this.ecip1017EraRounds = ecip1017EraRounds;
this.evmConfiguration = evmConfiguration;
this.miningParameters = miningParameters;
this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled;
this.metricsSystem = metricsSystem;
}
public ProtocolSpecBuilder frontierDefinition() {
return MainnetProtocolSpecs.frontierDefinition(evmConfiguration);
return MainnetProtocolSpecs.frontierDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder homesteadDefinition() {
return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration);
return MainnetProtocolSpecs.homesteadDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder daoRecoveryInitDefinition() {
return MainnetProtocolSpecs.daoRecoveryInitDefinition(evmConfiguration);
return MainnetProtocolSpecs.daoRecoveryInitDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder daoRecoveryTransitionDefinition() {
return MainnetProtocolSpecs.daoRecoveryTransitionDefinition(evmConfiguration);
return MainnetProtocolSpecs.daoRecoveryTransitionDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder tangerineWhistleDefinition() {
return MainnetProtocolSpecs.tangerineWhistleDefinition(evmConfiguration);
return MainnetProtocolSpecs.tangerineWhistleDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder spuriousDragonDefinition() {
return MainnetProtocolSpecs.spuriousDragonDefinition(chainId, evmConfiguration);
return MainnetProtocolSpecs.spuriousDragonDefinition(
chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder byzantiumDefinition() {
return MainnetProtocolSpecs.byzantiumDefinition(
chainId, isRevertReasonEnabled, evmConfiguration);
chainId,
isRevertReasonEnabled,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder constantinopleDefinition() {
return MainnetProtocolSpecs.constantinopleDefinition(
chainId, isRevertReasonEnabled, evmConfiguration);
chainId,
isRevertReasonEnabled,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder petersburgDefinition() {
return MainnetProtocolSpecs.petersburgDefinition(
chainId, isRevertReasonEnabled, evmConfiguration);
chainId,
isRevertReasonEnabled,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder istanbulDefinition() {
return MainnetProtocolSpecs.istanbulDefinition(
chainId, isRevertReasonEnabled, evmConfiguration);
chainId,
isRevertReasonEnabled,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder muirGlacierDefinition() {
return MainnetProtocolSpecs.muirGlacierDefinition(
chainId, isRevertReasonEnabled, evmConfiguration);
chainId,
isRevertReasonEnabled,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder berlinDefinition() {
return MainnetProtocolSpecs.berlinDefinition(chainId, isRevertReasonEnabled, evmConfiguration);
return MainnetProtocolSpecs.berlinDefinition(
chainId,
isRevertReasonEnabled,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder londonDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.londonDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder arrowGlacierDefinition(
final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.arrowGlacierDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder grayGlacierDefinition(
final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.grayGlacierDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder parisDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.parisDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder shanghaiDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.shanghaiDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder cancunDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.cancunDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder cancunEOFDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.cancunEOFDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder pragueDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.pragueDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder pragueEOFDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.pragueEOFDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
/**
@ -156,7 +248,13 @@ public class MainnetProtocolSpecFactory {
*/
public ProtocolSpecBuilder futureEipsDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.futureEipsDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
/**
@ -172,57 +270,100 @@ public class MainnetProtocolSpecFactory {
public ProtocolSpecBuilder experimentalEipsDefinition(
final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.experimentalEipsDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Classic Protocol Specs
public ProtocolSpecBuilder dieHardDefinition() {
return ClassicProtocolSpecs.dieHardDefinition(chainId, evmConfiguration);
return ClassicProtocolSpecs.dieHardDefinition(
chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder gothamDefinition() {
return ClassicProtocolSpecs.gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration);
return ClassicProtocolSpecs.gothamDefinition(
chainId, ecip1017EraRounds, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder defuseDifficultyBombDefinition() {
return ClassicProtocolSpecs.defuseDifficultyBombDefinition(
chainId, ecip1017EraRounds, evmConfiguration);
chainId, ecip1017EraRounds, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem);
}
public ProtocolSpecBuilder atlantisDefinition() {
return ClassicProtocolSpecs.atlantisDefinition(
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
chainId,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder aghartaDefinition() {
return ClassicProtocolSpecs.aghartaDefinition(
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
chainId,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder phoenixDefinition() {
return ClassicProtocolSpecs.phoenixDefinition(
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
chainId,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder thanosDefinition() {
return ClassicProtocolSpecs.thanosDefinition(
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
chainId,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder magnetoDefinition() {
return ClassicProtocolSpecs.magnetoDefinition(
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
chainId,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder mystiqueDefinition() {
return ClassicProtocolSpecs.mystiqueDefinition(
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
chainId,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolSpecBuilder spiralDefinition() {
return ClassicProtocolSpecs.spiralDefinition(
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
chainId,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem);
}
}

@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.blockhash.FrontierBlockHashProcesso
import org.hyperledger.besu.ethereum.mainnet.blockhash.PragueBlockHashProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.mainnet.parallelization.MainnetParallelBlockProcessor;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater;
@ -67,6 +68,7 @@ import org.hyperledger.besu.evm.processor.ContractCreationProcessor;
import org.hyperledger.besu.evm.processor.MessageCallProcessor;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.io.IOException;
import java.math.BigInteger;
@ -101,7 +103,10 @@ public abstract class MainnetProtocolSpecs {
private MainnetProtocolSpecs() {}
public static ProtocolSpecBuilder frontierDefinition(final EvmConfiguration evmConfiguration) {
public static ProtocolSpecBuilder frontierDefinition(
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return new ProtocolSpecBuilder()
.gasCalculator(FrontierGasCalculator::new)
.gasLimitCalculatorBuilder(feeMarket -> new FrontierTargetingGasLimitCalculator())
@ -152,7 +157,10 @@ public abstract class MainnetProtocolSpecs {
.transactionReceiptFactory(MainnetProtocolSpecs::frontierTransactionReceiptFactory)
.blockReward(FRONTIER_BLOCK_REWARD)
.skipZeroBlockRewards(false)
.blockProcessorBuilder(MainnetBlockProcessor::new)
.blockProcessorBuilder(
isParallelTxProcessingEnabled
? new MainnetParallelBlockProcessor.ParallelBlockProcessorBuilder(metricsSystem)
: MainnetBlockProcessor::new)
.blockValidatorBuilder(MainnetProtocolSpecs.blockValidatorBuilder())
.blockImporterBuilder(MainnetBlockImporter::new)
.blockHeaderFunctions(new MainnetBlockHeaderFunctions())
@ -173,8 +181,11 @@ public abstract class MainnetProtocolSpecs {
return MainnetBlockValidator::new;
}
public static ProtocolSpecBuilder homesteadDefinition(final EvmConfiguration evmConfiguration) {
return frontierDefinition(evmConfiguration)
public static ProtocolSpecBuilder homesteadDefinition(
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return frontierDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.gasCalculator(HomesteadGasCalculator::new)
.evmBuilder(MainnetEVMs::homestead)
.contractCreationProcessorBuilder(
@ -190,8 +201,10 @@ public abstract class MainnetProtocolSpecs {
}
public static ProtocolSpecBuilder daoRecoveryInitDefinition(
final EvmConfiguration evmConfiguration) {
return homesteadDefinition(evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return homesteadDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.blockHeaderValidatorBuilder(feeMarket -> MainnetBlockHeaderValidator.createDaoValidator())
.blockProcessorBuilder(
(transactionProcessor,
@ -201,7 +214,16 @@ public abstract class MainnetProtocolSpecs {
skipZeroBlockRewards,
protocolSchedule) ->
new DaoBlockProcessor(
new MainnetBlockProcessor(
isParallelTxProcessingEnabled
? new MainnetParallelBlockProcessor(
transactionProcessor,
transactionReceiptFactory,
blockReward,
miningBeneficiaryCalculator,
skipZeroBlockRewards,
protocolSchedule,
metricsSystem)
: new MainnetBlockProcessor(
transactionProcessor,
transactionReceiptFactory,
blockReward,
@ -212,22 +234,33 @@ public abstract class MainnetProtocolSpecs {
}
public static ProtocolSpecBuilder daoRecoveryTransitionDefinition(
final EvmConfiguration evmConfiguration) {
return daoRecoveryInitDefinition(evmConfiguration)
.blockProcessorBuilder(MainnetBlockProcessor::new)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return daoRecoveryInitDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.blockProcessorBuilder(
isParallelTxProcessingEnabled
? new MainnetParallelBlockProcessor.ParallelBlockProcessorBuilder(metricsSystem)
: MainnetBlockProcessor::new)
.name("DaoRecoveryTransition");
}
public static ProtocolSpecBuilder tangerineWhistleDefinition(
final EvmConfiguration evmConfiguration) {
return homesteadDefinition(evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return homesteadDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.gasCalculator(TangerineWhistleGasCalculator::new)
.name("TangerineWhistle");
}
public static ProtocolSpecBuilder spuriousDragonDefinition(
final Optional<BigInteger> chainId, final EvmConfiguration evmConfiguration) {
return tangerineWhistleDefinition(evmConfiguration)
final Optional<BigInteger> chainId,
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return tangerineWhistleDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.isReplayProtectionSupported(true)
.gasCalculator(SpuriousDragonGasCalculator::new)
.skipZeroBlockRewards(true)
@ -271,8 +304,11 @@ public abstract class MainnetProtocolSpecs {
public static ProtocolSpecBuilder byzantiumDefinition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return spuriousDragonDefinition(chainId, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return spuriousDragonDefinition(
chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem)
.gasCalculator(ByzantiumGasCalculator::new)
.evmBuilder(MainnetEVMs::byzantium)
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::byzantium)
@ -301,8 +337,15 @@ public abstract class MainnetProtocolSpecs {
public static ProtocolSpecBuilder constantinopleDefinition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return byzantiumDefinition(chainId, enableRevertReason, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return byzantiumDefinition(
chainId,
enableRevertReason,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.difficultyCalculator(MainnetDifficultyCalculators.CONSTANTINOPLE)
.gasCalculator(ConstantinopleGasCalculator::new)
.evmBuilder(MainnetEVMs::constantinople)
@ -313,8 +356,15 @@ public abstract class MainnetProtocolSpecs {
public static ProtocolSpecBuilder petersburgDefinition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return constantinopleDefinition(chainId, enableRevertReason, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return constantinopleDefinition(
chainId,
enableRevertReason,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.gasCalculator(PetersburgGasCalculator::new)
.name("Petersburg");
}
@ -322,8 +372,15 @@ public abstract class MainnetProtocolSpecs {
public static ProtocolSpecBuilder istanbulDefinition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return petersburgDefinition(chainId, enableRevertReason, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return petersburgDefinition(
chainId,
enableRevertReason,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.gasCalculator(IstanbulGasCalculator::new)
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
@ -344,8 +401,15 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder muirGlacierDefinition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return istanbulDefinition(chainId, enableRevertReason, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return istanbulDefinition(
chainId,
enableRevertReason,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.difficultyCalculator(MainnetDifficultyCalculators.MUIR_GLACIER)
.name("MuirGlacier");
}
@ -353,8 +417,15 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder berlinDefinition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return muirGlacierDefinition(chainId, enableRevertReason, evmConfiguration)
final EvmConfiguration evmConfiguration,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return muirGlacierDefinition(
chainId,
enableRevertReason,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.gasCalculator(BerlinGasCalculator::new)
.transactionValidatorFactoryBuilder(
(evm, gasLimitCalculator, feeMarket) ->
@ -376,7 +447,9 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
final long londonForkBlockNumber =
genesisConfigOptions.getLondonBlockNumber().orElse(Long.MAX_VALUE);
final BaseFeeMarket londonFeeMarket;
@ -390,7 +463,12 @@ public abstract class MainnetProtocolSpecs {
londonFeeMarket =
FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas());
}
return berlinDefinition(chainId, enableRevertReason, evmConfiguration)
return berlinDefinition(
chainId,
enableRevertReason,
evmConfiguration,
isParallelTxProcessingEnabled,
metricsSystem)
.feeMarket(londonFeeMarket)
.gasCalculator(LondonGasCalculator::new)
.gasLimitCalculatorBuilder(
@ -455,9 +533,17 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return londonDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem)
.difficultyCalculator(MainnetDifficultyCalculators.ARROW_GLACIER)
.name("ArrowGlacier");
}
@ -467,9 +553,17 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return arrowGlacierDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem)
.difficultyCalculator(MainnetDifficultyCalculators.GRAY_GLACIER)
.name("GrayGlacier");
}
@ -479,10 +573,18 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return grayGlacierDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem)
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
MainnetEVMs.paris(gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration))
@ -499,9 +601,17 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return parisDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem)
// gas calculator has new code to support EIP-3860 limit and meter initcode
.gasCalculator(ShanghaiGasCalculator::new)
// EVM has a new operation for EIP-3855 PUSH0 instruction
@ -550,7 +660,9 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L);
final BaseFeeMarket cancunFeeMarket;
if (genesisConfigOptions.isZeroBaseFee()) {
@ -565,7 +677,13 @@ public abstract class MainnetProtocolSpecs {
}
return shanghaiDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem)
.feeMarket(cancunFeeMarket)
// gas calculator for EIP-4844 blob gas
.gasCalculator(CancunGasCalculator::new)
@ -595,7 +713,8 @@ public abstract class MainnetProtocolSpecs {
true,
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.eip1559()))
CoinbaseFeePriceCalculator.eip1559(),
new AuthorityProcessor(chainId)))
// change to check for max blob gas per block for EIP-4844
.transactionValidatorFactoryBuilder(
(evm, gasLimitCalculator, feeMarket) ->
@ -622,11 +741,19 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
ProtocolSpecBuilder protocolSpecBuilder =
cancunDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("CancunEOF");
}
@ -635,14 +762,22 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
final Address depositContractAddress =
genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS);
return cancunDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
// EIP-3074 AUTH and AUTHCALL gas
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem)
// EIP-3074 AUTH and AUTCALL gas
.gasCalculator(PragueGasCalculator::new)
// EIP-3074 AUTH and AUTHCALL
.evmBuilder(
@ -658,6 +793,23 @@ public abstract class MainnetProtocolSpecs {
// EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests
.requestProcessorCoordinator(pragueRequestsProcessors(depositContractAddress))
// change to accept EIP-7702 transactions
.transactionValidatorFactoryBuilder(
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
evm.getGasCalculator(),
gasLimitCalculator,
feeMarket,
true,
chainId,
Set.of(
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB,
TransactionType.SET_CODE),
evm.getEvmVersion().getMaxInitcodeSize()))
// EIP-2935 Blockhash processor
.blockHashProcessor(new PragueBlockHashProcessor())
.name("Prague");
@ -668,11 +820,19 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
ProtocolSpecBuilder protocolSpecBuilder =
pragueDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters);
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("PragueEOF");
}
@ -704,9 +864,17 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return pragueEOFDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem)
// Use Future EIP configured EVM
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
@ -731,10 +899,18 @@ public abstract class MainnetProtocolSpecs {
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final MiningParameters miningParameters,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
return futureEipsDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
chainId,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem)
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
MainnetEVMs.experimentalEips(

@ -42,6 +42,7 @@ import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.processor.AbstractMessageProcessor;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.Deque;
@ -80,6 +81,8 @@ public class MainnetTransactionProcessor {
protected final FeeMarket feeMarket;
private final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator;
private final Optional<AuthorityProcessor> maybeAuthorityProcessor;
public MainnetTransactionProcessor(
final GasCalculator gasCalculator,
final TransactionValidatorFactory transactionValidatorFactory,
@ -90,6 +93,30 @@ public class MainnetTransactionProcessor {
final int maxStackSize,
final FeeMarket feeMarket,
final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator) {
this(
gasCalculator,
transactionValidatorFactory,
contractCreationProcessor,
messageCallProcessor,
clearEmptyAccounts,
warmCoinbase,
maxStackSize,
feeMarket,
coinbaseFeePriceCalculator,
null);
}
public MainnetTransactionProcessor(
final GasCalculator gasCalculator,
final TransactionValidatorFactory transactionValidatorFactory,
final AbstractMessageProcessor contractCreationProcessor,
final AbstractMessageProcessor messageCallProcessor,
final boolean clearEmptyAccounts,
final boolean warmCoinbase,
final int maxStackSize,
final FeeMarket feeMarket,
final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator,
final AuthorityProcessor maybeAuthorityProcessor) {
this.gasCalculator = gasCalculator;
this.transactionValidatorFactory = transactionValidatorFactory;
this.contractCreationProcessor = contractCreationProcessor;
@ -99,6 +126,7 @@ public class MainnetTransactionProcessor {
this.maxStackSize = maxStackSize;
this.feeMarket = feeMarket;
this.coinbaseFeePriceCalculator = coinbaseFeePriceCalculator;
this.maybeAuthorityProcessor = Optional.ofNullable(maybeAuthorityProcessor);
}
/**
@ -259,6 +287,8 @@ public class MainnetTransactionProcessor {
final PrivateMetadataUpdater privateMetadataUpdater,
final Wei blobGasPrice) {
try {
final AuthorizedCodeService authorizedCodeService = new AuthorizedCodeService();
worldState.setAuthorizedCodeService(authorizedCodeService);
final var transactionValidator = transactionValidatorFactory.get();
LOG.trace("Starting execution of {}", transaction);
ValidationResult<TransactionInvalidReason> validationResult =
@ -332,15 +362,19 @@ public class MainnetTransactionProcessor {
transaction.getPayload(), transaction.isContractCreation());
final long accessListGas =
gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount);
final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas;
final long setCodeGas = gasCalculator.setCodeListGasCost(transaction.authorizationListSize());
final long gasAvailable =
transaction.getGasLimit() - intrinsicGas - accessListGas - setCodeGas;
LOG.trace(
"Gas available for execution {} = {} - {} - {} (limit - intrinsic - accessList)",
"Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - setCode)",
gasAvailable,
transaction.getGasLimit(),
intrinsicGas,
accessListGas);
accessListGas,
setCodeGas);
final WorldUpdater worldUpdater = worldState.updater();
worldUpdater.setAuthorizedCodeService(authorizedCodeService);
final ImmutableMap.Builder<String, Object> contextVariablesBuilder =
ImmutableMap.<String, Object>builder()
.put(KEY_IS_PERSISTING_PRIVATE_STATE, isPersistingPrivateState)
@ -374,6 +408,15 @@ public class MainnetTransactionProcessor {
if (transaction.getVersionedHashes().isPresent()) {
commonMessageFrameBuilder.versionedHashes(
Optional.of(transaction.getVersionedHashes().get().stream().toList()));
} else if (transaction.getAuthorizationList().isPresent()) {
if (maybeAuthorityProcessor.isEmpty()) {
throw new RuntimeException("Authority processor is required for 7702 transactions");
}
maybeAuthorityProcessor
.get()
.addContractToAuthority(worldUpdater, authorizedCodeService, transaction);
addressList.addAll(authorizedCodeService.getAuthorities());
} else {
commonMessageFrameBuilder.versionedHashes(Optional.empty());
}
@ -392,6 +435,7 @@ public class MainnetTransactionProcessor {
.contract(contractAddress)
.inputData(initCodeBytes.slice(code.getSize()))
.code(code)
.authorizedCodeService(authorizedCodeService)
.build();
} else {
@SuppressWarnings("OptionalGetWithoutIsPresent") // isContractCall tests isPresent
@ -407,6 +451,7 @@ public class MainnetTransactionProcessor {
maybeContract
.map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode()))
.orElse(CodeV0.EMPTY_CODE))
.authorizedCodeService(authorizedCodeService)
.build();
}
Deque<MessageFrame> messageFrameStack = initialFrame.getMessageFrameStack();
@ -462,7 +507,6 @@ public class MainnetTransactionProcessor {
final long gasUsedByTransaction = transaction.getGasLimit() - initialFrame.getRemainingGas();
// update the coinbase
final var coinbase = worldState.getOrCreate(miningBeneficiary);
final long usedGas = transaction.getGasLimit() - refundedGas;
final CoinbaseFeePriceCalculator coinbaseCalculator;
if (blockHeader.getBaseFee().isPresent()) {
@ -484,7 +528,11 @@ public class MainnetTransactionProcessor {
final Wei coinbaseWeiDelta =
coinbaseCalculator.price(usedGas, transactionGasPrice, blockHeader.getBaseFee());
operationTracer.traceBeforeRewardTransaction(worldUpdater, transaction, coinbaseWeiDelta);
final var coinbase = worldState.getOrCreate(miningBeneficiary);
coinbase.incrementBalance(coinbaseWeiDelta);
authorizedCodeService.resetAuthorities();
operationTracer.traceEndTransaction(
worldUpdater,

@ -189,7 +189,8 @@ public class MainnetTransactionValidator implements TransactionValidator {
final long intrinsicGasCost =
gasCalculator.transactionIntrinsicGasCost(
transaction.getPayload(), transaction.isContractCreation())
+ (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L));
+ (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L))
+ gasCalculator.setCodeListGasCost(transaction.authorizationListSize());
if (Long.compareUnsigned(intrinsicGasCost, transaction.getGasLimit()) > 0) {
return ValidationResult.invalid(
TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT,

@ -20,6 +20,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.math.BigInteger;
import java.util.NavigableMap;
@ -45,6 +46,8 @@ public class ProtocolScheduleBuilder {
private final EvmConfiguration evmConfiguration;
private final MiningParameters miningParameters;
private final BadBlockManager badBlockManager;
private final boolean isParallelTxProcessingEnabled;
private final MetricsSystem metricsSystem;
public ProtocolScheduleBuilder(
final GenesisConfigOptions config,
@ -54,7 +57,9 @@ public class ProtocolScheduleBuilder {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
this(
config,
Optional.of(defaultChainId),
@ -63,7 +68,9 @@ public class ProtocolScheduleBuilder {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
public ProtocolScheduleBuilder(
@ -73,7 +80,9 @@ public class ProtocolScheduleBuilder {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
this(
config,
Optional.empty(),
@ -82,7 +91,9 @@ public class ProtocolScheduleBuilder {
isRevertReasonEnabled,
evmConfiguration,
miningParameters,
badBlockManager);
badBlockManager,
isParallelTxProcessingEnabled,
metricsSystem);
}
private ProtocolScheduleBuilder(
@ -93,7 +104,9 @@ public class ProtocolScheduleBuilder {
final boolean isRevertReasonEnabled,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters,
final BadBlockManager badBlockManager) {
final BadBlockManager badBlockManager,
final boolean isParallelTxProcessingEnabled,
final MetricsSystem metricsSystem) {
this.config = config;
this.protocolSpecAdapters = protocolSpecAdapters;
this.privacyParameters = privacyParameters;
@ -102,6 +115,8 @@ public class ProtocolScheduleBuilder {
this.defaultChainId = defaultChainId;
this.miningParameters = miningParameters;
this.badBlockManager = badBlockManager;
this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled;
this.metricsSystem = metricsSystem;
}
public ProtocolSchedule createProtocolSchedule() {
@ -121,7 +136,9 @@ public class ProtocolScheduleBuilder {
config.getEcip1017EraRounds(),
evmConfiguration.overrides(
config.getContractSizeLimit(), OptionalInt.empty(), config.getEvmStackSize()),
miningParameters);
miningParameters,
isParallelTxProcessingEnabled,
metricsSystem);
validateForkOrdering();
@ -203,7 +220,8 @@ public class ProtocolScheduleBuilder {
protocolSchedule,
BuilderMapEntry.MilestoneType.BLOCK_NUMBER,
classicBlockNumber,
ClassicProtocolSpecs.classicRecoveryInitDefinition(evmConfiguration),
ClassicProtocolSpecs.classicRecoveryInitDefinition(
evmConfiguration, isParallelTxProcessingEnabled, metricsSystem),
Function.identity());
protocolSchedule.putBlockNumberMilestone(
classicBlockNumber + 1, originalProtocolSpec);

@ -51,6 +51,7 @@ public class ProtocolSpecBuilder {
private Function<FeeMarket, GasLimitCalculator> gasLimitCalculatorBuilder;
private Wei blockReward;
private boolean skipZeroBlockRewards;
private BlockHeaderFunctions blockHeaderFunctions;
private AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory;
private DifficultyCalculator difficultyCalculator;
@ -66,9 +67,11 @@ public class ProtocolSpecBuilder {
private BiFunction<EVM, PrecompileContractRegistry, AbstractMessageProcessor>
messageCallProcessorBuilder;
private TransactionProcessorBuilder transactionProcessorBuilder;
private BlockProcessorBuilder blockProcessorBuilder;
private BlockValidatorBuilder blockValidatorBuilder;
private BlockImporterBuilder blockImporterBuilder;
private String name;
private MiningBeneficiaryCalculator miningBeneficiaryCalculator;
private PrivacyParameters privacyParameters;

@ -0,0 +1,199 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet.parallelization;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.mainnet.BlockProcessor;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockProcessor;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter;
import java.util.List;
import java.util.Optional;
public class MainnetParallelBlockProcessor extends MainnetBlockProcessor {
private final Optional<MetricsSystem> metricsSystem;
private final Optional<Counter> confirmedParallelizedTransactionCounter;
private final Optional<Counter> conflictingButCachedTransactionCounter;
public MainnetParallelBlockProcessor(
final MainnetTransactionProcessor transactionProcessor,
final TransactionReceiptFactory transactionReceiptFactory,
final Wei blockReward,
final MiningBeneficiaryCalculator miningBeneficiaryCalculator,
final boolean skipZeroBlockRewards,
final ProtocolSchedule protocolSchedule,
final MetricsSystem metricsSystem) {
super(
transactionProcessor,
transactionReceiptFactory,
blockReward,
miningBeneficiaryCalculator,
skipZeroBlockRewards,
protocolSchedule);
this.metricsSystem = Optional.of(metricsSystem);
this.confirmedParallelizedTransactionCounter =
Optional.of(
this.metricsSystem
.get()
.createCounter(
BesuMetricCategory.BLOCK_PROCESSING,
"parallelized_transactions_counter",
"Counter for the number of parallelized transactions during block processing"));
this.conflictingButCachedTransactionCounter =
Optional.of(
this.metricsSystem
.get()
.createCounter(
BesuMetricCategory.BLOCK_PROCESSING,
"conflicted_transactions_counter",
"Counter for the number of conflicted transactions during block processing"));
}
@Override
protected Optional<PreprocessingContext> runBlockPreProcessing(
final MutableWorldState worldState,
final PrivateMetadataUpdater privateMetadataUpdater,
final BlockHeader blockHeader,
final List<Transaction> transactions,
final Address miningBeneficiary,
final BlockHashOperation.BlockHashLookup blockHashLookup,
final Wei blobGasPrice) {
if ((worldState instanceof DiffBasedWorldState)) {
ParallelizedConcurrentTransactionProcessor parallelizedConcurrentTransactionProcessor =
new ParallelizedConcurrentTransactionProcessor(transactionProcessor);
// runAsyncBlock, if activated, facilitates the non-blocking parallel execution of
// transactions in the background through an optimistic strategy.
parallelizedConcurrentTransactionProcessor.runAsyncBlock(
worldState,
blockHeader,
transactions,
miningBeneficiary,
blockHashLookup,
blobGasPrice,
privateMetadataUpdater);
return Optional.of(
new ParallelizedPreProcessingContext(parallelizedConcurrentTransactionProcessor));
}
return Optional.empty();
}
@Override
protected TransactionProcessingResult getTransactionProcessingResult(
final Optional<PreprocessingContext> preProcessingContext,
final MutableWorldState worldState,
final WorldUpdater blockUpdater,
final PrivateMetadataUpdater privateMetadataUpdater,
final BlockHeader blockHeader,
final Wei blobGasPrice,
final Address miningBeneficiary,
final Transaction transaction,
final int location,
final BlockHashOperation.BlockHashLookup blockHashLookup) {
TransactionProcessingResult transactionProcessingResult = null;
if (preProcessingContext.isPresent()) {
final ParallelizedPreProcessingContext parallelizedPreProcessingContext =
(ParallelizedPreProcessingContext) preProcessingContext.get();
transactionProcessingResult =
parallelizedPreProcessingContext
.getParallelizedConcurrentTransactionProcessor()
.applyParallelizedTransactionResult(
worldState,
miningBeneficiary,
transaction,
location,
confirmedParallelizedTransactionCounter,
conflictingButCachedTransactionCounter)
.orElse(null);
}
if (transactionProcessingResult == null) {
return super.getTransactionProcessingResult(
preProcessingContext,
worldState,
blockUpdater,
privateMetadataUpdater,
blockHeader,
blobGasPrice,
miningBeneficiary,
transaction,
location,
blockHashLookup);
} else {
return transactionProcessingResult;
}
}
static class ParallelizedPreProcessingContext implements PreprocessingContext {
final ParallelizedConcurrentTransactionProcessor parallelizedConcurrentTransactionProcessor;
public ParallelizedPreProcessingContext(
final ParallelizedConcurrentTransactionProcessor
parallelizedConcurrentTransactionProcessor) {
this.parallelizedConcurrentTransactionProcessor = parallelizedConcurrentTransactionProcessor;
}
public ParallelizedConcurrentTransactionProcessor
getParallelizedConcurrentTransactionProcessor() {
return parallelizedConcurrentTransactionProcessor;
}
}
public static class ParallelBlockProcessorBuilder
implements ProtocolSpecBuilder.BlockProcessorBuilder {
final MetricsSystem metricsSystem;
public ParallelBlockProcessorBuilder(final MetricsSystem metricsSystem) {
this.metricsSystem = metricsSystem;
}
@Override
public BlockProcessor apply(
final MainnetTransactionProcessor transactionProcessor,
final TransactionReceiptFactory transactionReceiptFactory,
final Wei blockReward,
final MiningBeneficiaryCalculator miningBeneficiaryCalculator,
final boolean skipZeroBlockRewards,
final ProtocolSchedule protocolSchedule) {
return new MainnetParallelBlockProcessor(
transactionProcessor,
transactionReceiptFactory,
blockReward,
miningBeneficiaryCalculator,
skipZeroBlockRewards,
protocolSchedule,
metricsSystem);
}
}
}

@ -0,0 +1,268 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet.parallelization;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.NoopBonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldView;
import org.hyperledger.besu.plugin.services.metrics.Counter;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import com.google.common.annotations.VisibleForTesting;
/**
* Optimizes transaction processing by executing transactions in parallel within a given block.
* Transactions are executed optimistically in a non-blocking manner. After execution, the class
* checks for potential conflicts among transactions to ensure data integrity before applying the
* results to the world state.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class ParallelizedConcurrentTransactionProcessor {
private static final int NCPU = Runtime.getRuntime().availableProcessors();
private static final Executor executor = Executors.newFixedThreadPool(NCPU);
private final MainnetTransactionProcessor transactionProcessor;
private final TransactionCollisionDetector transactionCollisionDetector;
private final Map<Integer, ParallelizedTransactionContext>
parallelizedTransactionContextByLocation = new ConcurrentHashMap<>();
/**
* Constructs a PreloadConcurrentTransactionProcessor with a specified transaction processor. This
* processor is responsible for the individual processing of transactions.
*
* @param transactionProcessor The transaction processor for processing individual transactions.
*/
public ParallelizedConcurrentTransactionProcessor(
final MainnetTransactionProcessor transactionProcessor) {
this.transactionProcessor = transactionProcessor;
this.transactionCollisionDetector = new TransactionCollisionDetector();
}
@VisibleForTesting
public ParallelizedConcurrentTransactionProcessor(
final MainnetTransactionProcessor transactionProcessor,
final TransactionCollisionDetector transactionCollisionDetector) {
this.transactionProcessor = transactionProcessor;
this.transactionCollisionDetector = transactionCollisionDetector;
}
/**
* Initiates the parallel and optimistic execution of transactions within a block by creating a
* copy of the world state for each transaction. This method processes transactions in a
* non-blocking manner. Transactions are executed against their respective copies of the world
* state, ensuring that the original world state passed as a parameter remains unmodified during
* this process.
*
* @param worldState Mutable world state intended for applying transaction results. This world
* state is not modified directly; instead, copies are made for transaction execution.
* @param blockHeader Header of the current block containing the transactions.
* @param transactions List of transactions to be processed.
* @param miningBeneficiary Address of the beneficiary to receive mining rewards.
* @param blockHashLookup Function for block hash lookup.
* @param blobGasPrice Gas price for blob transactions.
* @param privateMetadataUpdater Updater for private transaction metadata.
*/
public void runAsyncBlock(
final MutableWorldState worldState,
final BlockHeader blockHeader,
final List<Transaction> transactions,
final Address miningBeneficiary,
final BlockHashOperation.BlockHashLookup blockHashLookup,
final Wei blobGasPrice,
final PrivateMetadataUpdater privateMetadataUpdater) {
for (int i = 0; i < transactions.size(); i++) {
final Transaction transaction = transactions.get(i);
final int transactionLocation = i;
/*
* All transactions are executed in the background by copying the world state of the block on which the transactions need to be executed, ensuring that each one has its own accumulator.
*/
CompletableFuture.runAsync(
() ->
runTransaction(
worldState,
blockHeader,
transactionLocation,
transaction,
miningBeneficiary,
blockHashLookup,
blobGasPrice,
privateMetadataUpdater),
executor);
}
}
@VisibleForTesting
public void runTransaction(
final MutableWorldState worldState,
final BlockHeader blockHeader,
final int transactionLocation,
final Transaction transaction,
final Address miningBeneficiary,
final BlockHashOperation.BlockHashLookup blockHashLookup,
final Wei blobGasPrice,
final PrivateMetadataUpdater privateMetadataUpdater) {
try (final DiffBasedWorldState roundWorldState =
new BonsaiWorldState(
(BonsaiWorldState) worldState, new NoopBonsaiCachedMerkleTrieLoader())) {
roundWorldState.freeze(); // make the clone frozen
final ParallelizedTransactionContext.Builder contextBuilder =
new ParallelizedTransactionContext.Builder();
final DiffBasedWorldStateUpdateAccumulator<?> roundWorldStateUpdater =
(DiffBasedWorldStateUpdateAccumulator<?>) roundWorldState.updater();
final TransactionProcessingResult result =
transactionProcessor.processTransaction(
roundWorldStateUpdater,
blockHeader,
transaction,
miningBeneficiary,
new OperationTracer() {
@Override
public void traceBeforeRewardTransaction(
final WorldView worldView,
final org.hyperledger.besu.datatypes.Transaction tx,
final Wei miningReward) {
/*
* This part checks if the mining beneficiary's account was accessed before increasing its balance for rewards.
* Indeed, if the transaction has interacted with the address to read or modify it,
* it means that the value is necessary for the proper execution of the transaction and will therefore be considered in collision detection.
* If this is not the case, we can ignore this address during conflict detection.
*/
if (transactionCollisionDetector
.getAddressesTouchedByTransaction(
transaction, Optional.of(roundWorldStateUpdater))
.contains(miningBeneficiary)) {
contextBuilder.isMiningBeneficiaryTouchedPreRewardByTransaction(true);
}
contextBuilder.miningBeneficiaryReward(miningReward);
}
},
blockHashLookup,
true,
TransactionValidationParams.processingBlock(),
privateMetadataUpdater,
blobGasPrice);
// commit the accumulator in order to apply all the modifications
roundWorldState.getAccumulator().commit();
contextBuilder
.transactionAccumulator(roundWorldState.getAccumulator())
.transactionProcessingResult(result);
final ParallelizedTransactionContext parallelizedTransactionContext = contextBuilder.build();
if (!parallelizedTransactionContext.isMiningBeneficiaryTouchedPreRewardByTransaction()) {
/*
* If the address of the mining beneficiary has been touched only for adding rewards,
* we remove it from the accumulator to avoid a false positive collision.
* The balance will be increased during the sequential processing.
*/
roundWorldStateUpdater.getAccountsToUpdate().remove(miningBeneficiary);
}
parallelizedTransactionContextByLocation.put(
transactionLocation, parallelizedTransactionContext);
}
}
/**
* Applies the results of parallelized transactions to the world state after checking for
* conflicts.
*
* <p>If a transaction was executed optimistically without any detected conflicts, its result is
* directly applied to the world state. If there is a conflict, this method does not apply the
* transaction's modifications directly to the world state. Instead, it caches the data read from
* the database during the transaction's execution. This cached data is then used to optimize the
* replay of the transaction by reducing the need for additional reads from the disk, thereby
* making the replay process faster. This approach ensures that the integrity of the world state
* is maintained while optimizing the performance of transaction processing.
*
* @param worldState Mutable world state intended for applying transaction results.
* @param miningBeneficiary Address of the beneficiary for mining rewards.
* @param transaction Transaction for which the result is to be applied.
* @param transactionLocation Index of the transaction within the block.
* @param confirmedParallelizedTransactionCounter Metric counter for confirmed parallelized
* transactions
* @param conflictingButCachedTransactionCounter Metric counter for conflicting but cached
* transactions
* @return Optional containing the transaction processing result if applied, or empty if the
* transaction needs to be replayed due to a conflict.
*/
public Optional<TransactionProcessingResult> applyParallelizedTransactionResult(
final MutableWorldState worldState,
final Address miningBeneficiary,
final Transaction transaction,
final int transactionLocation,
final Optional<Counter> confirmedParallelizedTransactionCounter,
final Optional<Counter> conflictingButCachedTransactionCounter) {
final DiffBasedWorldState diffBasedWorldState = (DiffBasedWorldState) worldState;
final DiffBasedWorldStateUpdateAccumulator blockAccumulator =
(DiffBasedWorldStateUpdateAccumulator) diffBasedWorldState.updater();
final ParallelizedTransactionContext parallelizedTransactionContext =
parallelizedTransactionContextByLocation.remove(transactionLocation);
/*
* If `parallelizedTransactionContext` is not null, it means that the transaction had time to complete in the background.
*/
if (parallelizedTransactionContext != null) {
final DiffBasedWorldStateUpdateAccumulator<?> transactionAccumulator =
parallelizedTransactionContext.transactionAccumulator();
final TransactionProcessingResult transactionProcessingResult =
parallelizedTransactionContext.transactionProcessingResult();
final boolean hasCollision =
transactionCollisionDetector.hasCollision(
transaction, miningBeneficiary, parallelizedTransactionContext, blockAccumulator);
if (transactionProcessingResult.isSuccessful() && !hasCollision) {
blockAccumulator
.getOrCreate(miningBeneficiary)
.incrementBalance(parallelizedTransactionContext.miningBeneficiaryReward());
blockAccumulator.importStateChangesFromSource(transactionAccumulator);
if (confirmedParallelizedTransactionCounter.isPresent())
confirmedParallelizedTransactionCounter.get().inc();
return Optional.of(transactionProcessingResult);
} else {
blockAccumulator.importPriorStateFromSource(transactionAccumulator);
if (conflictingButCachedTransactionCounter.isPresent())
conflictingButCachedTransactionCounter.get().inc();
// If there is a conflict, we return an empty result to signal the block processor to
// re-execute the transaction.
return Optional.empty();
}
}
return Optional.empty();
}
}

@ -0,0 +1,133 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet.parallelization;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import java.util.Objects;
public final class ParallelizedTransactionContext {
private final DiffBasedWorldStateUpdateAccumulator<?> transactionAccumulator;
private final TransactionProcessingResult transactionProcessingResult;
private final boolean isMiningBeneficiaryTouchedPreRewardByTransaction;
private final Wei miningBeneficiaryReward;
public ParallelizedTransactionContext(
final DiffBasedWorldStateUpdateAccumulator<?> transactionAccumulator,
final TransactionProcessingResult transactionProcessingResult,
final boolean isMiningBeneficiaryTouchedPreRewardByTransaction,
final Wei miningBeneficiaryReward) {
this.transactionAccumulator = transactionAccumulator;
this.transactionProcessingResult = transactionProcessingResult;
this.isMiningBeneficiaryTouchedPreRewardByTransaction =
isMiningBeneficiaryTouchedPreRewardByTransaction;
this.miningBeneficiaryReward = miningBeneficiaryReward;
}
public DiffBasedWorldStateUpdateAccumulator<?> transactionAccumulator() {
return transactionAccumulator;
}
public TransactionProcessingResult transactionProcessingResult() {
return transactionProcessingResult;
}
public boolean isMiningBeneficiaryTouchedPreRewardByTransaction() {
return isMiningBeneficiaryTouchedPreRewardByTransaction;
}
public Wei miningBeneficiaryReward() {
return miningBeneficiaryReward;
}
@Override
public boolean equals(final Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (ParallelizedTransactionContext) obj;
return Objects.equals(this.transactionAccumulator, that.transactionAccumulator)
&& Objects.equals(this.transactionProcessingResult, that.transactionProcessingResult)
&& this.isMiningBeneficiaryTouchedPreRewardByTransaction
== that.isMiningBeneficiaryTouchedPreRewardByTransaction
&& Objects.equals(this.miningBeneficiaryReward, that.miningBeneficiaryReward);
}
@Override
public int hashCode() {
return Objects.hash(
transactionAccumulator,
transactionProcessingResult,
isMiningBeneficiaryTouchedPreRewardByTransaction,
miningBeneficiaryReward);
}
@Override
public String toString() {
return "ParallelizedTransactionContext["
+ "transactionAccumulator="
+ transactionAccumulator
+ ", "
+ "transactionProcessingResult="
+ transactionProcessingResult
+ ", "
+ "isMiningBeneficiaryTouchedPreRewardByTransaction="
+ isMiningBeneficiaryTouchedPreRewardByTransaction
+ ", "
+ "miningBeneficiaryReward="
+ miningBeneficiaryReward
+ ']';
}
public static class Builder {
private DiffBasedWorldStateUpdateAccumulator<?> transactionAccumulator;
private TransactionProcessingResult transactionProcessingResult;
private boolean isMiningBeneficiaryTouchedPreRewardByTransaction;
private Wei miningBeneficiaryReward = Wei.ZERO;
public Builder transactionAccumulator(
final DiffBasedWorldStateUpdateAccumulator<?> transactionAccumulator) {
this.transactionAccumulator = transactionAccumulator;
return this;
}
public Builder transactionProcessingResult(
final TransactionProcessingResult transactionProcessingResult) {
this.transactionProcessingResult = transactionProcessingResult;
return this;
}
public Builder isMiningBeneficiaryTouchedPreRewardByTransaction(
final boolean isMiningBeneficiaryTouchedPreRewardByTransaction) {
this.isMiningBeneficiaryTouchedPreRewardByTransaction =
isMiningBeneficiaryTouchedPreRewardByTransaction;
return this;
}
public Builder miningBeneficiaryReward(final Wei miningBeneficiaryReward) {
this.miningBeneficiaryReward = miningBeneficiaryReward;
return this;
}
public ParallelizedTransactionContext build() {
return new ParallelizedTransactionContext(
transactionAccumulator,
transactionProcessingResult,
isMiningBeneficiaryTouchedPreRewardByTransaction,
miningBeneficiaryReward);
}
}
}

@ -0,0 +1,114 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet.parallelization;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
public class TransactionCollisionDetector {
/**
* Determines if a transaction has a collision based on the addresses it touches. A collision
* occurs if the transaction touches the mining beneficiary address or if there are common
* addresses touched by both the transaction and other transactions within the same block.
*
* @param transaction The transaction to check for collisions.
* @param miningBeneficiary The address of the mining beneficiary.
* @param parallelizedTransactionContext The context containing the accumulator for the
* transaction.
* @param blockAccumulator The accumulator for the block.
* @return true if there is a collision; false otherwise.
*/
public boolean hasCollision(
final Transaction transaction,
final Address miningBeneficiary,
final ParallelizedTransactionContext parallelizedTransactionContext,
final DiffBasedWorldStateUpdateAccumulator<?> blockAccumulator) {
final Set<Address> addressesTouchedByTransaction =
getAddressesTouchedByTransaction(
transaction, Optional.of(parallelizedTransactionContext.transactionAccumulator()));
if (addressesTouchedByTransaction.contains(miningBeneficiary)) {
return true;
}
final Set<Address> addressesTouchedByBlock =
getAddressesTouchedByBlock(Optional.of(blockAccumulator));
final Iterator<Address> it = addressesTouchedByTransaction.iterator();
boolean commonAddressFound = false;
while (it.hasNext() && !commonAddressFound) {
if (addressesTouchedByBlock.contains(it.next())) {
commonAddressFound = true;
}
}
return commonAddressFound;
}
/**
* Retrieves the set of addresses that were touched by a transaction. This includes the sender and
* recipient of the transaction, as well as any addresses that were read from or written to by the
* transaction's execution.
*
* @param transaction The transaction to analyze.
* @param accumulator An optional accumulator containing state changes made by the transaction.
* @return A set of addresses touched by the transaction.
*/
public Set<Address> getAddressesTouchedByTransaction(
final Transaction transaction,
final Optional<DiffBasedWorldStateUpdateAccumulator<?>> accumulator) {
HashSet<Address> addresses = new HashSet<>();
addresses.add(transaction.getSender());
if (transaction.getTo().isPresent()) {
addresses.add(transaction.getTo().get());
}
accumulator.ifPresent(
diffBasedWorldStateUpdateAccumulator -> {
diffBasedWorldStateUpdateAccumulator
.getAccountsToUpdate()
.forEach((address, diffBasedValue) -> addresses.add(address));
addresses.addAll(diffBasedWorldStateUpdateAccumulator.getDeletedAccountAddresses());
});
return addresses;
}
/**
* Retrieves the set of addresses that were touched by all transactions within a block. This
* method filters out addresses that were only read and not modified.
*
* @param accumulator An optional accumulator containing state changes made by the block.
* @return A set of addresses that were modified by the block's transactions.
*/
private Set<Address> getAddressesTouchedByBlock(
final Optional<DiffBasedWorldStateUpdateAccumulator<?>> accumulator) {
HashSet<Address> addresses = new HashSet<>();
accumulator.ifPresent(
diffBasedWorldStateUpdateAccumulator -> {
diffBasedWorldStateUpdateAccumulator
.getAccountsToUpdate()
.forEach(
(address, diffBasedValue) -> {
if (!diffBasedValue.isUnchanged()) {
addresses.add(address);
}
});
addresses.addAll(diffBasedWorldStateUpdateAccumulator.getDeletedAccountAddresses());
});
return addresses;
}
}

@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.Collection;
@ -30,35 +31,39 @@ public class PrivateMutableWorldStateUpdater implements WorldUpdater {
protected final WorldUpdater publicWorldUpdater;
protected final WorldUpdater privateWorldUpdater;
private AuthorizedCodeService authorizedCodeService;
public PrivateMutableWorldStateUpdater(
final WorldUpdater publicWorldUpdater, final WorldUpdater privateWorldUpdater) {
this.publicWorldUpdater = publicWorldUpdater;
this.privateWorldUpdater = privateWorldUpdater;
this.authorizedCodeService = new AuthorizedCodeService();
}
@Override
public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) {
return privateWorldUpdater.createAccount(address, nonce, balance);
return authorizedCodeService.processMutableAccount(
this, privateWorldUpdater.createAccount(address, nonce, balance), address);
}
@Override
public MutableAccount createAccount(final Address address) {
return privateWorldUpdater.createAccount(address);
return authorizedCodeService.processMutableAccount(
this, privateWorldUpdater.createAccount(address), address);
}
@Override
public MutableAccount getAccount(final Address address) {
final MutableAccount privateAccount = privateWorldUpdater.getAccount(address);
if (privateAccount != null && !privateAccount.isEmpty()) {
return privateAccount;
return authorizedCodeService.processMutableAccount(this, privateAccount, address);
}
final MutableAccount publicAccount = publicWorldUpdater.getAccount(address);
if (publicAccount != null && !publicAccount.isEmpty()) {
publicAccount.becomeImmutable();
return publicAccount;
return authorizedCodeService.processMutableAccount(this, publicAccount, address);
}
return privateAccount;
return authorizedCodeService.processMutableAccount(this, privateAccount, address);
}
@Override
@ -104,4 +109,9 @@ public class PrivateMutableWorldStateUpdater implements WorldUpdater {
public Optional<WorldUpdater> parentUpdater() {
return privateWorldUpdater.parentUpdater();
}
@Override
public void setAuthorizedCodeService(final AuthorizedCodeService authorizedCodeService) {
this.authorizedCodeService = authorizedCodeService;
}
}

@ -0,0 +1,44 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
public class NoopBonsaiCachedMerkleTrieLoader extends BonsaiCachedMerkleTrieLoader {
public NoopBonsaiCachedMerkleTrieLoader() {
super(new NoOpMetricsSystem());
}
@Override
public void preLoadAccount(
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage,
final Hash worldStateRootHash,
final Address account) {
// noop
}
@Override
public void preLoadStorageSlot(
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage,
final Address account,
final StorageSlotKey slotKey) {
// noop
}
}

@ -76,6 +76,18 @@ public class BonsaiWorldState extends DiffBasedWorldState {
diffBasedWorldStateConfig);
}
public BonsaiWorldState(
final BonsaiWorldState worldState,
final BonsaiCachedMerkleTrieLoader cachedMerkleTrieLoader) {
this(
new BonsaiWorldStateLayerStorage(worldState.getWorldStateStorage()),
cachedMerkleTrieLoader,
worldState.cachedWorldStorageManager,
worldState.trieLogManager,
worldState.accumulator.getEvmConfiguration(),
new DiffBasedWorldStateConfig(worldState.worldStateConfig));
}
public BonsaiWorldState(
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage,
final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader,

@ -230,12 +230,12 @@ public abstract class DiffBasedWorldStateProvider implements WorldStateArchive {
} catch (final Exception e) {
// if we fail we must clean up the updater
diffBasedUpdater.reset();
LOG.debug(
"State rolling failed on "
+ mutableState.getWorldStateStorage().getClass().getSimpleName()
+ " for block hash "
+ blockHash,
e);
LOG.atDebug()
.setMessage("State rolling failed on {} for block hash {}")
.addArgument(mutableState.getWorldStateStorage().getClass().getSimpleName())
.addArgument(blockHash)
.addArgument(e)
.log();
return Optional.empty();
}

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

Loading…
Cancel
Save