merge main into verkle (#7824)

Signed-off-by: Karim Taam <karim.t2am@gmail.com>
pull/7843/head
Karim Taam 4 weeks ago committed by GitHub
parent d000c7a880
commit dbf6333084
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 31
      .github/ISSUE_TEMPLATE/release-checklist.md
  2. 4
      .github/workflows/BesuContainerVerify.sh
  3. 64
      .github/workflows/docker-promote.yml
  4. 160
      .github/workflows/draft-release.yml
  5. 2
      .github/workflows/sonarcloud.yml
  6. 2
      .github/workflows/splitList.sh
  7. 2
      .github/workflows/splitTestsByTime.sh
  8. 26
      CHANGELOG.md
  9. 3
      MAINTAINERS.md
  10. 21
      README.md
  11. 2
      acceptance-tests/dsl/build.gradle
  12. 20
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/AcceptanceTestBase.java
  13. 200
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/AcceptanceTestBaseJunit5.java
  14. 2
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/blockchain/ExpectBlockNotCreated.java
  15. 4
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java
  16. 2
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java
  17. 12
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java
  18. 2
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/account/TransferTransactionBuilder.java
  19. 2
      acceptance-tests/test-plugins/build.gradle
  20. 19
      acceptance-tests/tests/build.gradle
  21. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/ParameterizedBftTestBase.java
  22. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/qbft/QbftContractAcceptanceTest.java
  23. 2
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java
  24. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/clique/CliqueDiscardRpcAcceptanceTest.java
  25. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/clique/CliqueGetSignersRpcAcceptanceTest.java
  26. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/clique/CliqueMiningAcceptanceTest.java
  27. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/clique/CliqueProposalRpcAcceptanceTest.java
  28. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/clique/CliqueProposeRpcAcceptanceTest.java
  29. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/clique/CliqueZeroValidatorsAcceptanceTest.java
  30. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/crypto/SECP256R1AcceptanceTest.java
  31. 21
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/PragueAcceptanceTestHelper.java
  32. 3
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEnginePragueAcceptanceTest.java
  33. 10
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/mining/MiningAcceptanceTest.java
  34. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/BadCLIOptionsPluginTest.java
  35. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/BesuEventsPluginTest.java
  36. 4
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PermissioningPluginTest.java
  37. 12
      acceptance-tests/tests/src/test/resources/dev/dev_prague.json
  38. 23
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/genesis.json
  39. 4
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/00_get_genesis_block_info.json
  40. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/01_cancun_prepare_payload.json
  41. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/02_cancun_getPayloadV3.json
  42. 14
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/03_cancun_newPayloadV3.json
  43. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/04_cancun_forkchoiceUpdatedV3.json
  44. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/05_prague_forkchoiceUpdatedV3.json
  45. 26
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/06_prague_getPayloadV4.json
  46. 0
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/07_prague_send_raw_transaction_deposit_request.json
  47. 16
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/08_prague_invalid_null_deposit_request_execute_payload.json
  48. 34
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/09_prague_newPayloadV4.json
  49. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/10_prague_forkchoiceUpdatedV3.json
  50. 20
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/11_prague_getPayloadV4.json
  51. 21
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV3.json
  52. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_forkchoiceUpdatedV3.json
  53. 40
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/16_prague_getPayloadV4.json
  54. 10
      besu/build.gradle
  55. 549
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  56. 22
      besu/src/main/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilder.java
  57. 1
      besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java
  58. 6
      besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java
  59. 1
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/ApiConfigurationOptions.java
  60. 249
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java
  61. 36
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCConfiguration.java
  62. 81
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCOptions.java
  63. 1
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/GraphQlOptions.java
  64. 37
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java
  65. 113
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java
  66. 225
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java
  67. 1
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/PermissionsOptions.java
  68. 121
      besu/src/main/java/org/hyperledger/besu/cli/options/storage/DataStorageOptions.java
  69. 217
      besu/src/main/java/org/hyperledger/besu/cli/options/storage/DiffBasedSubStorageOptions.java
  70. 79
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java
  71. 2
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/P2PTLSConfigOptions.java
  72. 2
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/PasswordSubCommand.java
  73. 2
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java
  74. 2
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/BackupState.java
  75. 3
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/GenerateBlockchainConfig.java
  76. 2
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/RestoreState.java
  77. 75
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelper.java
  78. 7
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java
  79. 16
      besu/src/main/java/org/hyperledger/besu/components/BesuCommandModule.java
  80. 42
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  81. 15
      besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java
  82. 15
      besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
  83. 2
      besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java
  84. 8
      besu/src/main/java/org/hyperledger/besu/services/TransactionPoolServiceImpl.java
  85. 81
      besu/src/main/java/org/hyperledger/besu/util/EphemeryGenesisUpdater.java
  86. 2
      besu/src/main/scripts/besu-entry.sh
  87. 17
      besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java
  88. 10
      besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java
  89. 6
      besu/src/test/java/org/hyperledger/besu/RunnerTest.java
  90. 4
      besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java
  91. 100
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  92. 9
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  93. 12
      besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java
  94. 4
      besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java
  95. 10
      besu/src/test/java/org/hyperledger/besu/cli/PrivacyOptionsTest.java
  96. 1
      besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java
  97. 14
      besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java
  98. 63
      besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java
  99. 79
      besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelperTest.java
  100. 13
      besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommandTest.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -12,25 +12,34 @@ assignees: ''
- [ ] 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: for hotfixes, 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`
- [ ] git tag 24.4.0-RC2
- [ ] git push upstream 24.4.0-RC2
- [ ] On the appropriate branch/commit, create a calver tag for the release candidate, format example: `24.4.0-RC1`
- [ ] git tag 24.4.0-RC1
- [ ] git push upstream 24.4.0-RC1
- [ ] Sign-off with team; announce the tag in #besu-release in Discord
- [ ] Targeting this tag for the burn-in: https://github.com/hyperledger/besu/releases/tag/24.4.0-RC2
- [ ] Targeting this tag for the burn-in: https://github.com/hyperledger/besu/releases/tag/24.4.0-RC1
- [ ] Consensys staff start burn-in using this tag
- [ ] Seek sign off for burn-in
- [ ] Pass? Go ahead and complete the release process
- [ ] Fail? Put a message in #besu-release in Discord indicating the release will be aborted because it failed burn-in
- [ ] 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:
- [ ] Optional: Perform a dry run with https://github.com/consensys/protocols-release-sandbox to test the workflows
- [ ] Sync fork
- [ ] git checkout <sha of 24.4.0-RC1>
- [ ] git tag 24.4.0
- [ ] git push origin 24.4.0
- [ ] Manually run https://github.com/Consensys/protocols-release-sandbox/actions/workflows/draft-release.yml using `main` branch and `24.4.0` tag
- [ ] Back on besu, using the same git sha as 24.4.0-RC1, create a calver tag for the FULL RELEASE, example format `24.4.0`
- [ ] git checkout 24.4.0-RC1
- [ ] git tag 24.4.0
- [ ] git push upstream 24.4.0
- [ ] Manually run https://github.com/hyperledger/besu/actions/workflows/draft-release.yml using `main` branch` and the FULL RELEASE tag name, i.e. `24.4.0`. Note, this workflow should always be run from `main` branch (hotfix tags will still be released even if they were created based on another branch)
- publishes artefacts and version-specific docker tags but does not fully publish the GitHub release so subscribers are not yet notified
- [ ] Check all draft-release workflow jobs went green
- [ ] Check binary SHAs are correct on the release page
- [ ] Update release notes in the GitHub draft release, save draft and sign-off with team
- [ ] Publish draft release ensuring it is marked as latest release (if appropriate)
- 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
- [ ] Check binary SHAs are correct on the release page
- [ ] Check "Container Verify" GitHub workflow has run successfully
- [ ] Update the besu-docs version [update-version workflow](https://github.com/hyperledger/besu-docs/actions/workflows/update-version.yml)
- If the PR has not been automatically created, create the PR manually using the created branch `besu-version-<version>`
- [ ] Create homebrew release using [update-version workflow](https://github.com/hyperledger/homebrew-besu/actions/workflows/update-version.yml)
- If the PR has not been automatically created, create the PR manually using the created branch `update-<version>`
- Run commands `brew tap hyperledger/besu && brew install besu` on MacOSX and verify latest version has been installed

@ -1,6 +1,6 @@
#!/bin/bash
##
## Copyright contributors to Hyperledger Besu.
## Copyright contributors to 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
@ -57,7 +57,7 @@ else
fi
# For the latest tag check the version match
if [[ ${TAG} == "latest" && ${CHECK_LATEST} == "true" ]]
if [[ ${TAG} =~ ^latest && ${CHECK_LATEST} == "true" ]]
then
_VERSION_IN_LOG=$(docker logs ${CONTAINER_NAME} | grep "#" | grep "Besu version" | cut -d " " -f 4 | sed 's/\s//g')
echo "Extracted version from logs [$_VERSION_IN_LOG]"

@ -14,25 +14,25 @@ jobs:
validate:
runs-on: ubuntu-22.04
env:
RELEASE_NAME: "${{ github.event.release.name }}"
RELEASE_VERSION: "${{ github.event.release.name }}"
steps:
- name: Pre-process Release Name
id: pre_process_release_name
id: pre_process_release_version
run: |
# strip all whitespace
RELEASE_NAME="${RELEASE_NAME//[[:space:]]/}"
if [[ ! "$RELEASE_NAME" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-.*)?$ ]]; then
RELEASE_VERSION="${RELEASE_VERSION//[[:space:]]/}"
if [[ ! "$RELEASE_VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-.*)?$ ]]; then
echo "Release name does not conform to a valid besu release format YY.M.v[-suffix], e.g. 24.8.0-RC1."
exit 1
fi
echo "release_name=$RELEASE_NAME" >> $GITHUB_OUTPUT # Set as output using the new syntax
echo "release_version=$RELEASE_VERSION" >> $GITHUB_OUTPUT # Set as output using the new syntax
outputs:
release_name: ${{ steps.pre_process_release_name.outputs.release_name }}
release_version: ${{ steps.pre_process_release_version.outputs.release_version }}
docker-promote:
needs: [validate]
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
runs-on: ubuntu-22.04
steps:
- name: Checkout
@ -58,24 +58,52 @@ jobs:
cache-disabled: true
- name: Docker upload
run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_NAME }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" dockerUploadRelease
run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_VERSION }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" dockerUploadRelease
- name: Docker manifest
run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_NAME }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" manifestDockerRelease
run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_VERSION }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" manifestDockerRelease
docker-verify:
needs: [validate, docker-promote]
needs: [validate,docker-promote]
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job
runs-on: ubuntu-22.04
permissions:
contents: read
actions: write
CONTAINER_NAME: besu-check
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
runs-on: ${{ matrix.combination.runner }}
timeout-minutes: 4
strategy:
matrix:
combination:
- tag: latest-amd64
platform: 'linux/amd64'
runner: ubuntu-22.04
- tag: latest
platform: ''
runner: ubuntu-22.04
- tag: latest-arm64
platform: ''
runner: besu-arm64
- tag: latest
platform: ''
runner: besu-arm64
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
sparse-checkout: '.github/workflows/BesuContainerVerify.sh'
- name: Trigger container verify
run: echo '{"version":"${{ env.RELEASE_NAME }}","verify-latest-version":"true"}' | gh workflow run container-verify.yml --json
- name: Start container
run: |
PLATFORM_OPT=""
[[ x${{ matrix.combination.platform }} != 'x' ]] && PLATFORM_OPT="--platform ${{ matrix.combination.platform }}"
docker run -d $PLATFORM_OPT --name ${{ env.CONTAINER_NAME }} ${{ secrets.DOCKER_ORG }}/besu:${{ matrix.combination.tag }}
- name: Verify besu container
run: bash .github/workflows/BesuContainerVerify.sh
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ matrix.combination.tag }}
VERSION: ${{ env.RELEASE_VERSION }}
CHECK_LATEST: true
- name: Stop container
run: docker stop ${{ env.CONTAINER_NAME }}

@ -16,7 +16,7 @@ jobs:
validate:
runs-on: ubuntu-22.04
env:
RELEASE_NAME: "${{ inputs.tag }}"
RELEASE_VERSION: "${{ inputs.tag }}"
steps:
- name: Check default branch
run: |
@ -24,36 +24,36 @@ jobs:
echo "Default Branch: ${{ github.event.repository.default_branch }}"
if [[ ${{ github.ref_name }} != ${{ github.event.repository.default_branch }} ]]
then
echo "This workflow can only be run on default branch"
echo "This workflow can only be run on default branch. This is not an issue for hot fixes as code is checked out from the tag"
exit 1
fi
- name: Pre-process Release Name
id: pre_process_release_name
id: validate_release_version
run: |
# strip all whitespace
RELEASE_NAME="${RELEASE_NAME//[[:space:]]/}"
if [[ ! "$RELEASE_NAME" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-.*)?$ ]]; then
RELEASE_VERSION="${RELEASE_VERSION//[[:space:]]/}"
if [[ ! "$RELEASE_VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-.*)?$ ]]; then
echo "Release name does not conform to a valid besu release format YY.M.v[-suffix], e.g. 24.8.0-RC1."
exit 1
fi
echo "release_name=$RELEASE_NAME" >> $GITHUB_OUTPUT # Set as output using the new syntax
echo "release_version=$RELEASE_VERSION" >> $GITHUB_OUTPUT # Set as output using the new syntax
# Perform a tag checkout to ensure tag is available
- name: Verify tag Exist
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ steps.pre_process_release_name.outputs.release_name }}
with:
ref: ${{ steps.validate_release_version.outputs.release_version }}
fetch-depth: 1
outputs:
release_name: ${{ steps.pre_process_release_name.outputs.release_name }}
release_version: ${{ steps.validate_release_version.outputs.release_version }}
build:
runs-on: ubuntu-22.04
needs: validate
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} # Use the output from the pre_process_release job
outputs:
tarSha: ${{steps.hashes.outputs.tarSha}}
zipSha: ${{steps.hashes.outputs.zipSha}}
@ -61,22 +61,22 @@ jobs:
- name: Checkout tag
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ env.RELEASE_NAME }}
ref: ${{ env.RELEASE_VERSION }}
- name: Set up Java
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
with:
distribution: temurin
java-version: 21
- name: Setup gradle
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
with:
cache-disabled: true
- name: Assemble release
run:
./gradlew -Prelease.releaseVersion=${{env.RELEASE_NAME}} -Pversion=${{env.RELEASE_NAME}} assemble
./gradlew -Prelease.releaseVersion=${{env.RELEASE_VERSION}} -Pversion=${{env.RELEASE_VERSION}} assemble
- name: Hashes
id: hashes
@ -86,35 +86,35 @@ jobs:
echo "tarSha=$(shasum -a 256 besu*.tar.gz)"
echo "zipSha=$(shasum -a 256 besu*.zip)" >> $GITHUB_OUTPUT
echo "tarSha=$(shasum -a 256 besu*.tar.gz)" >> $GITHUB_OUTPUT
shasum -a 256 besu-${{env.RELEASE_NAME}}.tar.gz > besu-${{env.RELEASE_NAME}}.tar.gz.sha256
shasum -a 256 besu-${{env.RELEASE_NAME}}.zip > besu-${{env.RELEASE_NAME}}.zip.sha256
shasum -a 256 besu-${{env.RELEASE_VERSION}}.tar.gz > besu-${{env.RELEASE_VERSION}}.tar.gz.sha256
shasum -a 256 besu-${{env.RELEASE_VERSION}}.zip > besu-${{env.RELEASE_VERSION}}.zip.sha256
- name: Upload tarball
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with:
path: 'build/distributions/besu-${{ env.RELEASE_NAME }}.tar.gz'
name: besu-${{ env.RELEASE_NAME }}.tar.gz
path: 'build/distributions/besu-${{ env.RELEASE_VERSION }}.tar.gz'
name: besu-${{ env.RELEASE_VERSION }}.tar.gz
compression-level: 0
- name: upload zipfile
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with:
path: 'build/distributions/besu-${{ env.RELEASE_NAME }}.zip'
name: besu-${{ env.RELEASE_NAME }}.zip
path: 'build/distributions/besu-${{ env.RELEASE_VERSION }}.zip'
name: besu-${{ env.RELEASE_VERSION }}.zip
compression-level: 0
- name: upload checksum zip
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with:
path: 'build/distributions/besu-${{ env.RELEASE_NAME }}.zip.sha256'
name: besu-${{ env.RELEASE_NAME }}.zip.sha256
path: 'build/distributions/besu-${{ env.RELEASE_VERSION }}.zip.sha256'
name: besu-${{ env.RELEASE_VERSION }}.zip.sha256
compression-level: 0
- name: upload checksum tar.gz
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with:
path: 'build/distributions/besu-${{ env.RELEASE_NAME }}.tar.gz.sha256'
name: besu-${{ env.RELEASE_NAME }}.tar.gz.sha256
path: 'build/distributions/besu-${{ env.RELEASE_VERSION }}.tar.gz.sha256'
name: besu-${{ env.RELEASE_VERSION }}.tar.gz.sha256
compression-level: 0
test-windows:
@ -127,7 +127,7 @@ jobs:
with:
distribution: temurin
java-version: 21
- name: Download zip
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe
with:
@ -153,7 +153,7 @@ jobs:
with:
distribution: temurin
java-version: 21
- name: Download tar.gz
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe
with:
@ -172,20 +172,20 @@ jobs:
runs-on: ubuntu-22.04
needs: [test-linux, test-windows]
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} # Use the output from the pre_process_release job
steps:
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ env.RELEASE_NAME }}
ref: ${{ env.RELEASE_VERSION }}
- name: hadoLint
run: docker run --rm -i hadolint/hadolint < docker/Dockerfile
docker-publish:
needs: [validate, docker-lint]
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} # Use the output from the pre_process_release job
strategy:
fail-fast: false
matrix:
@ -198,7 +198,7 @@ jobs:
id: prep
run: |
platform=${{ matrix.platform }}
if [ "$platform" = 'ubuntu-22.04' ]; then
if [ "$platform" = 'ubuntu-22.04' ]; then
echo "PLATFORM_PAIR=linux-amd64" >> $GITHUB_OUTPUT
echo "ARCH=amd64" >> $GITHUB_OUTPUT
else
@ -209,7 +209,7 @@ jobs:
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ env.RELEASE_NAME }}
ref: ${{ env.RELEASE_VERSION }}
- name: short sha
id: shortSha
@ -225,7 +225,7 @@ jobs:
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
with:
cache-disabled: true
- name: install goss
run: |
mkdir -p docker/reports
@ -244,23 +244,23 @@ jobs:
architecture: ${{ steps.prep.outputs.ARCH }}
with:
cache-disabled: true
arguments: testDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_NAME}} -Prelease.releaseVersion=${{ env.RELEASE_NAME }}
arguments: testDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_VERSION}} -Prelease.releaseVersion=${{ env.RELEASE_VERSION }}
- name: publish
env:
architecture: ${{ steps.prep.outputs.ARCH }}
run: ./gradlew --no-daemon dockerUpload -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_NAME}} -Prelease.releaseVersion=${{ env.RELEASE_NAME }}
run: ./gradlew --no-daemon dockerUpload -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_VERSION}} -Prelease.releaseVersion=${{ env.RELEASE_VERSION }}
docker-manifest:
needs: [validate, docker-publish]
runs-on: ubuntu-22.04
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
steps:
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ env.RELEASE_NAME }}
ref: ${{ env.RELEASE_VERSION }}
- name: Set up Java
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
@ -281,24 +281,48 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD_RW }}
- name: multi-arch docker
run: ./gradlew manifestDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_NAME}} -Prelease.releaseVersion=${{ env.RELEASE_NAME }}
run: ./gradlew manifestDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_VERSION}} -Prelease.releaseVersion=${{ env.RELEASE_VERSION }}
docker-verify:
needs: [validate,docker-manifest]
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job
runs-on: ubuntu-22.04
permissions:
contents: read
actions: write
CONTAINER_NAME: besu-check
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
runs-on: ${{ matrix.combination.runner }}
timeout-minutes: 4
strategy:
matrix:
combination:
- tag: ${{ needs.validate.outputs.release_version }}
platform: ''
runner: ubuntu-22.04
- tag: ${{ needs.validate.outputs.release_version }}-amd64
platform: 'linux/amd64'
runner: ubuntu-22.04
- tag: ${{ needs.validate.outputs.release_version }}-arm64
platform: ''
runner: besu-arm64
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
sparse-checkout: '.github/workflows/BesuContainerVerify.sh'
- name: Start container
run: |
PLATFORM_OPT=""
[[ x${{ matrix.combination.platform }} != 'x' ]] && PLATFORM_OPT="--platform ${{ matrix.combination.platform }}"
docker run -d $PLATFORM_OPT --name ${{ env.CONTAINER_NAME }} ${{ secrets.DOCKER_ORG }}/besu:${{ matrix.combination.tag }}
- name: Trigger container verify
run: echo '{"version":"${{ env.RELEASE_NAME }}","verify-latest-version":"false"}' | gh workflow run container-verify.yml --json
- name: Verify besu container
run: bash .github/workflows/BesuContainerVerify.sh
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ matrix.combination.tag }}
VERSION: ${{ env.RELEASE_VERSION }}
CHECK_LATEST: false
- name: Stop container
run: docker stop ${{ env.CONTAINER_NAME }}
release-draft:
runs-on: ubuntu-22.04
@ -306,42 +330,42 @@ jobs:
permissions:
contents: write
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }}
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
steps:
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ env.RELEASE_NAME }}
ref: ${{ env.RELEASE_VERSION }}
- name: Download Besu artifacts
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe
with:
pattern: besu-${{env.RELEASE_NAME}}*
pattern: besu-${{env.RELEASE_VERSION}}*
merge-multiple: true
- name: Draft release notes
run: |
echo "## ${{env.RELEASE_NAME}}" > draft-release-notes.md
echo "## ${{env.RELEASE_VERSION}}" > draft-release-notes.md
echo "## Upcoming Breaking Changes" >> draft-release-notes.md
echo "## Breaking Changes" >> draft-release-notes.md
echo "## Additions and Improvements" >> draft-release-notes.md
echo "## Bug fixes" >> draft-release-notes.md
echo "`$(cat besu-${{env.RELEASE_NAME}}.zip.sha256)`" >> draft-release-notes.md
echo "`$(cat besu-${{env.RELEASE_NAME}}.tar.gz.sha256)`" >> draft-release-notes.md
cat besu-${{env.RELEASE_NAME}}.zip.sha256 >> draft-release-notes.md
cat besu-${{env.RELEASE_NAME}}.tar.gz.sha256 >> draft-release-notes.md
echo "`$(cat besu-${{env.RELEASE_VERSION}}.zip.sha256)`" >> draft-release-notes.md
echo "`$(cat besu-${{env.RELEASE_VERSION}}.tar.gz.sha256)`" >> draft-release-notes.md
cat besu-${{env.RELEASE_VERSION}}.zip.sha256 >> draft-release-notes.md
cat besu-${{env.RELEASE_VERSION}}.tar.gz.sha256 >> draft-release-notes.md
- name: Draft release
run: |
gh release create \
--draft \
--title=${{env.RELEASE_NAME}} \
--title=${{env.RELEASE_VERSION}} \
--notes-file draft-release-notes.md \
--verify-tag ${{env.RELEASE_NAME}} \
besu-${{env.RELEASE_NAME}}.tar.gz \
besu-${{env.RELEASE_NAME}}.zip \
besu-${{env.RELEASE_NAME}}.zip.sha256 \
besu-${{env.RELEASE_NAME}}.tar.gz.sha256
--verify-tag ${{env.RELEASE_VERSION}} \
besu-${{env.RELEASE_VERSION}}.tar.gz \
besu-${{env.RELEASE_VERSION}}.zip \
besu-${{env.RELEASE_VERSION}}.zip.sha256 \
besu-${{env.RELEASE_VERSION}}.tar.gz.sha256
env:
GH_TOKEN: ${{ github.token }}
@ -349,12 +373,12 @@ jobs:
runs-on: ubuntu-22.04
needs: [validate, test-linux, test-windows]
env:
RELEASE_NAME: ${{ needs.validate.outputs.release_name }}
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
steps:
- name: checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ env.RELEASE_NAME }}
ref: ${{ env.RELEASE_VERSION }}
- name: Set up Java
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
@ -371,4 +395,4 @@ jobs:
env:
ARTIFACTORY_USER: ${{ secrets.BESU_ARTIFACTORY_USER }}
ARTIFACTORY_KEY: ${{ secrets.BESU_ARTIFACTORY_TOKEN }}
run: ./gradlew -Prelease.releaseVersion=${{ env.RELEASE_NAME }} -Pversion=${{env.RELEASE_NAME}} artifactoryPublish
run: ./gradlew -Prelease.releaseVersion=${{ env.RELEASE_VERSION }} -Pversion=${{env.RELEASE_VERSION}} artifactoryPublish

@ -38,4 +38,4 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_ORGANIZATION: ${{ vars.SONAR_ORGANIZATION }}
SONAR_PROJECT_KEY: ${{ vars.SONAR_PROJECT_KEY }}
run: ./gradlew build sonarqube --continue --info -Dorg.gradle.parallel=true -Dorg.gradle.caching=true
run: ./gradlew build sonar --continue -Dorg.gradle.parallel=true -Dorg.gradle.caching=true

@ -1,6 +1,6 @@
#!/usr/bin/env bash
##
## Copyright contributors to Hyperledger Besu.
## Copyright contributors to 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

@ -1,6 +1,6 @@
#!/bin/bash
##
## Copyright contributors to Hyperledger Besu.
## Copyright contributors to 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

@ -1,13 +1,29 @@
# Changelog
## [Unreleased]
- Added isLabelsObserved to LabelledGauge in plugin-api. Default implementation returns false.
### Breaking Changes
### Upcoming Breaking Changes
- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release
### Additions and Improvements
- Fine tune already seen txs tracker when a tx is removed from the pool [#7755](https://github.com/hyperledger/besu/pull/7755)
- Create and publish Besu BOM (Bill of Materials) [#7615](https://github.com/hyperledger/besu/pull/7615)
- Update Java dependencies [#7786](https://github.com/hyperledger/besu/pull/7786)
- Add a method to get all the transaction in the pool, to the `TransactionPoolService`, to easily access the transaction pool content from plugins [#7813](https://github.com/hyperledger/besu/pull/7813)
### Bug fixes
## 24.10.0
### Breaking Changes
- Besu will now fail to start if any plugins encounter errors during initialization. To allow Besu to continue running despite plugin errors, use the `--plugin-continue-on-error` option. [#7662](https://github.com/hyperledger/besu/pull/7662)
### Upcoming Breaking Changes
- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release
- `--host-whitelist` has been deprecated in favor of `--host-allowlist` since 2020 and will be removed in a future release
### Additions and Improvements
- Remove privacy test classes support [#7569](https://github.com/hyperledger/besu/pull/7569)
- Add Blob Transaction Metrics [#7622](https://github.com/hyperledger/besu/pull/7622)
@ -17,6 +33,9 @@
- Interrupt pending transaction processing on block creation timeout [#7673](https://github.com/hyperledger/besu/pull/7673)
- Align gas cap calculation for transaction simulation to Geth approach [#7703](https://github.com/hyperledger/besu/pull/7703)
- Expose chainId in the `BlockchainService` [7702](https://github.com/hyperledger/besu/pull/7702)
- Add support for `chainId` in `CallParameters` [#7720](https://github.com/hyperledger/besu/pull/7720)
- Add `--ephemery` network support for Ephemery Testnet [#7563](https://github.com/hyperledger/besu/pull/7563) thanks to [@gconnect](https://github.com/gconnect)
- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647)
### Bug fixes
- Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575)
@ -24,6 +43,10 @@
- Corrects a regression where custom plugin services are not initialized correctly. [#7625](https://github.com/hyperledger/besu/pull/7625)
- Fix for IBFT2 chains using the BONSAI DB format [#7631](https://github.com/hyperledger/besu/pull/7631)
- Fix reading `tx-pool-min-score` option from configuration file [#7623](https://github.com/hyperledger/besu/pull/7623)
- Fix an unhandled PeerTable exception [#7733](https://github.com/hyperledger/besu/issues/7733)
- Fix RocksDBException: Busy leading to MerkleTrieException: Unable to load trie node value [#7745](https://github.com/hyperledger/besu/pull/7745)
- If a BFT validator node is syncing, pause block production until sync has completed [#7657](https://github.com/hyperledger/besu/pull/7657)
- Fix eth_feeHistory rewards when bounded by configuration [#7750](https://github.com/hyperledger/besu/pull/7750)
## 24.9.1
@ -4461,7 +4484,6 @@ Specify `*` or `all` for `--host-whitelist` to effectively disable host protecti
- Send client quitting disconnect message to peers on shutdown (PR [#253](https://github.com/PegaSysEng/pantheon/pull/253))
- Improved error message for port conflict error (PR [#232](https://github.com/PegaSysEng/pantheon/pull/232))
### Technical Improvements
- Upgraded Ethereum reference tests to 6.0 beta 2. (thanks to [@jvirtanen](https://github.com/jvirtanen) for the initial upgrade to beta 1)
- Set Java compiler default encoding to UTF-8 (PR [#238](https://github.com/PegaSysEng/pantheon/pull/238) thanks to [@matt9ucci](https://github.com/matt9ucci))

@ -9,6 +9,7 @@
| Name | Github | LFID |
| ---------------- | ---------------- | ---------------- |
| Ameziane Hamlat | ahamlat | ahamlat |
| Chaminda Divitotawela | cdivitotawela | cdivitotawela |
| Daniel Lehrner | daniellehrner | daniellehrner |
| Diego López León | diega | diega |
| Fabio Di Fabio | fab-10 | fab-10 |
@ -18,7 +19,7 @@
| Justin Florentine| jflo | RoboCopsGoneMad |
| Jason Frame | jframe | jframe |
| Joshua Fernandes | joshuafernandes | joshuafernandes |
| Luis Pinto | lu-pinto | lu-pinto
| Luis Pinto | lu-pinto | lu-pinto |
| Lucas Saldanha | lucassaldanha | lucassaldanha |
| Sally MacFarlane | macfarla | macfarla |
| Karim Taam | matkt | matkt |

@ -14,15 +14,15 @@ Besu is an Apache 2.0 licensed, MainNet compatible, Ethereum client written in J
* [Besu User Documentation]
* [Besu Issues]
* [Besu Wiki](https://wiki.hyperledger.org/display/BESU/Besu)
* [How to Contribute to Besu](https://wiki.hyperledger.org/display/BESU/How+to+Contribute)
* [Besu Roadmap & Planning](https://wiki.hyperledger.org/pages/viewpage.action?pageId=24781786)
* [Besu Wiki](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/)
* [How to Contribute to Besu](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156850/How+to+Contribute)
* [Besu Roadmap & Planning](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154278/Besu+Roadmap+Planning)
## Issues
Besu issues are tracked [in the github issues tab][Besu Issues].
See our [guidelines](https://wiki.hyperledger.org/display/BESU/Issues) for more details on searching and creating issues.
See our [guidelines](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154243/Issues) for more details on searching and creating issues.
If you have any questions, queries or comments, [Besu channel on Discord] is the place to find us.
@ -34,20 +34,19 @@ To install the Besu binary, follow [these instructions](https://besu.hyperledger
## Besu Developers
* [Contributing Guidelines]
* [Coding Conventions](https://wiki.hyperledger.org/display/BESU/Coding+Conventions)
* [Command Line Interface (CLI) Style Guide](https://wiki.hyperledger.org/display/BESU/Besu+CLI+Style+Guide)
* [Coding Conventions](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154259/Coding+Conventions)
* [Command Line Interface (CLI) Style Guide](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154260/Besu+CLI+Style+Guide)
* [Besu User Documentation] for running and using Besu
### Development
Instructions for how to get started with developing on the Besu codebase. Please also read the
[wiki](https://wiki.hyperledger.org/display/BESU/Pull+Requests) for more details on how to submit a pull request (PR).
[wiki](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154251/Pull+Requests) for more details on how to submit a pull request (PR).
* [Checking Out and Building](https://wiki.hyperledger.org/display/BESU/Building+from+source)
* [Running Developer Builds](https://wiki.hyperledger.org/display/BESU/Building+from+source#running-developer-builds)
* [Code Coverage](https://wiki.hyperledger.org/display/BESU/Code+coverage)
* [Logging](https://wiki.hyperledger.org/display/BESU/Logging) or the [Documentation's Logging section](https://besu.hyperledger.org/public-networks/how-to/monitor/logging)
* [Checking Out and Building](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154264/Building+from+source)
* [Code Coverage](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154288/Code+coverage)
* [Logging](https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22154291/Logging) or the [Documentation's Logging section](https://besu.hyperledger.org/public-networks/how-to/monitor/logging)
## Release Notes

@ -33,7 +33,6 @@ dependencies {
implementation 'info.picocli:picocli'
implementation 'io.reactivex.rxjava2:rxjava'
implementation 'io.vertx:vertx-core'
implementation 'junit:junit'
implementation 'io.opentelemetry:opentelemetry-api'
implementation 'io.tmio:tuweni-bytes'
implementation 'io.tmio:tuweni-io'
@ -46,6 +45,5 @@ dependencies {
implementation 'org.web3j:crypto'
implementation 'org.wiremock:wiremock'
implementation 'org.testcontainers:testcontainers'
implementation 'org.junit.jupiter:junit-jupiter'
}

@ -49,13 +49,15 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.web3.Web3Transactio
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ProcessBuilder.Redirect;
import java.math.BigInteger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.After;
import org.apache.logging.log4j.ThreadContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -125,7 +127,15 @@ public class AcceptanceTestBase {
exitedSuccessfully = new ExitedWithCode(0);
}
@After
@BeforeEach
public void setUp(final TestInfo testInfo) {
// log4j is configured to create a file per test
// build/acceptanceTestLogs/${ctx:class}.${ctx:test}.log
ThreadContext.put("class", this.getClass().getSimpleName());
ThreadContext.put("test", testInfo.getTestMethod().get().getName());
}
@AfterEach
public void tearDownAcceptanceTestBase() {
reportMemory();
cluster.close();
@ -143,7 +153,9 @@ public class AcceptanceTestBase {
if (command != null) {
LOG.info("Memory usage at end of test:");
final ProcessBuilder processBuilder =
new ProcessBuilder(command).redirectErrorStream(true).redirectInput(Redirect.INHERIT);
new ProcessBuilder(command)
.redirectErrorStream(true)
.redirectInput(ProcessBuilder.Redirect.INHERIT);
try {
final Process memInfoProcess = processBuilder.start();
outputProcessorExecutor.execute(() -> printOutput(memInfoProcess));

@ -1,200 +0,0 @@
/*
* 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.dsl;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Blockchain;
import org.hyperledger.besu.tests.acceptance.dsl.condition.admin.AdminConditions;
import org.hyperledger.besu.tests.acceptance.dsl.condition.bft.BftConditions;
import org.hyperledger.besu.tests.acceptance.dsl.condition.clique.CliqueConditions;
import org.hyperledger.besu.tests.acceptance.dsl.condition.eth.EthConditions;
import org.hyperledger.besu.tests.acceptance.dsl.condition.login.LoginConditions;
import org.hyperledger.besu.tests.acceptance.dsl.condition.net.NetConditions;
import org.hyperledger.besu.tests.acceptance.dsl.condition.perm.PermissioningConditions;
import org.hyperledger.besu.tests.acceptance.dsl.condition.process.ExitedWithCode;
import org.hyperledger.besu.tests.acceptance.dsl.condition.txpool.TxPoolConditions;
import org.hyperledger.besu.tests.acceptance.dsl.condition.web3.Web3Conditions;
import org.hyperledger.besu.tests.acceptance.dsl.contract.ContractVerifier;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeFactory;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.permissioning.PermissionedNodeBuilder;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.account.AccountTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.admin.AdminTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.bft.BftTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.clique.CliqueTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.contract.ContractTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.miner.MinerTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.net.NetTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.PermissioningTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.txpool.TxPoolTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.web3.Web3Transactions;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.logging.log4j.ThreadContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Superclass for acceptance tests. For now (transition to junit5 is ongoing) this class supports
* junit5 format. Once the transition is complete, this class can be removed and recombined with
* AcceptanceTestBase (original).
*/
@ExtendWith(AcceptanceTestBaseTestWatcher.class)
public class AcceptanceTestBaseJunit5 {
private static final Logger LOG = LoggerFactory.getLogger(AcceptanceTestBaseJunit5.class);
protected final Accounts accounts;
protected final AccountTransactions accountTransactions;
protected final AdminConditions admin;
protected final AdminTransactions adminTransactions;
protected final Blockchain blockchain;
protected final CliqueConditions clique;
protected final CliqueTransactions cliqueTransactions;
protected final Cluster cluster;
protected final ContractVerifier contractVerifier;
protected final ContractTransactions contractTransactions;
protected final EthConditions eth;
protected final EthTransactions ethTransactions;
protected final BftTransactions bftTransactions;
protected final BftConditions bft;
protected final LoginConditions login;
protected final NetConditions net;
protected final BesuNodeFactory besu;
protected final PermissioningConditions perm;
protected final PermissionedNodeBuilder permissionedNodeBuilder;
protected final PermissioningTransactions permissioningTransactions;
protected final MinerTransactions minerTransactions;
protected final Web3Conditions web3;
protected final TxPoolConditions txPoolConditions;
protected final TxPoolTransactions txPoolTransactions;
protected final ExitedWithCode exitedSuccessfully;
private final ExecutorService outputProcessorExecutor = Executors.newCachedThreadPool();
protected AcceptanceTestBaseJunit5() {
ethTransactions = new EthTransactions();
accounts = new Accounts(ethTransactions);
adminTransactions = new AdminTransactions();
cliqueTransactions = new CliqueTransactions();
bftTransactions = new BftTransactions();
accountTransactions = new AccountTransactions(accounts);
permissioningTransactions = new PermissioningTransactions();
contractTransactions = new ContractTransactions();
minerTransactions = new MinerTransactions();
blockchain = new Blockchain(ethTransactions);
clique = new CliqueConditions(ethTransactions, cliqueTransactions);
eth = new EthConditions(ethTransactions);
bft = new BftConditions(bftTransactions);
login = new LoginConditions();
net = new NetConditions(new NetTransactions());
cluster = new Cluster(net);
perm = new PermissioningConditions(permissioningTransactions);
admin = new AdminConditions(adminTransactions);
web3 = new Web3Conditions(new Web3Transactions());
besu = new BesuNodeFactory();
txPoolTransactions = new TxPoolTransactions();
txPoolConditions = new TxPoolConditions(txPoolTransactions);
contractVerifier = new ContractVerifier(accounts.getPrimaryBenefactor());
permissionedNodeBuilder = new PermissionedNodeBuilder();
exitedSuccessfully = new ExitedWithCode(0);
}
@BeforeEach
public void setUp(final TestInfo testInfo) {
// log4j is configured to create a file per test
// build/acceptanceTestLogs/${ctx:class}.${ctx:test}.log
ThreadContext.put("class", this.getClass().getSimpleName());
ThreadContext.put("test", testInfo.getTestMethod().get().getName());
}
@AfterEach
public void tearDownAcceptanceTestBase() {
reportMemory();
cluster.close();
}
public void reportMemory() {
String os = System.getProperty("os.name");
String[] command = null;
if (os.contains("Linux")) {
command = new String[] {"/usr/bin/top", "-n", "1", "-o", "%MEM", "-b", "-c", "-w", "180"};
}
if (os.contains("Mac")) {
command = new String[] {"/usr/bin/top", "-l", "1", "-o", "mem", "-n", "20"};
}
if (command != null) {
LOG.info("Memory usage at end of test:");
final ProcessBuilder processBuilder =
new ProcessBuilder(command)
.redirectErrorStream(true)
.redirectInput(ProcessBuilder.Redirect.INHERIT);
try {
final Process memInfoProcess = processBuilder.start();
outputProcessorExecutor.execute(() -> printOutput(memInfoProcess));
memInfoProcess.waitFor();
LOG.debug("Memory info process exited with code {}", memInfoProcess.exitValue());
} catch (final Exception e) {
LOG.warn("Error running memory information process", e);
}
} else {
LOG.info("Don't know how to report memory for OS {}", os);
}
}
private void printOutput(final Process process) {
try (final BufferedReader in =
new BufferedReader(new InputStreamReader(process.getInputStream(), UTF_8))) {
String line = in.readLine();
while (line != null) {
LOG.info(line);
line = in.readLine();
}
} catch (final IOException e) {
LOG.warn("Failed to read output from memory information process: ", e);
}
}
protected void waitForBlockHeight(final Node node, final long blockchainHeight) {
WaitUtils.waitFor(
120,
() ->
assertThat(node.execute(ethTransactions.blockNumber()))
.isGreaterThanOrEqualTo(BigInteger.valueOf(blockchainHeight)));
}
@Test
void dryRunDetector() {
assertThat(true)
.withFailMessage("This test is here so gradle --dry-run executes this class")
.isTrue();
}
}

@ -14,7 +14,7 @@
*/
package org.hyperledger.besu.tests.acceptance.dsl.condition.blockchain;
import static junit.framework.TestCase.fail;
import static org.junit.jupiter.api.Assertions.fail;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;

@ -18,7 +18,7 @@ import static java.util.Collections.unmodifiableList;
import static org.apache.tuweni.io.file.Files.copyResource;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.config.MergeConfiguration;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.KeyPairUtil;
import org.hyperledger.besu.datatypes.Address;
@ -228,7 +228,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
});
this.requestedPlugins = requestedPlugins;
engineRpcConfiguration.ifPresent(
config -> MergeConfigOptions.setMergeEnabled(config.isEnabled()));
config -> MergeConfiguration.setMergeEnabled(config.isEnabled()));
this.extraCLIOptions = extraCLIOptions;
this.staticNodes = staticNodes;
this.isDnsEnabled = isDnsEnabled;

@ -18,7 +18,7 @@ import static com.google.common.base.Preconditions.checkState;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.hyperledger.besu.cli.options.TransactionPoolOptions;
import org.hyperledger.besu.cli.options.stable.DataStorageOptions;
import org.hyperledger.besu.cli.options.storage.DataStorageOptions;
import org.hyperledger.besu.cli.options.unstable.NetworkingOptions;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;

@ -54,6 +54,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMer
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.MetricCategoryRegistryImpl;
import org.hyperledger.besu.metrics.MetricsSystemModule;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
@ -71,6 +72,7 @@ import org.hyperledger.besu.plugin.services.StorageService;
import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService;
import org.hyperledger.besu.plugin.services.TransactionSelectionService;
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry;
import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBPlugin;
import org.hyperledger.besu.services.BesuConfigurationImpl;
import org.hyperledger.besu.services.BesuEventsImpl;
@ -396,6 +398,12 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
retval.init(blockchain, transactionSimulator);
return retval;
}
@Provides
@Singleton
MetricCategoryRegistryImpl provideMetricCategoryRegistry() {
return new MetricCategoryRegistryImpl();
}
}
@Module
@ -476,6 +484,8 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
final BesuConfiguration commonPluginConfiguration,
final PermissioningServiceImpl permissioningService,
final MetricCategoryRegistryImpl metricCategoryRegistry,
final MetricsSystem metricsSystem,
final @Named("ExtraCLIOptions") List<String> extraCLIOptions,
final @Named("RequestedPlugins") List<String> requestedPlugins) {
final CommandLine commandLine = new CommandLine(CommandSpec.create());
@ -492,6 +502,8 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
TransactionSimulationService.class, transactionSimulationServiceImpl);
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);
besuPluginContext.addService(BesuConfiguration.class, commonPluginConfiguration);
besuPluginContext.addService(MetricCategoryRegistry.class, metricCategoryRegistry);
besuPluginContext.addService(MetricsSystem.class, metricsSystem);
final Path pluginsPath;
final String pluginDir = System.getProperty("besu.plugins.dir");

@ -14,7 +14,7 @@
*/
package org.hyperledger.besu.tests.acceptance.dsl.transaction.account;
import static org.testcontainers.shaded.com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.crypto.SignatureAlgorithm;

@ -14,8 +14,6 @@ dependencies {
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.junit.jupiter:junit-jupiter'
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
}
task testPluginsJar(type: Jar) {

@ -68,21 +68,17 @@ dependencies {
testImplementation 'io.opentracing:opentracing-api'
testImplementation 'io.opentracing:opentracing-util'
testImplementation 'io.vertx:vertx-core'
testImplementation 'junit:junit'
testImplementation 'org.apache.commons:commons-compress'
testImplementation 'org.apache.logging.log4j:log4j-core'
testImplementation 'io.tmio:tuweni-crypto'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.testcontainers:testcontainers'
testImplementation 'org.web3j:abi'
testImplementation 'org.web3j:besu'
testImplementation 'org.web3j:core'
testImplementation 'org.wiremock:wiremock'
testImplementation project(path: ':acceptance-tests:tests:shanghai')
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
}
test.enabled = false
@ -106,7 +102,8 @@ task acceptanceTest(type: Test) {
setSystemProperties(test.getSystemProperties())
systemProperty 'acctests.runBesuAsProcess', 'true'
systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security"
mustRunAfter rootProject.subprojects*.test
def javaProjects = rootProject.subprojects - project(':platform')
mustRunAfter javaProjects.test
description = 'Runs ALL Besu acceptance tests (mainnet and non-mainnet).'
group = 'verification'
@ -135,7 +132,8 @@ task acceptanceTestNotPrivacy(type: Test) {
setSystemProperties(test.getSystemProperties())
systemProperty 'acctests.runBesuAsProcess', 'true'
systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security"
mustRunAfter rootProject.subprojects*.test
def javaProjects = rootProject.subprojects - project(':platform')
mustRunAfter javaProjects.test
description = 'Runs MAINNET Besu acceptance tests (excluding specific non-mainnet suites).'
group = 'verification'
@ -163,7 +161,8 @@ task acceptanceTestCliqueBft(type: Test) {
setSystemProperties(test.getSystemProperties())
systemProperty 'acctests.runBesuAsProcess', 'true'
systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security"
mustRunAfter rootProject.subprojects*.test
def javaProjects = rootProject.subprojects - project(':platform')
mustRunAfter javaProjects.test
description = 'Runs Clique and BFT Besu acceptance tests.'
group = 'verification'
@ -192,7 +191,8 @@ task acceptanceTestBftSoak(type: Test) {
// Set to any time > 60 minutes to run the soak test for longer
// systemProperty 'acctests.soakTimeMins', '120'
systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security"
mustRunAfter rootProject.subprojects*.test
def javaProjects = rootProject.subprojects - project(':platform')
mustRunAfter javaProjects.test
description = 'Runs BFT soak test.'
group = 'verification'
@ -219,7 +219,8 @@ task acceptanceTestPermissioning(type: Test) {
setSystemProperties(test.getSystemProperties())
systemProperty 'acctests.runBesuAsProcess', 'true'
systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security"
mustRunAfter rootProject.subprojects*.test
def javaProjects = rootProject.subprojects - project(':platform')
mustRunAfter javaProjects.test
description = 'Runs Permissioning Besu acceptance tests.'
group = 'verification'

@ -14,7 +14,7 @@
*/
package org.hyperledger.besu.tests.acceptance.bft;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import java.util.stream.Stream;
@ -22,7 +22,7 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.provider.Arguments;
@Disabled("This is not a test class, it offers BFT parameterization only.")
public abstract class ParameterizedBftTestBase extends AcceptanceTestBaseJunit5 {
public abstract class ParameterizedBftTestBase extends AcceptanceTestBase {
protected String bftType;
protected BftAcceptanceTestParameterization nodeFactory;

@ -14,13 +14,13 @@
*/
package org.hyperledger.besu.tests.acceptance.bft.qbft;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.junit.jupiter.api.Test;
public class QbftContractAcceptanceTest extends AcceptanceTestBaseJunit5 {
public class QbftContractAcceptanceTest extends AcceptanceTestBase {
@Test
public void shouldMineOnMultipleNodesEvenWhenClusterContainsNonValidator() throws Exception {

@ -41,7 +41,7 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase {
private static final long ONE_MINUTE = Duration.of(1, ChronoUnit.MINUTES).toMillis();
private static final long THREE_MINUTES = Duration.of(1, ChronoUnit.MINUTES).toMillis();
private static final long THREE_MINUTES = Duration.of(3, ChronoUnit.MINUTES).toMillis();
private static final long TEN_SECONDS = Duration.of(10, ChronoUnit.SECONDS).toMillis();

@ -14,14 +14,14 @@
*/
package org.hyperledger.besu.tests.acceptance.clique;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.io.IOException;
import org.junit.jupiter.api.Test;
public class CliqueDiscardRpcAcceptanceTest extends AcceptanceTestBaseJunit5 {
public class CliqueDiscardRpcAcceptanceTest extends AcceptanceTestBase {
@Test
public void shouldDiscardVotes() throws IOException {

@ -16,7 +16,7 @@ package org.hyperledger.besu.tests.acceptance.clique;
import static org.hyperledger.besu.tests.acceptance.dsl.transaction.clique.CliqueTransactions.LATEST;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.junit.jupiter.api.BeforeEach;
@ -24,7 +24,7 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled("flaky test due to hardcoded block numbers")
public class CliqueGetSignersRpcAcceptanceTest extends AcceptanceTestBaseJunit5 {
public class CliqueGetSignersRpcAcceptanceTest extends AcceptanceTestBase {
private BesuNode minerNode1;
private BesuNode minerNode2;

@ -18,7 +18,7 @@ import static java.util.stream.Collectors.joining;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.data.Percentage.withPercentage;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationFactory.CliqueOptions;
@ -32,7 +32,7 @@ import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.web3j.protocol.core.DefaultBlockParameter;
public class CliqueMiningAcceptanceTest extends AcceptanceTestBaseJunit5 {
public class CliqueMiningAcceptanceTest extends AcceptanceTestBase {
@Test
public void shouldMineTransactionsOnSingleNode() throws IOException {

@ -14,14 +14,14 @@
*/
package org.hyperledger.besu.tests.acceptance.clique;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.io.IOException;
import org.junit.jupiter.api.Test;
public class CliqueProposalRpcAcceptanceTest extends AcceptanceTestBaseJunit5 {
public class CliqueProposalRpcAcceptanceTest extends AcceptanceTestBase {
@Test
public void shouldReturnProposals() throws IOException {

@ -14,7 +14,7 @@
*/
package org.hyperledger.besu.tests.acceptance.clique;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.condition.clique.ExpectNonceVote.CLIQUE_NONCE_VOTE;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
@ -23,7 +23,7 @@ import java.io.IOException;
import org.junit.jupiter.api.Test;
public class CliqueProposeRpcAcceptanceTest extends AcceptanceTestBaseJunit5 {
public class CliqueProposeRpcAcceptanceTest extends AcceptanceTestBase {
@Test
public void shouldAddValidators() throws IOException {

@ -14,14 +14,14 @@
*/
package org.hyperledger.besu.tests.acceptance.clique;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.io.IOException;
import org.junit.jupiter.api.Test;
public class CliqueZeroValidatorsAcceptanceTest extends AcceptanceTestBaseJunit5 {
public class CliqueZeroValidatorsAcceptanceTest extends AcceptanceTestBase {
@Test
public void zeroValidatorsFormValidCluster() throws IOException {

@ -15,7 +15,7 @@
package org.hyperledger.besu.tests.acceptance.crypto;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SECP256R1;
@ -80,7 +80,7 @@ public class SECP256R1AcceptanceTest extends AcceptanceTestBase {
// the signature algorithm instance to SECP256R1 as it could influence other tests running at
// the same time. So we only execute the test when ProcessBesuNodeRunner is used, as there is
// not conflict because we use separate processes.
assumeThat(BesuNodeRunner.isProcessBesuNodeRunner()).isTrue();
assumeTrue(BesuNodeRunner.isProcessBesuNodeRunner());
minerNode.verify(net.awaitPeerCount(1));
otherNode.verify(net.awaitPeerCount(1));

@ -22,7 +22,9 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions
import java.io.IOException;
import java.util.Optional;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import okhttp3.Call;
import okhttp3.MediaType;
@ -74,17 +76,15 @@ public class PragueAcceptanceTestHelper {
final Call getPayloadRequest = createEngineCall(createGetPayloadRequest(payloadId));
final ObjectNode executionPayload;
final ArrayNode executionRequests;
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");
JsonNode result = mapper.readTree(getPayloadResponse.body().string()).get("result");
executionPayload = (ObjectNode) result.get("executionPayload");
executionRequests = (ArrayNode) result.get("executionRequests");
newBlockHash = executionPayload.get("blockHash").asText();
parentBeaconBlockRoot = executionPayload.remove("parentBeaconBlockRoot").asText();
@ -94,7 +94,8 @@ public class PragueAcceptanceTestHelper {
final Call newPayloadRequest =
createEngineCall(
createNewPayloadRequest(executionPayload.toString(), parentBeaconBlockRoot));
createNewPayloadRequest(
executionPayload.toString(), parentBeaconBlockRoot, executionRequests.toString()));
try (final Response newPayloadResponse = newPayloadRequest.execute()) {
assertThat(newPayloadResponse.code()).isEqualTo(200);
}
@ -168,7 +169,9 @@ public class PragueAcceptanceTestHelper {
}
private String createNewPayloadRequest(
final String executionPayload, final String parentBeaconBlockRoot) {
final String executionPayload,
final String parentBeaconBlockRoot,
final String executionRequests) {
return "{"
+ " \"jsonrpc\": \"2.0\","
+ " \"method\": \"engine_newPayloadV4\","
@ -178,6 +181,8 @@ public class PragueAcceptanceTestHelper {
+ "\""
+ parentBeaconBlockRoot
+ "\""
+ ","
+ executionRequests
+ "],"
+ " \"id\": 67"
+ "}";

@ -20,8 +20,11 @@ import java.util.stream.Stream;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.provider.Arguments;
// TODO SLD
@Disabled("TODO SLD - Enable when Prague spec is finalized")
public class ExecutionEnginePragueAcceptanceTest extends AbstractJsonRpcTest {
private static final String GENESIS_FILE = "/jsonrpc/engine/prague/genesis.json";
private static final String TEST_CASE_PATH = "/jsonrpc/engine/prague/test-cases/";

@ -18,21 +18,21 @@ import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class MiningAcceptanceTest extends AcceptanceTestBase {
class MiningAcceptanceTest extends AcceptanceTestBase {
private Node minerNode;
@Before
@BeforeEach
public void setUp() throws Exception {
minerNode = besu.createMinerNode("miner1");
cluster.start(minerNode);
}
@Test
public void shouldMineTransactions() {
void shouldMineTransactions() {
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
minerNode.execute(accountTransactions.createTransfer(sender, 50));

@ -16,7 +16,7 @@ package org.hyperledger.besu.tests.acceptance.plugins;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.io.File;
@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
public class BadCLIOptionsPluginTest extends AcceptanceTestBaseJunit5 {
public class BadCLIOptionsPluginTest extends AcceptanceTestBase {
private BesuNode node;
@BeforeEach

@ -14,7 +14,7 @@
*/
package org.hyperledger.besu.tests.acceptance.plugins;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.io.File;
@ -28,7 +28,7 @@ import org.awaitility.Awaitility;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class BesuEventsPluginTest extends AcceptanceTestBaseJunit5 {
public class BesuEventsPluginTest extends AcceptanceTestBase {
private BesuNode pluginNode;
private BesuNode minerNode;

@ -15,7 +15,7 @@
package org.hyperledger.besu.tests.acceptance.plugins;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBaseJunit5;
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;
@ -27,7 +27,7 @@ import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class PermissioningPluginTest extends AcceptanceTestBaseJunit5 {
public class PermissioningPluginTest extends AcceptanceTestBase {
private BesuNode minerNode;
private BesuNode aliceNode;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -12,14 +12,14 @@
"id": 67,
"result": {
"number": "0x0",
"hash" : "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"hash" : "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce" : "0x0000000000000042",
"sha3Uncles" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"transactionsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd",
"stateRoot" : "0x860be6ab5a8fc2003c3739bfe2cdbcd9dbb273c8ea42951b832a8e1f22fb3a60",
"receiptsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"miner" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x400000000",

@ -4,8 +4,8 @@
"method": "engine_forkchoiceUpdatedV3",
"params": [
{
"headBlockHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"safeBlockHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"headBlockHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"safeBlockHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
@ -24,10 +24,10 @@
"result": {
"payloadStatus": {
"status": "VALID",
"latestValidHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"latestValidHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"validationError": null
},
"payloadId": "0x28264396eca1deef"
"payloadId": "0x282643b677b85211"
}
},
"statusCode": 200

@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV3",
"params": [
"0x28264396eca1deef"
"0x282643b677b85211"
],
"id": 67
},
@ -12,9 +12,9 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"parentHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd",
"stateRoot": "0x860be6ab5a8fc2003c3739bfe2cdbcd9dbb273c8ea42951b832a8e1f22fb3a60",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -29,7 +29,7 @@
"blockNumber": "0x1",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0",
"blockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593"
"blockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e"
},
"blockValue": "0x0",
"blobsBundle": {

@ -4,9 +4,9 @@
"method": "engine_newPayloadV3",
"params": [
{
"parentHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"parentHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd",
"stateRoot": "0x860be6ab5a8fc2003c3739bfe2cdbcd9dbb273c8ea42951b832a8e1f22fb3a60",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -14,13 +14,13 @@
"timestamp": "0x10",
"extraData": "0x",
"baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"transactions": [],
"withdrawals": [],
"blockNumber": "0x1",
"blockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0"
"blobGasUsed": "0x0",
"blockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
},
[],
"0x0000000000000000000000000000000000000000000000000000000000000000"
@ -32,7 +32,7 @@
"id": 67,
"result": {
"status": "VALID",
"latestValidHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"latestValidHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"validationError": null
}
},

@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3",
"params": [
{
"headBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"safeBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"finalizedBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593"
"headBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"safeBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"finalizedBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e"
},
null
],
@ -18,7 +18,7 @@
"result": {
"payloadStatus": {
"status": "VALID",
"latestValidHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"latestValidHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"validationError": null
},
"payloadId": null

@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3",
"params": [
{
"headBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"safeBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"finalizedBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593"
"headBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"safeBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"finalizedBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e"
},
{
"timestamp": "0x20",
@ -24,10 +24,10 @@
"result": {
"payloadStatus": {
"status": "VALID",
"latestValidHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"latestValidHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"validationError": null
},
"payloadId": "0x282643d3a905e721"
"payloadId": "0x282643fdcbcb1ddf"
}
},
"statusCode": 200

@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV4",
"params": [
"0x282643d3a905e721"
"0x282643fdcbcb1ddf"
],
"id": 67
},
@ -12,9 +12,9 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"parentHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x2e59916a57b535875bcd80d8472aeaa0027aa685d159804e8caa2f12d060155e",
"stateRoot": "0xed4093bcd157ba955245906a1cda7695d3b3f233af709f0adf17689abb4d93b4",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -23,22 +23,13 @@
"extraData": "0x",
"baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactions": [],
"withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [
{
"sourceAddress": "0xa4664c40aacebd82a2db79f0ea36c06bc6a19adb",
"validatorPubkey": "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e",
"amount": "0x0"
}
],
"consolidationRequests" : [],
"blockNumber": "0x2",
"blockHash": "0x27a2bc2ac21b3fc796f636bec1ec9cba100435f9a793176a83a5d4fa7cc13006",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0"
"blockHash": "0x303fb51567c090ed3fb7ac50a082ae3a0bcb8ff522d071011a1ca433561a4569"
},
"blockValue": "0x0",
"blobsBundle": {
@ -46,7 +37,12 @@
"proofs": [],
"blobs": []
},
"shouldOverrideBuilder": false
"shouldOverrideBuilder": false,
"executionRequests": [
"0x",
"0xa4664c40aacebd82a2db79f0ea36c06bc6a19adbb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e0000000000000000",
"0x"
]
}
},
"statusCode": 200

@ -17,24 +17,24 @@
"excessBlobGas": "0x0",
"transactions": [],
"withdrawals": [],
"depositRequests": null,
"blockNumber": "0x2",
"blockHash": "0x2331b2dc9c453e9a33685099742cbbcd529d42bd5681969f45754f06866c6766",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0"
},
[],
"0x0000000000000000000000000000000000000000000000000000000000000000"
"0x0000000000000000000000000000000000000000000000000000000000000000",
null
],
"id": 67
},
"response": {
"jsonrpc": "2.0",
"id": 67,
"error": {
"code": -32602,
"message": "Invalid params",
"data": "Missing deposit field"
"jsonrpc" : "2.0",
"id" : 67,
"error" : {
"code" : -32602,
"message" : "Invalid execution requests params",
"data" : "Missing execution requests field"
}
},
"statusCode": 200

@ -4,9 +4,9 @@
"method": "engine_newPayloadV4",
"params": [
{
"parentHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"parentHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x961878fdcdff52ea42db0026f59aa414a5ec2835e56ed1a8ae50c80a9fe3a04b",
"stateRoot": "0x176ea6dfa3b8efb148a025f759cccfaab02db38427b12a4ede73491eda397196",
"logsBloom": "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -15,34 +15,22 @@
"extraData": "0x",
"baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"transactions": [
"0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"
],
"withdrawals": [],
"depositRequests": [
{
"amount": "0x773594000",
"index": "0x0",
"pubkey": "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9",
"signature": "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9",
"withdrawalCredentials": "0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2"
}
],
"withdrawalRequests": [
{
"sourceAddress": "0xa4664c40aacebd82a2db79f0ea36c06bc6a19adb",
"amount": "0x0",
"validatorPubkey": "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"
}
],
"consolidationRequests": [],
"blockNumber": "0x2",
"blockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"receiptsRoot": "0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9",
"blobGasUsed": "0x0"
"blockHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6"
},
[],
"0x0000000000000000000000000000000000000000000000000000000000000000"
"0x0000000000000000000000000000000000000000000000000000000000000000",
[
"0xf84794a4664c40aacebd82a2db79f0ea36c06bc6a19adbb0b10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e80",
"0xa4664c40aacebd82a2db79f0ea36c06bc6a19adbb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e0000000000000000",
"0x"
]
],
"id": 67
},
@ -51,7 +39,7 @@
"id": 67,
"result": {
"status": "VALID",
"latestValidHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"latestValidHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"validationError": null
}
},

@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3",
"params": [
{
"headBlockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"safeBlockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"finalizedBlockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca"
"headBlockHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"safeBlockHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"finalizedBlockHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6"
},
{
"timestamp": "0x30",
@ -24,10 +24,10 @@
"result": {
"payloadStatus": {
"status": "VALID",
"latestValidHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"latestValidHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"validationError": null
},
"payloadId": "0x282643a16a58b5cf"
"payloadId": "0x282643aeecfdbccf"
}
},
"statusCode": 200

@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV4",
"params": [
"0x282643a16a58b5cf"
"0x282643aeecfdbccf"
],
"id": 67
},
@ -12,9 +12,9 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"parentHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x5fc31c01a451fe02f0e938de7ec7044aaba1159a81a1be64357bc70af226f304",
"stateRoot": "0xade3c29cae771ddfa994d3d2994f3bcbe084bc7bb23cdbb9bd7e35b39f007841",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -23,16 +23,13 @@
"extraData": "0x",
"baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactions": [],
"withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [],
"consolidationRequests" : [],
"blockNumber": "0x3",
"blockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0"
"blockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929"
},
"blockValue": "0x0",
"blobsBundle": {
@ -40,7 +37,12 @@
"proofs": [],
"blobs": []
},
"shouldOverrideBuilder": false
"shouldOverrideBuilder": false,
"executionRequests": [
"0x",
"0x",
"0x"
]
}
},
"statusCode": 200

@ -4,9 +4,9 @@
"method": "engine_newPayloadV3",
"params": [
{
"parentHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"parentHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x5fc31c01a451fe02f0e938de7ec7044aaba1159a81a1be64357bc70af226f304",
"stateRoot": "0xade3c29cae771ddfa994d3d2994f3bcbe084bc7bb23cdbb9bd7e35b39f007841",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -14,18 +14,21 @@
"timestamp": "0x30",
"extraData": "0x",
"baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"transactions": [],
"withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [],
"blockNumber": "0x3",
"blockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0"
"blockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929"
},
[],
"0x0000000000000000000000000000000000000000000000000000000000000000"
"0x0000000000000000000000000000000000000000000000000000000000000000",
[
"0x",
"0x",
"0x"
]
],
"id": 67
},
@ -34,7 +37,7 @@
"id": 67,
"result": {
"status": "VALID",
"latestValidHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"latestValidHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"validationError": null
}
},

@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3",
"params": [
{
"headBlockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"safeBlockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"finalizedBlockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634"
"headBlockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"safeBlockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"finalizedBlockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929"
},
{
"timestamp": "0x40",
@ -24,10 +24,10 @@
"result": {
"payloadStatus": {
"status": "VALID",
"latestValidHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"latestValidHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"validationError": null
},
"payloadId": "0x28264396a9634d41"
"payloadId": "0x282643ae671b03bf"
}
},
"statusCode": 200

@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV4",
"params": [
"0x28264396a9634d41"
"0x282643ae671b03bf"
],
"id": 67
},
@ -12,50 +12,40 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"parentHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x49df1f1a1d28a23fa752230d442077768787d392e9edb70c83d727d31e55eaac",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"stateRoot": "0xc7dbe7764cb5edd271a3e7fc4ffad23736aa1b8d4a5703e05a58db88d4ecbdc3",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
"gasUsed": "0x3ad4d",
"gasUsed": "0x3b6c5",
"timestamp": "0x40",
"extraData": "0x",
"baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactions": [
"0xf8a08085e8d4a51000832dc6c09400a3ca265ebcb825b45f985a16cefb49958ce01702b8388706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf2430000000000000000822fdfa00476c1a81f80f4c130acb5f8b8075468ba0893d766b7ec51a8d9723c573ad034a03bd3eaedabbaaf745f15023185ba66584ad3ee8bb40b9bef8c0b9ed27f8b1959",
"0xf8c80185e8d4a51000832dc6c09400b42dbf2194e931e80326d950320f7d9dbeac0201b860fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe822fe0a05b88b593926d340f448918ef1c6263356c37f2434774e0fdb1cb9d90cfa5a23ba003a86aac4adb774181ba51eda17efb5fbed99ad57895e6eb56ccdf508a88a7cc"
],
"withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [
{
"sourceAddress": "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f",
"amount": "0x0",
"validatorPubkey": "0x8706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf243"
}
],
"consolidationRequests": [
{
"sourceAddress": "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f",
"sourcePubkey": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"targetPubkey": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
}
],
"blockNumber": "0x4",
"receiptsRoot": "0x970fc81bb3e7fb21435f9a65a184aa9e3fd2f52b89fd859302b46954354266b5",
"blobGasUsed": "0x0",
"blockHash": "0x93df6f3484202f24c692354e2ab96e9948ae45eea6ad85faea121a389e468ea8"
"receiptsRoot": "0x640f4036d53782ca4c5e9273ba6d657db4f5ff4fe526a8ed1997af9d0b8ae2d3",
"blockHash": "0x61642311e6c1e0af50abf17be1fcb6de8bd75af2ca2d188031d074f6e71bf5e6"
},
"blockValue": "0x3581baab15c12e5",
"blockValue": "0x360b8482c4b509d",
"blobsBundle": {
"commitments": [],
"proofs": [],
"blobs": []
},
"shouldOverrideBuilder": false
"shouldOverrideBuilder": false,
"executionRequests": [
"0x",
"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f8706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf2430000000000000000",
"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
]
}
},
"statusCode": 200,

@ -68,20 +68,21 @@ dependencies {
implementation 'com.google.guava:guava'
implementation 'com.google.dagger:dagger'
implementation 'com.graphql-java:graphql-java'
implementation 'commons-net:commons-net'
implementation 'info.picocli:picocli'
implementation 'io.vertx:vertx-core'
implementation 'io.vertx:vertx-web'
implementation 'org.apache.commons:commons-lang3'
implementation 'org.apache.logging.log4j:log4j-core'
implementation 'io.tmio:tuweni-bytes'
implementation 'io.tmio:tuweni-config'
implementation 'io.tmio:tuweni-toml'
implementation 'io.tmio:tuweni-units'
implementation 'org.apache.commons:commons-lang3'
implementation 'org.apache.logging.log4j:log4j-core'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'org.rocksdb:rocksdbjni'
implementation 'org.springframework.security:spring-security-crypto'
implementation 'org.xerial.snappy:snappy-java'
implementation 'tech.pegasys:jc-kzg-4844'
implementation 'org.rocksdb:rocksdbjni'
implementation 'commons-net:commons-net'
runtimeOnly 'org.apache.logging.log4j:log4j-jul'
runtimeOnly 'com.splunk.logging:splunk-library-javalogging'
@ -103,7 +104,6 @@ dependencies {
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.testcontainers:testcontainers'
testImplementation 'tech.pegasys.discovery:discovery'
testImplementation 'com.google.dagger:dagger'

@ -20,11 +20,11 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hyperledger.besu.cli.DefaultCommandValues.getDefaultBesuDataPath;
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
import static org.hyperledger.besu.cli.config.NetworkName.MAINNET;
import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG;
import static org.hyperledger.besu.cli.util.CommandLineUtils.isOptionSet;
import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_ENGINE_JSON_RPC_PORT;
import static org.hyperledger.besu.ethereum.api.jsonrpc.authentication.EngineAuthService.EPHEMERAL_JWT_FILE;
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
@ -38,35 +38,36 @@ import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.cli.config.ProfilesCompletionCandidates;
import org.hyperledger.besu.cli.converter.MetricCategoryConverter;
import org.hyperledger.besu.cli.converter.PercentageConverter;
import org.hyperledger.besu.cli.converter.SubnetInfoConverter;
import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty;
import org.hyperledger.besu.cli.error.BesuExecutionExceptionHandler;
import org.hyperledger.besu.cli.error.BesuParameterExceptionHandler;
import org.hyperledger.besu.cli.options.MiningOptions;
import org.hyperledger.besu.cli.options.TransactionPoolOptions;
import org.hyperledger.besu.cli.options.stable.ApiConfigurationOptions;
import org.hyperledger.besu.cli.options.stable.DataStorageOptions;
import org.hyperledger.besu.cli.options.stable.EngineRPCConfiguration;
import org.hyperledger.besu.cli.options.stable.EngineRPCOptions;
import org.hyperledger.besu.cli.options.stable.EthstatsOptions;
import org.hyperledger.besu.cli.options.stable.GraphQlOptions;
import org.hyperledger.besu.cli.options.stable.JsonRpcHttpOptions;
import org.hyperledger.besu.cli.options.stable.LoggingLevelOption;
import org.hyperledger.besu.cli.options.stable.MetricsOptionGroup;
import org.hyperledger.besu.cli.options.stable.MetricsOptions;
import org.hyperledger.besu.cli.options.stable.NodePrivateKeyFileOption;
import org.hyperledger.besu.cli.options.stable.P2PTLSConfigOptions;
import org.hyperledger.besu.cli.options.stable.P2PDiscoveryOptions;
import org.hyperledger.besu.cli.options.stable.PermissionsOptions;
import org.hyperledger.besu.cli.options.stable.PluginsConfigurationOptions;
import org.hyperledger.besu.cli.options.stable.RpcWebsocketOptions;
import org.hyperledger.besu.cli.options.storage.DataStorageOptions;
import org.hyperledger.besu.cli.options.storage.DiffBasedSubStorageOptions;
import org.hyperledger.besu.cli.options.unstable.ChainPruningOptions;
import org.hyperledger.besu.cli.options.unstable.DnsOptions;
import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions;
import org.hyperledger.besu.cli.options.unstable.EvmOptions;
import org.hyperledger.besu.cli.options.unstable.InProcessRpcOptions;
import org.hyperledger.besu.cli.options.unstable.IpcOptions;
import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions;
import org.hyperledger.besu.cli.options.unstable.NatOptions;
import org.hyperledger.besu.cli.options.unstable.NativeLibraryOptions;
import org.hyperledger.besu.cli.options.unstable.NetworkingOptions;
import org.hyperledger.besu.cli.options.unstable.P2PTLSConfigOptions;
import org.hyperledger.besu.cli.options.unstable.PrivacyPluginOptions;
import org.hyperledger.besu.cli.options.unstable.RPCOptions;
import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions;
@ -89,7 +90,7 @@ import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.CheckpointConfigOptions;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.config.MergeConfiguration;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.controller.BesuControllerBuilder;
import org.hyperledger.besu.crypto.Blake2bfMessageDigest;
@ -124,6 +125,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolCo
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.mainnet.FrontierTargetingGasLimitCalculator;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.P2PDiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.p2p.peers.StaticNodesParser;
@ -138,7 +140,9 @@ 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.DiffBasedSubStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDiffBasedSubStorageConfiguration;
import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract;
import org.hyperledger.besu.evm.precompile.BigIntegerModularExponentiationPrecompiledContract;
import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract;
@ -195,6 +199,7 @@ import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl;
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin;
import org.hyperledger.besu.util.EphemeryGenesisUpdater;
import org.hyperledger.besu.util.InvalidConfigurationException;
import org.hyperledger.besu.util.LogConfigurator;
import org.hyperledger.besu.util.NetworkUtility;
@ -209,7 +214,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.URI;
import java.net.URL;
@ -246,8 +250,6 @@ import com.google.common.collect.ImmutableMap;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.json.DecodeException;
import io.vertx.core.metrics.MetricsOptions;
import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger;
@ -296,7 +298,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final NetworkingOptions unstableNetworkingOptions = NetworkingOptions.create();
final SynchronizerOptions unstableSynchronizerOptions = SynchronizerOptions.create();
final EthProtocolOptions unstableEthProtocolOptions = EthProtocolOptions.create();
final MetricsCLIOptions unstableMetricsCLIOptions = MetricsCLIOptions.create();
private final DnsOptions unstableDnsOptions = DnsOptions.create();
private final NatOptions unstableNatOptions = NatOptions.create();
private final NativeLibraryOptions unstableNativeLibraryOptions = NativeLibraryOptions.create();
@ -416,7 +417,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
// P2P Discovery Option Group
@CommandLine.ArgGroup(validate = false, heading = "@|bold P2P Discovery Options|@%n")
P2PDiscoveryOptionGroup p2PDiscoveryOptionGroup = new P2PDiscoveryOptionGroup();
P2PDiscoveryOptions p2PDiscoveryOptions = new P2PDiscoveryOptions();
P2PDiscoveryConfiguration p2PDiscoveryConfig;
private final TransactionSelectionServiceImpl transactionSelectionServiceImpl;
private final TransactionPoolValidatorServiceImpl transactionValidatorServiceImpl;
@ -424,163 +427,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private final BlockchainServiceImpl blockchainServiceImpl;
private BesuComponent besuComponent;
static class P2PDiscoveryOptionGroup {
// Public IP stored to prevent having to research it each time we need it.
private InetAddress autoDiscoveredDefaultIP = null;
// Completely disables P2P within Besu.
@Option(
names = {"--p2p-enabled"},
description = "Enable P2P functionality (default: ${DEFAULT-VALUE})",
arity = "1")
private final Boolean p2pEnabled = true;
// Boolean option to indicate if peers should NOT be discovered, default to
// false indicates that
// the peers should be discovered by default.
//
// This negative option is required because of the nature of the option that is
// true when
// added on the command line. You can't do --option=false, so false is set as
// default
// and you have not to set the option at all if you want it false.
// This seems to be the only way it works with Picocli.
// Also many other software use the same negative option scheme for false
// defaults
// meaning that it's probably the right way to handle disabling options.
@Option(
names = {"--discovery-enabled"},
description = "Enable P2P discovery (default: ${DEFAULT-VALUE})",
arity = "1")
private final Boolean peerDiscoveryEnabled = true;
// A list of bootstrap nodes can be passed
// and a hardcoded list will be used otherwise by the Runner.
// NOTE: we have no control over default value here.
@Option(
names = {"--bootnodes"},
paramLabel = "<enode://id@host:port>",
description =
"Comma separated enode URLs for P2P discovery bootstrap. "
+ "Default is a predefined list.",
split = ",",
arity = "0..*")
private final List<String> bootNodes = null;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@Option(
names = {"--p2p-host"},
paramLabel = MANDATORY_HOST_FORMAT_HELP,
description = "IP address this node advertises to its peers (default: ${DEFAULT-VALUE})",
arity = "1")
private String p2pHost = autoDiscoverDefaultIP().getHostAddress();
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@Option(
names = {"--p2p-interface"},
paramLabel = MANDATORY_HOST_FORMAT_HELP,
description =
"The network interface address on which this node listens for P2P communication (default: ${DEFAULT-VALUE})",
arity = "1")
private String p2pInterface = NetworkUtility.INADDR_ANY;
@Option(
names = {"--p2p-port"},
paramLabel = MANDATORY_PORT_FORMAT_HELP,
description = "Port on which to listen for P2P communication (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer p2pPort = EnodeURLImpl.DEFAULT_LISTENING_PORT;
@Option(
names = {"--max-peers", "--p2p-peer-upper-bound"},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description = "Maximum P2P connections that can be established (default: ${DEFAULT-VALUE})")
private final Integer maxPeers = DEFAULT_MAX_PEERS;
@Option(
names = {"--remote-connections-limit-enabled"},
description =
"Whether to limit the number of P2P connections initiated remotely. (default: ${DEFAULT-VALUE})")
private final Boolean isLimitRemoteWireConnectionsEnabled = true;
@Option(
names = {"--remote-connections-max-percentage"},
paramLabel = MANDATORY_DOUBLE_FORMAT_HELP,
description =
"The maximum percentage of P2P connections that can be initiated remotely. Must be between 0 and 100 inclusive. (default: ${DEFAULT-VALUE})",
arity = "1",
converter = PercentageConverter.class)
private final Percentage maxRemoteConnectionsPercentage =
Fraction.fromFloat(DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED).toPercentage();
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--discovery-dns-url"},
description = "Specifies the URL to use for DNS discovery")
private String discoveryDnsUrl = null;
@Option(
names = {"--random-peer-priority-enabled"},
description =
"Allow for incoming connections to be prioritized randomly. This will prevent (typically small, stable) networks from forming impenetrable peer cliques. (default: ${DEFAULT-VALUE})")
private final Boolean randomPeerPriority = Boolean.FALSE;
@Option(
names = {"--banned-node-ids", "--banned-node-id"},
paramLabel = MANDATORY_NODE_ID_FORMAT_HELP,
description = "A list of node IDs to ban from the P2P network.",
split = ",",
arity = "1..*")
void setBannedNodeIds(final List<String> values) {
try {
bannedNodeIds =
values.stream()
.filter(value -> !value.isEmpty())
.map(EnodeURLImpl::parseNodeId)
.collect(Collectors.toList());
} catch (final IllegalArgumentException e) {
throw new ParameterException(
new CommandLine(this),
"Invalid ids supplied to '--banned-node-ids'. " + e.getMessage());
}
}
// 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.
// Loopback IP is used by default as this is how smokeTests require it to be
// and it's probably a good security behaviour to default only on the localhost.
private InetAddress autoDiscoverDefaultIP() {
autoDiscoveredDefaultIP =
Optional.ofNullable(autoDiscoveredDefaultIP).orElseGet(InetAddress::getLoopbackAddress);
return autoDiscoveredDefaultIP;
}
@Option(
names = {"--net-restrict"},
arity = "1..*",
split = ",",
converter = SubnetInfoConverter.class,
description =
"Comma-separated list of allowed IP subnets (e.g., '192.168.1.0/24,10.0.0.0/8').")
private List<SubnetInfo> allowedSubnets;
}
@Option(
names = {"--sync-mode"},
paramLabel = MANDATORY_MODE_FORMAT_HELP,
@ -647,42 +493,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
// Engine JSON-PRC Options
@CommandLine.ArgGroup(validate = false, heading = "@|bold Engine JSON-RPC Options|@%n")
EngineRPCOptionGroup engineRPCOptionGroup = new EngineRPCOptionGroup();
EngineRPCOptions engineRPCOptions = new EngineRPCOptions();
static class EngineRPCOptionGroup {
@Option(
names = {"--engine-rpc-enabled"},
description =
"enable the engine api, even in the absence of merge-specific configurations.")
private final Boolean overrideEngineRpcEnabled = false;
@Option(
names = {"--engine-rpc-port", "--engine-rpc-http-port"},
paramLabel = MANDATORY_PORT_FORMAT_HELP,
description = "Port to provide consensus client APIS on (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer engineRpcPort = DEFAULT_ENGINE_JSON_RPC_PORT;
@Option(
names = {"--engine-jwt-secret"},
paramLabel = MANDATORY_FILE_FORMAT_HELP,
description = "Path to file containing shared secret key for JWT signature verification")
private final Path engineJwtKeyFile = null;
@Option(
names = {"--engine-jwt-disabled"},
description = "Disable authentication for Engine APIs (default: ${DEFAULT-VALUE})")
private final Boolean isEngineAuthDisabled = false;
@Option(
names = {"--engine-host-allowlist"},
paramLabel = "<hostname>[,<hostname>...]... or * or all",
description =
"Comma separated list of hostnames to allow for ENGINE API access (applies to both HTTP and websockets), or * to accept any host (default: ${DEFAULT-VALUE})",
defaultValue = "localhost,127.0.0.1")
private final JsonRPCAllowlistHostsProperty engineHostsAllowlist =
new JsonRPCAllowlistHostsProperty();
}
EngineRPCConfiguration engineRPCConfig = engineRPCOptions.toDomainObject();
// JSON-RPC HTTP Options
@CommandLine.ArgGroup(validate = false, heading = "@|bold JSON-RPC HTTP Options|@%n")
@ -773,7 +586,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
// Metrics Option Group
@CommandLine.ArgGroup(validate = false, heading = "@|bold Metrics Options|@%n")
MetricsOptionGroup metricsOptionGroup = new MetricsOptionGroup();
MetricsOptions metricsOptions = MetricsOptions.create();
@Option(
names = {"--host-allowlist"},
@ -1342,7 +1155,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final ImmutableMap<String, Object> unstableOptions =
unstableOptionsBuild
.put("Ethereum Wire Protocol", unstableEthProtocolOptions)
.put("Metrics", unstableMetricsCLIOptions)
.put("P2P Network", unstableNetworkingOptions)
.put("RPC", unstableRPCOptions)
.put("DNS Configuration", unstableDnsOptions)
@ -1409,13 +1221,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private Runner buildRunner() {
return synchronize(
besuController,
p2PDiscoveryOptionGroup.p2pEnabled,
p2PDiscoveryConfig.p2pEnabled(),
p2pTLSConfiguration,
p2PDiscoveryOptionGroup.peerDiscoveryEnabled,
p2PDiscoveryConfig.peerDiscoveryEnabled(),
ethNetworkConfig,
p2PDiscoveryOptionGroup.p2pHost,
p2PDiscoveryOptionGroup.p2pInterface,
p2PDiscoveryOptionGroup.p2pPort,
p2PDiscoveryConfig.p2pHost(),
p2PDiscoveryConfig.p2pInterface(),
p2PDiscoveryConfig.p2pPort(),
graphQLConfiguration,
jsonRpcConfiguration,
engineJsonRpcConfiguration,
@ -1598,7 +1410,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
if (genesisConfigOptionsSupplier.get().getCancunTime().isPresent()
|| genesisConfigOptionsSupplier.get().getCancunEOFTime().isPresent()
|| genesisConfigOptionsSupplier.get().getPragueTime().isPresent()
|| genesisConfigOptionsSupplier.get().getPragueEOFTime().isPresent()) {
|| genesisConfigOptionsSupplier.get().getOsakaTime().isPresent()) {
if (kzgTrustedSetupFile != null) {
KZGPointEvalPrecompiledContract.init(kzgTrustedSetupFile);
} else {
@ -1612,9 +1424,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private void validateOptions() {
validateRequiredOptions();
issueOptionWarnings();
validateP2PInterface(p2PDiscoveryOptionGroup.p2pInterface);
validateP2PInterface(p2PDiscoveryOptions.p2pInterface);
validateMiningParams();
validateNatParams();
validateNetStatsParams();
@ -1666,19 +1477,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
dataStorageOptions.validate(commandLine);
}
private void validateRequiredOptions() {
commandLine
.getCommandSpec()
.options()
.forEach(
option -> {
if (option.required() && option.stringValues().isEmpty()) {
throw new ParameterException(
this.commandLine, "Missing required option: " + option.longestName());
}
});
}
private void validateMiningParams() {
miningOptions.validate(
commandLine, genesisConfigOptionsSupplier.get(), isMergeEnabled(), logger);
@ -1750,13 +1548,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private void ensureValidPeerBoundParams() {
maxPeers = p2PDiscoveryOptionGroup.maxPeers;
maxPeers = p2PDiscoveryOptions.maxPeers;
final Boolean isLimitRemoteWireConnectionsEnabled =
p2PDiscoveryOptionGroup.isLimitRemoteWireConnectionsEnabled;
p2PDiscoveryOptions.isLimitRemoteWireConnectionsEnabled;
if (isLimitRemoteWireConnectionsEnabled) {
final float fraction =
Fraction.fromPercentage(p2PDiscoveryOptionGroup.maxRemoteConnectionsPercentage)
.getValue();
Fraction.fromPercentage(p2PDiscoveryOptions.maxRemoteConnectionsPercentage).getValue();
checkState(
fraction >= 0.0 && fraction <= 1.0,
"Fraction of remote connections allowed must be between 0.0 and 1.0 (inclusive).");
@ -1796,11 +1593,14 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private GenesisConfigFile readGenesisConfigFile() {
final GenesisConfigFile effectiveGenesisFile =
genesisFile != null
? GenesisConfigFile.fromSource(genesisConfigSource(genesisFile))
: GenesisConfigFile.fromResource(
Optional.ofNullable(network).orElse(MAINNET).getGenesisFile());
GenesisConfigFile effectiveGenesisFile;
effectiveGenesisFile =
network.equals(EPHEMERY)
? EphemeryGenesisUpdater.updateGenesis(genesisConfigOverrides)
: genesisFile != null
? GenesisConfigFile.fromSource(genesisConfigSource(genesisFile))
: GenesisConfigFile.fromResource(
Optional.ofNullable(network).orElse(MAINNET).getGenesisFile());
return effectiveGenesisFile.withOverrides(genesisConfigOverrides);
}
@ -1820,7 +1620,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
logger,
commandLine,
"--p2p-enabled",
!p2PDiscoveryOptionGroup.p2pEnabled,
!p2PDiscoveryOptions.p2pEnabled,
asList(
"--bootnodes",
"--discovery-enabled",
@ -1846,7 +1646,11 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
CommandLineUtils.failIfOptionDoesntMeetRequirement(
commandLine,
"--Xsnapsync-synchronizer-flat option can only be used when --Xbonsai-full-flat-db-enabled is true",
dataStorageOptions.toDomainObject().getUnstable().getBonsaiFullFlatDbEnabled(),
dataStorageOptions
.toDomainObject()
.getDiffBasedSubStorageConfiguration()
.getUnstable()
.getFullFlatDbEnabled(),
asList(
"--Xsnapsync-synchronizer-flat-account-healed-count-per-request",
"--Xsnapsync-synchronizer-flat-slot-healed-count-per-request"));
@ -1861,6 +1665,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private void configure() throws Exception {
p2PDiscoveryConfig = p2PDiscoveryOptions.toDomainObject();
engineRPCConfig = engineRPCOptions.toDomainObject();
checkPortClash();
checkIfRequiredPortsAreAvailable();
syncMode = getDefaultSyncModeIfNotSet();
@ -1870,25 +1676,18 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
jsonRpcConfiguration =
jsonRpcHttpOptions.jsonRpcConfiguration(
hostsAllowlist,
p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress(),
unstableRPCOptions.getHttpTimeoutSec());
hostsAllowlist, p2PDiscoveryOptions.p2pHost, unstableRPCOptions.getHttpTimeoutSec());
if (isEngineApiEnabled()) {
engineJsonRpcConfiguration =
createEngineJsonRpcConfiguration(
engineRPCOptionGroup.engineRpcPort, engineRPCOptionGroup.engineHostsAllowlist);
engineJsonRpcConfiguration = createEngineJsonRpcConfiguration();
}
p2pTLSConfiguration = p2pTLSConfigOptions.p2pTLSConfiguration(commandLine);
graphQLConfiguration =
graphQlOptions.graphQLConfiguration(
hostsAllowlist,
p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress(),
unstableRPCOptions.getHttpTimeoutSec());
hostsAllowlist, p2PDiscoveryOptions.p2pHost, unstableRPCOptions.getHttpTimeoutSec());
webSocketConfiguration =
rpcWebsocketOptions.webSocketConfiguration(
hostsAllowlist,
p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress(),
unstableRPCOptions.getWsTimeoutSec());
hostsAllowlist, p2PDiscoveryConfig.p2pHost(), unstableRPCOptions.getWsTimeoutSec());
jsonRpcIpcConfiguration =
jsonRpcIpcConfiguration(
unstableIpcOptions.isEnabled(),
@ -1983,57 +1782,64 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.withMiningParameters(miningParametersSupplier.get())
.withJsonRpcHttpOptions(jsonRpcHttpOptions);
final KeyValueStorageProvider storageProvider = keyValueStorageProvider(keyValueStorageName);
return controllerBuilder
.fromEthNetworkConfig(updateNetworkConfig(network), getDefaultSyncModeIfNotSet())
.synchronizerConfiguration(buildSyncConfig())
.ethProtocolConfiguration(unstableEthProtocolOptions.toDomainObject())
.networkConfiguration(unstableNetworkingOptions.toDomainObject())
.dataDirectory(dataDir())
.dataStorageConfiguration(getDataStorageConfiguration())
.miningParameters(miningParametersSupplier.get())
.transactionPoolConfiguration(buildTransactionPoolConfiguration())
.nodeKey(new NodeKey(securityModule()))
.metricsSystem((ObservableMetricsSystem) besuComponent.getMetricsSystem())
.messagePermissioningProviders(permissioningService.getMessagePermissioningProviders())
.privacyParameters(privacyParameters())
.clock(Clock.systemUTC())
.isRevertReasonEnabled(isRevertReasonEnabled)
.isParallelTxProcessingEnabled(
dataStorageConfiguration.getUnstable().isParallelTxProcessingEnabled())
.storageProvider(storageProvider)
.gasLimitCalculator(
miningParametersSupplier.get().getTargetGasLimit().isPresent()
? new FrontierTargetingGasLimitCalculator()
: GasLimitCalculator.constant())
.requiredBlocks(requiredBlocks)
.reorgLoggingThreshold(reorgLoggingThreshold)
.evmConfiguration(unstableEvmOptions.toDomainObject())
.maxPeers(p2PDiscoveryOptionGroup.maxPeers)
.maxRemotelyInitiatedPeers(maxRemoteInitiatedPeers)
.randomPeerPriority(p2PDiscoveryOptionGroup.randomPeerPriority)
.chainPruningConfiguration(unstableChainPruningOptions.toDomainObject())
.cacheLastBlocks(numberOfblocksToCache)
.genesisStateHashCacheEnabled(genesisStateHashCacheEnabled)
.besuComponent(besuComponent);
}
private JsonRpcConfiguration createEngineJsonRpcConfiguration(
final Integer engineListenPort, final List<String> allowCallsFrom) {
BesuControllerBuilder besuControllerBuilder =
controllerBuilder
.fromEthNetworkConfig(updateNetworkConfig(network), getDefaultSyncModeIfNotSet())
.synchronizerConfiguration(buildSyncConfig())
.ethProtocolConfiguration(unstableEthProtocolOptions.toDomainObject())
.networkConfiguration(unstableNetworkingOptions.toDomainObject())
.dataDirectory(dataDir())
.dataStorageConfiguration(getDataStorageConfiguration())
.miningParameters(miningParametersSupplier.get())
.transactionPoolConfiguration(buildTransactionPoolConfiguration())
.nodeKey(new NodeKey(securityModule()))
.metricsSystem((ObservableMetricsSystem) besuComponent.getMetricsSystem())
.messagePermissioningProviders(permissioningService.getMessagePermissioningProviders())
.privacyParameters(privacyParameters())
.clock(Clock.systemUTC())
.isRevertReasonEnabled(isRevertReasonEnabled)
.storageProvider(storageProvider)
.gasLimitCalculator(
miningParametersSupplier.get().getTargetGasLimit().isPresent()
? new FrontierTargetingGasLimitCalculator()
: GasLimitCalculator.constant())
.requiredBlocks(requiredBlocks)
.reorgLoggingThreshold(reorgLoggingThreshold)
.evmConfiguration(unstableEvmOptions.toDomainObject())
.maxPeers(p2PDiscoveryOptions.maxPeers)
.maxRemotelyInitiatedPeers(maxRemoteInitiatedPeers)
.randomPeerPriority(p2PDiscoveryOptions.randomPeerPriority)
.chainPruningConfiguration(unstableChainPruningOptions.toDomainObject())
.cacheLastBlocks(numberOfblocksToCache)
.genesisStateHashCacheEnabled(genesisStateHashCacheEnabled)
.besuComponent(besuComponent);
if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat())) {
final DiffBasedSubStorageConfiguration subStorageConfiguration =
getDataStorageConfiguration().getDiffBasedSubStorageConfiguration();
if (subStorageConfiguration.getLimitTrieLogsEnabled()) {
besuControllerBuilder.isParallelTxProcessingEnabled(
subStorageConfiguration.getUnstable().isParallelTxProcessingEnabled());
}
}
return besuControllerBuilder;
}
private JsonRpcConfiguration createEngineJsonRpcConfiguration() {
jsonRpcHttpOptions.checkDependencies(logger, commandLine);
final JsonRpcConfiguration engineConfig =
jsonRpcHttpOptions.jsonRpcConfiguration(
allowCallsFrom,
p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress(),
engineRPCConfig.engineHostsAllowlist(),
p2PDiscoveryConfig.p2pHost(),
unstableRPCOptions.getWsTimeoutSec());
engineConfig.setPort(engineListenPort);
engineConfig.setPort(engineRPCConfig.engineRpcPort());
engineConfig.setRpcApis(Arrays.asList("ENGINE", "ETH"));
engineConfig.setEnabled(isEngineApiEnabled());
if (!engineRPCOptionGroup.isEngineAuthDisabled) {
if (!engineRPCConfig.isEngineAuthDisabled()) {
engineConfig.setAuthenticationEnabled(true);
engineConfig.setAuthenticationAlgorithm(JwtAlgorithm.HS256);
if (Objects.nonNull(engineRPCOptionGroup.engineJwtKeyFile)
&& java.nio.file.Files.exists(engineRPCOptionGroup.engineJwtKeyFile)) {
engineConfig.setAuthenticationPublicKeyFile(engineRPCOptionGroup.engineJwtKeyFile.toFile());
if (Objects.nonNull(engineRPCConfig.engineJwtKeyFile())
&& java.nio.file.Files.exists(engineRPCConfig.engineJwtKeyFile())) {
engineConfig.setAuthenticationPublicKeyFile(engineRPCConfig.engineJwtKeyFile().toFile());
} else {
logger.warn(
"Engine API authentication enabled without key file. Expect ephemeral jwt.hex file in datadir");
@ -2060,7 +1866,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
* @return instance of MetricsConfiguration.
*/
public MetricsConfiguration metricsConfiguration() {
if (metricsOptionGroup.getMetricsEnabled() && metricsOptionGroup.getMetricsPushEnabled()) {
if (metricsOptions.getMetricsEnabled() && metricsOptions.getMetricsPushEnabled()) {
throw new ParameterException(
this.commandLine,
"--metrics-enabled option and --metrics-push-enabled option can't be used at the same "
@ -2071,40 +1877,33 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
logger,
commandLine,
"--metrics-enabled",
!metricsOptionGroup.getMetricsEnabled(),
!metricsOptions.getMetricsEnabled(),
asList("--metrics-host", "--metrics-port"));
CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
"--metrics-push-enabled",
!metricsOptionGroup.getMetricsPushEnabled(),
!metricsOptions.getMetricsPushEnabled(),
asList(
"--metrics-push-host",
"--metrics-push-port",
"--metrics-push-interval",
"--metrics-push-prometheus-job"));
return unstableMetricsCLIOptions
.toDomainObject()
.enabled(metricsOptionGroup.getMetricsEnabled())
final MetricsConfiguration.Builder metricsConfigurationBuilder =
metricsOptions.toDomainObject();
metricsConfigurationBuilder
.host(
Strings.isNullOrEmpty(metricsOptionGroup.getMetricsHost())
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
: metricsOptionGroup.getMetricsHost())
.port(metricsOptionGroup.getMetricsPort())
.protocol(metricsOptionGroup.getMetricsProtocol())
.metricCategories(metricsOptionGroup.getMetricCategories())
.pushEnabled(metricsOptionGroup.getMetricsPushEnabled())
Strings.isNullOrEmpty(metricsOptions.getMetricsHost())
? p2PDiscoveryOptions.p2pHost
: metricsOptions.getMetricsHost())
.pushHost(
Strings.isNullOrEmpty(metricsOptionGroup.getMetricsPushHost())
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
: metricsOptionGroup.getMetricsPushHost())
.pushPort(metricsOptionGroup.getMetricsPushPort())
.pushInterval(metricsOptionGroup.getMetricsPushInterval())
.hostsAllowlist(hostsAllowlist)
.prometheusJob(metricsOptionGroup.getMetricsPrometheusJob())
.build();
Strings.isNullOrEmpty(metricsOptions.getMetricsPushHost())
? p2PDiscoveryOptions.autoDiscoverDefaultIP().getHostAddress()
: metricsOptions.getMetricsPushHost())
.hostsAllowlist(hostsAllowlist);
return metricsConfigurationBuilder.build();
}
private PrivacyParameters privacyParameters() {
@ -2342,29 +2141,34 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
if (SyncMode.FULL.equals(getDefaultSyncModeIfNotSet())
&& DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())
&& dataStorageConfiguration.getBonsaiLimitTrieLogsEnabled()) {
&& DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())) {
final DiffBasedSubStorageConfiguration diffBasedSubStorageConfiguration =
dataStorageConfiguration.getDiffBasedSubStorageConfiguration();
if (diffBasedSubStorageConfiguration.getLimitTrieLogsEnabled()) {
if (CommandLineUtils.isOptionSet(
commandLine, DiffBasedSubStorageOptions.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",
DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED,
SyncMode.FULL,
DataStorageFormat.BONSAI,
DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED + "=false"));
}
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)
.withDiffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.copyOf(
dataStorageConfiguration.getDiffBasedSubStorageConfiguration())
.withLimitTrieLogsEnabled(false));
logger.warn(
"Forcing {}, since it cannot be enabled with --sync-mode={} and --data-storage-format={}.",
DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED + "=false",
SyncMode.FULL,
DataStorageFormat.BONSAI);
}
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;
}
@ -2441,7 +2245,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.apiConfiguration(apiConfiguration)
.pidPath(pidPath)
.dataDir(dataDir())
.bannedNodeIds(p2PDiscoveryOptionGroup.bannedNodeIds)
.bannedNodeIds(p2PDiscoveryConfig.bannedNodeIds())
.metricsSystem((ObservableMetricsSystem) besuComponent.getMetricsSystem())
.permissioningService(permissioningService)
.metricsConfiguration(metricsConfiguration)
@ -2453,8 +2257,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.storageProvider(keyValueStorageProvider(keyValueStorageName))
.rpcEndpointService(rpcEndpointServiceImpl)
.enodeDnsConfiguration(getEnodeDnsConfiguration())
.allowedSubnets(p2PDiscoveryOptionGroup.allowedSubnets)
.poaDiscoveryRetryBootnodes(p2PDiscoveryOptionGroup.poaDiscoveryRetryBootnodes)
.allowedSubnets(p2PDiscoveryConfig.allowedSubnets())
.poaDiscoveryRetryBootnodes(p2PDiscoveryConfig.poaDiscoveryRetryBootnodes())
.build();
addShutdownHook(runner);
@ -2477,7 +2281,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
return new VertxOptions()
.setPreferNativeTransport(true)
.setMetricsOptions(
new MetricsOptions()
new io.vertx.core.metrics.MetricsOptions()
.setEnabled(true)
.setFactory(new VertxMetricsAdapterFactory(metricsSystem)));
}
@ -2529,7 +2333,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
}
if (p2PDiscoveryOptionGroup.bootNodes == null) {
if (p2PDiscoveryOptions.bootNodes == null) {
builder.setBootNodes(new ArrayList<>());
}
builder.setDnsDiscoveryUrl(null);
@ -2540,9 +2344,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
if (networkId != null) {
builder.setNetworkId(networkId);
}
if (p2PDiscoveryOptionGroup.discoveryDnsUrl != null) {
builder.setDnsDiscoveryUrl(p2PDiscoveryOptionGroup.discoveryDnsUrl);
// ChainId update is required for Ephemery network
if (network.equals(EPHEMERY)) {
String chainId = genesisConfigOverrides.get("chainId");
builder.setNetworkId(new BigInteger(chainId));
}
if (p2PDiscoveryOptions.discoveryDnsUrl != null) {
builder.setDnsDiscoveryUrl(p2PDiscoveryOptions.discoveryDnsUrl);
} else {
final Optional<String> discoveryDnsUrlFromGenesis =
genesisConfigOptionsSupplier.get().getDiscoveryOptions().getDiscoveryDnsUrl();
@ -2550,9 +2358,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
List<EnodeURL> listBootNodes = null;
if (p2PDiscoveryOptionGroup.bootNodes != null) {
if (p2PDiscoveryOptions.bootNodes != null) {
try {
listBootNodes = buildEnodes(p2PDiscoveryOptionGroup.bootNodes, getEnodeDnsConfiguration());
listBootNodes = buildEnodes(p2PDiscoveryOptions.bootNodes, getEnodeDnsConfiguration());
} catch (final IllegalArgumentException e) {
throw new ParameterException(commandLine, e.getMessage());
}
@ -2564,7 +2372,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
}
if (listBootNodes != null) {
if (!p2PDiscoveryOptionGroup.peerDiscoveryEnabled) {
if (!p2PDiscoveryOptions.peerDiscoveryEnabled) {
logger.warn("Discovery disabled: bootnodes will be ignored.");
}
DiscoveryConfiguration.assertValidBootnodes(listBootNodes);
@ -2699,12 +2507,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.filter(port -> port > 0)
.forEach(
port -> {
if (port.equals(p2PDiscoveryOptionGroup.p2pPort)
if (port.equals(p2PDiscoveryConfig.p2pPort())
&& (NetworkUtility.isPortUnavailableForTcp(port)
|| NetworkUtility.isPortUnavailableForUdp(port))) {
unavailablePorts.add(port);
}
if (!port.equals(p2PDiscoveryOptionGroup.p2pPort)
if (!port.equals(p2PDiscoveryConfig.p2pPort())
&& NetworkUtility.isPortUnavailableForTcp(port)) {
unavailablePorts.add(port);
}
@ -2724,19 +2532,16 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
*/
private List<Integer> getEffectivePorts() {
final List<Integer> effectivePorts = new ArrayList<>();
addPortIfEnabled(
effectivePorts, p2PDiscoveryOptionGroup.p2pPort, p2PDiscoveryOptionGroup.p2pEnabled);
addPortIfEnabled(effectivePorts, p2PDiscoveryOptions.p2pPort, p2PDiscoveryOptions.p2pEnabled);
addPortIfEnabled(
effectivePorts, graphQlOptions.getGraphQLHttpPort(), graphQlOptions.isGraphQLHttpEnabled());
addPortIfEnabled(
effectivePorts, jsonRpcHttpOptions.getRpcHttpPort(), jsonRpcHttpOptions.isRpcHttpEnabled());
addPortIfEnabled(
effectivePorts, rpcWebsocketOptions.getRpcWsPort(), rpcWebsocketOptions.isRpcWsEnabled());
addPortIfEnabled(effectivePorts, engineRPCOptionGroup.engineRpcPort, isEngineApiEnabled());
addPortIfEnabled(effectivePorts, engineRPCConfig.engineRpcPort(), isEngineApiEnabled());
addPortIfEnabled(
effectivePorts,
metricsOptionGroup.getMetricsPort(),
metricsOptionGroup.getMetricsEnabled());
effectivePorts, metricsOptions.getMetricsPort(), metricsOptions.getMetricsEnabled());
addPortIfEnabled(
effectivePorts,
miningParametersSupplier.get().getStratumPort(),
@ -2810,7 +2615,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private void setMergeConfigOptions() {
MergeConfigOptions.setMergeEnabled(
MergeConfiguration.setMergeEnabled(
genesisConfigOptionsSupplier.get().getTerminalTotalDifficulty().isPresent());
}
@ -2855,11 +2660,11 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private boolean isMergeEnabled() {
return MergeConfigOptions.isMergeEnabled();
return MergeConfiguration.isMergeEnabled();
}
private boolean isEngineApiEnabled() {
return engineRPCOptionGroup.overrideEngineRpcEnabled || isMergeEnabled();
return engineRPCConfig.overrideEngineRpcEnabled() || isMergeEnabled();
}
private SyncMode getDefaultSyncModeIfNotSet() {
@ -2902,7 +2707,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
builder
.setDataStorage(dataStorageOptions.normalizeDataStorageFormat())
.setSyncMode(syncMode.normalize());
.setSyncMode(syncMode.normalize())
.setSyncMinPeers(syncMinPeerCount);
if (jsonRpcConfiguration != null && jsonRpcConfiguration.isEnabled()) {
builder
@ -2929,12 +2735,14 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
builder.setHighSpecEnabled();
}
if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat())
&& getDataStorageConfiguration().getBonsaiLimitTrieLogsEnabled()) {
builder.setLimitTrieLogsEnabled();
builder.setTrieLogRetentionLimit(getDataStorageConfiguration().getBonsaiMaxLayersToLoad());
builder.setTrieLogsPruningWindowSize(
getDataStorageConfiguration().getBonsaiTrieLogPruningWindowSize());
if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat())) {
final DiffBasedSubStorageConfiguration subStorageConfiguration =
getDataStorageConfiguration().getDiffBasedSubStorageConfiguration();
if (subStorageConfiguration.getLimitTrieLogsEnabled()) {
builder.setLimitTrieLogsEnabled();
builder.setTrieLogRetentionLimit(subStorageConfiguration.getMaxLayersToLoad());
builder.setTrieLogsPruningWindowSize(subStorageConfiguration.getTrieLogPruningWindowSize());
}
}
builder.setSnapServerEnabled(this.unstableSynchronizerOptions.isSnapsyncServerEnabled());
@ -2949,11 +2757,20 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
/**
* Returns the plugin context.
* 2 Returns the plugin context.
*
* @return the plugin context.
*/
public BesuPluginContextImpl getBesuPluginContext() {
return besuPluginContext;
}
/**
* Returns the metrics options
*
* @return the metrics options
*/
public MetricsOptions getMetricsOptions() {
return metricsOptions;
}
}

@ -46,13 +46,14 @@ public class ConfigurationOverviewBuilder {
private String customGenesisFileName;
private String dataStorage;
private String syncMode;
private Integer syncMinPeers;
private Integer rpcPort;
private Collection<String> rpcHttpApis;
private Integer enginePort;
private Collection<String> engineApis;
private String engineJwtFilePath;
private boolean isHighSpec = false;
private boolean isBonsaiLimitTrieLogsEnabled = false;
private boolean isLimitTrieLogsEnabled = false;
private long trieLogRetentionLimit = 0;
private Integer trieLogsPruningWindowSize = null;
private boolean isSnapServerEnabled = false;
@ -148,6 +149,17 @@ public class ConfigurationOverviewBuilder {
return this;
}
/**
* Sets sync min peers.
*
* @param syncMinPeers number of min peers for sync
* @return the builder
*/
public ConfigurationOverviewBuilder setSyncMinPeers(final int syncMinPeers) {
this.syncMinPeers = syncMinPeers;
return this;
}
/**
* Sets rpc port.
*
@ -208,7 +220,7 @@ public class ConfigurationOverviewBuilder {
* @return the builder
*/
public ConfigurationOverviewBuilder setLimitTrieLogsEnabled() {
isBonsaiLimitTrieLogsEnabled = true;
isLimitTrieLogsEnabled = true;
return this;
}
@ -340,6 +352,10 @@ public class ConfigurationOverviewBuilder {
lines.add("Sync mode: " + syncMode);
}
if (syncMinPeers != null) {
lines.add("Sync min peers: " + syncMinPeers);
}
if (rpcHttpApis != null) {
lines.add("RPC HTTP APIs: " + String.join(",", rpcHttpApis));
}
@ -373,7 +389,7 @@ public class ConfigurationOverviewBuilder {
lines.add("Experimental Snap Sync for BFT enabled");
}
if (isBonsaiLimitTrieLogsEnabled) {
if (isLimitTrieLogsEnabled) {
final StringBuilder trieLogPruningString = new StringBuilder();
trieLogPruningString
.append("Limit trie logs enabled: retention: ")

@ -77,6 +77,7 @@ public record EthNetworkConfig(
strings ->
strings.stream().map(EnodeURLImpl::fromString).collect(Collectors.toList()))
.orElse(Collections.emptyList());
return new EthNetworkConfig(
genesisConfigFile,
networkName.getNetworkId(),

@ -32,6 +32,12 @@ public enum NetworkName {
/** LUKSO mainnet network name. */
LUKSO("/lukso.json", BigInteger.valueOf(42)),
/**
* EPHEMERY network name. The actual networkId used is calculated based on this default value and
* the current time. https://ephemery.dev/
*/
EPHEMERY("/ephemery.json", BigInteger.valueOf(39438135)),
/** Verkle testnet */
KAUSTINEN("/kaustinen.json", BigInteger.valueOf(69420)),

@ -28,6 +28,7 @@ import picocli.CommandLine;
* Handles configuration options for the API in Besu, including gas price settings, RPC log range,
* and trace filter range.
*/
// TODO: implement CLIOption<ApiConfiguration>
public class ApiConfigurationOptions {
/** Default constructor. */
public ApiConfigurationOptions() {}

@ -1,249 +0,0 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_LIMIT_TRIE_LOGS_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_RECEIPT_COMPACTION_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.DEFAULT_BONSAI_CODE_USING_CODE_HASH_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.DEFAULT_BONSAI_FULL_FLAT_DB_ENABLED;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import picocli.CommandLine;
import picocli.CommandLine.Option;
/** The Data storage CLI options. */
public class DataStorageOptions implements CLIOptions<DataStorageConfiguration> {
private static final String DATA_STORAGE_FORMAT = "--data-storage-format";
/** The maximum number of historical layers to load. */
public static final String BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD =
"--bonsai-historical-block-limit";
// Use Bonsai DB
@Option(
names = {DATA_STORAGE_FORMAT},
description =
"Format to store trie data in. Either FOREST or BONSAI (default: ${DEFAULT-VALUE}).",
arity = "1")
private DataStorageFormat dataStorageFormat = DataStorageFormat.BONSAI;
@Option(
names = {BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD, "--bonsai-maximum-back-layers-to-load"},
paramLabel = "<LONG>",
description =
"Limit of historical layers that can be loaded with BONSAI (default: ${DEFAULT-VALUE}). When using "
+ BONSAI_LIMIT_TRIE_LOGS_ENABLED
+ " it will also be used as the number of layers of trie logs to retain.",
arity = "1")
private Long bonsaiMaxLayersToLoad = DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD;
/** 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 =
"--bonsai-trie-logs-pruning-window-size";
// TODO --Xbonsai-limit-trie-logs-enabled and --Xbonsai-trie-log-pruning-enabled are deprecated,
// remove in a future release
@SuppressWarnings("ExperimentalCliOptionMustBeCorrectlyDisplayed")
@CommandLine.Option(
names = {
BONSAI_LIMIT_TRIE_LOGS_ENABLED,
"--Xbonsai-limit-trie-logs-enabled", // deprecated
"--Xbonsai-trie-log-pruning-enabled" // deprecated
},
fallbackValue = "true",
description = "Limit the number of trie logs that are retained. (default: ${DEFAULT-VALUE})")
private Boolean bonsaiLimitTrieLogsEnabled = DEFAULT_BONSAI_LIMIT_TRIE_LOGS_ENABLED;
// TODO --Xbonsai-trie-logs-pruning-window-size is deprecated, remove in a future release
@SuppressWarnings("ExperimentalCliOptionMustBeCorrectlyDisplayed")
@CommandLine.Option(
names = {
BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE,
"--Xbonsai-trie-logs-pruning-window-size" // deprecated
},
description =
"The max number of blocks to load and prune trie logs for at startup. (default: ${DEFAULT-VALUE})")
private Integer bonsaiTrieLogPruningWindowSize = DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE;
@Option(
names = "--receipt-compaction-enabled",
description = "Enables compact storing of receipts (default: ${DEFAULT-VALUE})",
fallbackValue = "true")
private Boolean receiptCompactionEnabled = DEFAULT_RECEIPT_COMPACTION_ENABLED;
@CommandLine.ArgGroup(validate = false)
private final DataStorageOptions.Unstable unstableOptions = new Unstable();
/** Default Constructor. */
DataStorageOptions() {}
/** The unstable options for data storage. */
public static class Unstable {
// TODO: --Xsnapsync-synchronizer-flat-db-healing-enabled is deprecated, remove it in a future
// release
@CommandLine.Option(
hidden = true,
names = {
"--Xbonsai-full-flat-db-enabled",
"--Xsnapsync-synchronizer-flat-db-healing-enabled"
},
arity = "1",
description = "Enables bonsai full flat database strategy. (default: ${DEFAULT-VALUE})")
private Boolean bonsaiFullFlatDbEnabled = DEFAULT_BONSAI_FULL_FLAT_DB_ENABLED;
@CommandLine.Option(
hidden = true,
names = {"--Xbonsai-code-using-code-hash-enabled"},
arity = "1",
description =
"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() {}
}
/**
* Create data storage options.
*
* @return the data storage options
*/
public static DataStorageOptions create() {
return new DataStorageOptions();
}
/**
* Validates the data storage options
*
* @param commandLine the full commandLine to check all the options specified by the user
*/
public void validate(final CommandLine commandLine) {
if (DataStorageFormat.BONSAI == dataStorageFormat) {
if (bonsaiLimitTrieLogsEnabled) {
if (bonsaiMaxLayersToLoad < MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD + " minimum value is %d",
MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT));
}
if (bonsaiTrieLogPruningWindowSize <= 0) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than 0",
bonsaiTrieLogPruningWindowSize));
}
if (bonsaiTrieLogPruningWindowSize <= bonsaiMaxLayersToLoad) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE
+ "=%d must be greater than "
+ BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD
+ "=%d",
bonsaiTrieLogPruningWindowSize,
bonsaiMaxLayersToLoad));
}
}
} else {
if (unstableOptions.isParallelTxProcessingEnabled) {
throw new CommandLine.ParameterException(
commandLine,
"Transaction parallelization is not supported unless operating in a 'diffbased' mode, such as Bonsai.");
}
}
}
/**
* Converts to options from the configuration
*
* @param domainObject to be reversed
* @return the options that correspond to the configuration
*/
public static DataStorageOptions fromConfig(final DataStorageConfiguration domainObject) {
final DataStorageOptions dataStorageOptions = DataStorageOptions.create();
dataStorageOptions.dataStorageFormat = domainObject.getDataStorageFormat();
dataStorageOptions.bonsaiMaxLayersToLoad = domainObject.getBonsaiMaxLayersToLoad();
dataStorageOptions.receiptCompactionEnabled = domainObject.getReceiptCompactionEnabled();
dataStorageOptions.bonsaiLimitTrieLogsEnabled = domainObject.getBonsaiLimitTrieLogsEnabled();
dataStorageOptions.bonsaiTrieLogPruningWindowSize =
domainObject.getBonsaiTrieLogPruningWindowSize();
dataStorageOptions.unstableOptions.bonsaiFullFlatDbEnabled =
domainObject.getUnstable().getBonsaiFullFlatDbEnabled();
dataStorageOptions.unstableOptions.bonsaiCodeUsingCodeHashEnabled =
domainObject.getUnstable().getBonsaiCodeStoredByCodeHashEnabled();
dataStorageOptions.unstableOptions.isParallelTxProcessingEnabled =
domainObject.getUnstable().isParallelTxProcessingEnabled();
return dataStorageOptions;
}
@Override
public DataStorageConfiguration toDomainObject() {
return ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(dataStorageFormat)
.bonsaiMaxLayersToLoad(bonsaiMaxLayersToLoad)
.receiptCompactionEnabled(receiptCompactionEnabled)
.bonsaiLimitTrieLogsEnabled(bonsaiLimitTrieLogsEnabled)
.bonsaiTrieLogPruningWindowSize(bonsaiTrieLogPruningWindowSize)
.unstable(
ImmutableDataStorageConfiguration.Unstable.builder()
.bonsaiFullFlatDbEnabled(unstableOptions.bonsaiFullFlatDbEnabled)
.bonsaiCodeStoredByCodeHashEnabled(unstableOptions.bonsaiCodeUsingCodeHashEnabled)
.isParallelTxProcessingEnabled(unstableOptions.isParallelTxProcessingEnabled)
.build())
.build();
}
@Override
public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new DataStorageOptions());
}
/**
* Normalize data storage format string.
*
* @return the normalized string
*/
public String normalizeDataStorageFormat() {
return StringUtils.capitalize(dataStorageFormat.toString().toLowerCase(Locale.ROOT));
}
}

@ -0,0 +1,36 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty;
import java.nio.file.Path;
/**
* Command line options for configuring Engine RPC on the node.
*
* @param overrideEngineRpcEnabled enable the engine api, even in the absence of merge-specific
* configurations.
* @param engineRpcPort Port to provide consensus client APIS on
* @param engineJwtKeyFile Path to file containing shared secret key for JWT signature verification
* @param isEngineAuthDisabled Disable authentication for Engine APIs
* @param engineHostsAllowlist List of hosts to allowlist for Engine APIs
*/
public record EngineRPCConfiguration(
Boolean overrideEngineRpcEnabled,
Integer engineRpcPort,
Path engineJwtKeyFile,
Boolean isEngineAuthDisabled,
JsonRPCAllowlistHostsProperty engineHostsAllowlist) {}

@ -0,0 +1,81 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_ENGINE_JSON_RPC_PORT;
import org.hyperledger.besu.cli.DefaultCommandValues;
import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import java.nio.file.Path;
import java.util.List;
import picocli.CommandLine;
/** Command line options for configuring Engine RPC on the node. */
public class EngineRPCOptions implements CLIOptions<EngineRPCConfiguration> {
/** Default constructor */
public EngineRPCOptions() {}
@CommandLine.Option(
names = {"--engine-rpc-enabled"},
description = "enable the engine api, even in the absence of merge-specific configurations.")
private final Boolean overrideEngineRpcEnabled = false;
@CommandLine.Option(
names = {"--engine-rpc-port", "--engine-rpc-http-port"},
paramLabel = DefaultCommandValues.MANDATORY_PORT_FORMAT_HELP,
description = "Port to provide consensus client APIS on (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer engineRpcPort = DEFAULT_ENGINE_JSON_RPC_PORT;
@CommandLine.Option(
names = {"--engine-jwt-secret"},
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP,
description = "Path to file containing shared secret key for JWT signature verification")
private final Path engineJwtKeyFile = null;
@CommandLine.Option(
names = {"--engine-jwt-disabled"},
description = "Disable authentication for Engine APIs (default: ${DEFAULT-VALUE})")
private final Boolean isEngineAuthDisabled = false;
@CommandLine.Option(
names = {"--engine-host-allowlist"},
paramLabel = "<hostname>[,<hostname>...]... or * or all",
description =
"Comma separated list of hostnames to allow for ENGINE API access (applies to both HTTP and websockets), or * to accept any host (default: ${DEFAULT-VALUE})",
defaultValue = "localhost,127.0.0.1")
private final JsonRPCAllowlistHostsProperty engineHostsAllowlist =
new JsonRPCAllowlistHostsProperty();
@Override
public EngineRPCConfiguration toDomainObject() {
return new EngineRPCConfiguration(
overrideEngineRpcEnabled,
engineRpcPort,
engineJwtKeyFile,
isEngineAuthDisabled,
engineHostsAllowlist);
}
@Override
public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new EngineRPCOptions());
}
}

@ -29,6 +29,7 @@ import org.slf4j.Logger;
import picocli.CommandLine;
/** Handles configuration options for the GraphQL HTTP service in Besu. */
// TODO: implement CLIOptions<GraphQLConfiguration>
public class GraphQlOptions {
@CommandLine.Option(
names = {"--graphql-http-enabled"},

@ -15,6 +15,7 @@
package org.hyperledger.besu.cli.options.stable;
import static java.util.Arrays.asList;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_JSON_RPC_HOST;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_JSON_RPC_PORT;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_PRETTY_JSON_ENABLED;
import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.DEFAULT_RPC_APIS;
@ -52,6 +53,7 @@ import picocli.CommandLine;
* Handles configuration options for the JSON-RPC HTTP service, including validation and creation of
* a JSON-RPC configuration.
*/
// TODO: implement CLIOption<JsonRpcConfiguration>
public class JsonRpcHttpOptions {
@CommandLine.Option(
names = {"--rpc-http-enabled"},
@ -64,7 +66,7 @@ public class JsonRpcHttpOptions {
paramLabel = DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP,
description = "Host for JSON-RPC HTTP to listen on (default: ${DEFAULT-VALUE})",
arity = "1")
private String rpcHttpHost;
private String rpcHttpHost = DEFAULT_JSON_RPC_HOST;
@CommandLine.Option(
names = {"--rpc-http-port"},
@ -265,37 +267,50 @@ public class JsonRpcHttpOptions {
/**
* Creates a JsonRpcConfiguration based on the provided options.
*
* @param hostsAllowlist List of hosts allowed
* @param defaultHostAddress Default host address
* @param timoutSec timeout in seconds
* @return A JsonRpcConfiguration instance
* @return configuration populated from options or defaults
*/
public JsonRpcConfiguration jsonRpcConfiguration(
final List<String> hostsAllowlist, final String defaultHostAddress, final Long timoutSec) {
public JsonRpcConfiguration jsonRpcConfiguration() {
final JsonRpcConfiguration jsonRpcConfiguration = JsonRpcConfiguration.createDefault();
jsonRpcConfiguration.setEnabled(isRpcHttpEnabled);
jsonRpcConfiguration.setHost(
Strings.isNullOrEmpty(rpcHttpHost) ? defaultHostAddress : rpcHttpHost);
jsonRpcConfiguration.setPort(rpcHttpPort);
jsonRpcConfiguration.setMaxActiveConnections(rpcHttpMaxConnections);
jsonRpcConfiguration.setCorsAllowedDomains(rpcHttpCorsAllowedOrigins);
jsonRpcConfiguration.setRpcApis(rpcHttpApis.stream().distinct().collect(Collectors.toList()));
jsonRpcConfiguration.setNoAuthRpcApis(
rpcHttpApiMethodsNoAuth.stream().distinct().collect(Collectors.toList()));
jsonRpcConfiguration.setHostsAllowlist(hostsAllowlist);
jsonRpcConfiguration.setAuthenticationEnabled(isRpcHttpAuthenticationEnabled);
jsonRpcConfiguration.setAuthenticationCredentialsFile(rpcHttpAuthenticationCredentialsFile);
jsonRpcConfiguration.setAuthenticationPublicKeyFile(rpcHttpAuthenticationPublicKeyFile);
jsonRpcConfiguration.setAuthenticationAlgorithm(rpcHttpAuthenticationAlgorithm);
jsonRpcConfiguration.setTlsConfiguration(rpcHttpTlsConfiguration());
jsonRpcConfiguration.setHttpTimeoutSec(timoutSec);
jsonRpcConfiguration.setMaxBatchSize(rpcHttpMaxBatchSize);
jsonRpcConfiguration.setMaxRequestContentLength(rpcHttpMaxRequestContentLength);
jsonRpcConfiguration.setPrettyJsonEnabled(prettyJsonEnabled);
return jsonRpcConfiguration;
}
/**
* Creates a JsonRpcConfiguration based on the provided options.
*
* @param hostsAllowlist List of hosts allowed
* @param defaultHostAddress Default host address
* @param timoutSec timeout in seconds
* @return A JsonRpcConfiguration instance
*/
public JsonRpcConfiguration jsonRpcConfiguration(
final List<String> hostsAllowlist, final String defaultHostAddress, final Long timoutSec) {
final JsonRpcConfiguration jsonRpcConfiguration = this.jsonRpcConfiguration();
jsonRpcConfiguration.setHost(
Strings.isNullOrEmpty(rpcHttpHost) ? defaultHostAddress : rpcHttpHost);
jsonRpcConfiguration.setHostsAllowlist(hostsAllowlist);
;
jsonRpcConfiguration.setHttpTimeoutSec(timoutSec);
return jsonRpcConfiguration;
}
/**
* Checks dependencies between options.
*

@ -22,19 +22,80 @@ import static org.hyperledger.besu.metrics.MetricsProtocol.PROMETHEUS;
import static org.hyperledger.besu.metrics.prometheus.MetricsConfiguration.DEFAULT_METRICS_PORT;
import static org.hyperledger.besu.metrics.prometheus.MetricsConfiguration.DEFAULT_METRICS_PUSH_PORT;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.metrics.MetricsProtocol;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
import java.util.List;
import java.util.Set;
import picocli.CommandLine;
/** Command line options for configuring metrics. */
public class MetricsOptionGroup {
// TODO: implement CLIOption<MetricsConfiguration>
public class MetricsOptions implements CLIOptions<MetricsConfiguration.Builder> {
/**
* Returns a MetricsConfiguration.Builder because fields are often overridden from other domains,
* like using P2P settings as defaults.
*
* @return a newly created {@link MetricsOptions} with default values
*/
@Override
public MetricsConfiguration.Builder toDomainObject() {
MetricsConfiguration.Builder builder = MetricsConfiguration.builder();
builder
.timersEnabled(unstableOptions.timersEnabled)
.idleTimeout(unstableOptions.idleTimeout)
.enabled(getMetricsEnabled())
.host(getMetricsHost())
.port(getMetricsPort())
.protocol(getMetricsProtocol())
.metricCategories(getMetricCategories())
.pushEnabled(getMetricsPushEnabled())
.pushHost(getMetricsPushHost())
.pushPort(getMetricsPushPort())
.pushInterval(getMetricsPushInterval())
.prometheusJob(getMetricsPrometheusJob());
return builder;
}
// TODO: why do we need to be able to reverse this?
/**
* Returns a newly created {@link MetricsOptions} reversed from the supplied MetricsConfiguration
*
* @param config the metrics configuration
* @return a newly created {@link MetricsOptions} reversed from the supplied MetricsConfiguration
*/
public static MetricsOptions fromConfiguration(final MetricsConfiguration config) {
final MetricsOptions metricsOptions = create();
metricsOptions.unstableOptions.timersEnabled = config.isTimersEnabled();
metricsOptions.unstableOptions.idleTimeout = config.getIdleTimeout();
metricsOptions.isMetricsEnabled = config.isEnabled();
metricsOptions.metricsHost = config.getHost();
metricsOptions.metricsPort = config.getPort();
metricsOptions.metricsProtocol = config.getProtocol();
metricsOptions.metricCategories = config.getMetricCategories();
metricsOptions.metricsPrometheusJob = config.getPrometheusJob();
metricsOptions.isMetricsPushEnabled = config.isPushEnabled();
metricsOptions.metricsPushHost = config.getPushHost();
metricsOptions.metricsPushPort = config.getPushPort();
metricsOptions.metricsPushInterval = config.getPushInterval();
return metricsOptions;
}
@Override
public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new MetricsOptions());
}
@CommandLine.Option(
names = {"--metrics-enabled"},
description = "Set to start the metrics exporter (default: ${DEFAULT-VALUE})")
private final Boolean isMetricsEnabled = false;
private Boolean isMetricsEnabled = false;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
@ -49,14 +110,14 @@ public class MetricsOptionGroup {
paramLabel = MANDATORY_HOST_FORMAT_HELP,
description = "Host for the metrics exporter to listen on (default: ${DEFAULT-VALUE})",
arity = "1")
private String metricsHost;
private String metricsHost = MetricsConfiguration.DEFAULT_METRICS_HOST;
@CommandLine.Option(
names = {"--metrics-port"},
paramLabel = MANDATORY_PORT_FORMAT_HELP,
description = "Port for the metrics exporter to listen on (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer metricsPort = DEFAULT_METRICS_PORT;
private Integer metricsPort = DEFAULT_METRICS_PORT;
@CommandLine.Option(
names = {"--metrics-category", "--metrics-categories"},
@ -65,12 +126,12 @@ public class MetricsOptionGroup {
arity = "1..*",
description =
"Comma separated list of categories to track metrics for (default: ${DEFAULT-VALUE})")
private final Set<MetricCategory> metricCategories = DEFAULT_METRIC_CATEGORIES;
private Set<MetricCategory> metricCategories = DEFAULT_METRIC_CATEGORIES;
@CommandLine.Option(
names = {"--metrics-push-enabled"},
description = "Enable the metrics push gateway integration (default: ${DEFAULT-VALUE})")
private final Boolean isMetricsPushEnabled = false;
private Boolean isMetricsPushEnabled = false;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
@ -78,14 +139,14 @@ public class MetricsOptionGroup {
paramLabel = MANDATORY_HOST_FORMAT_HELP,
description = "Host of the Prometheus Push Gateway for push mode (default: ${DEFAULT-VALUE})",
arity = "1")
private String metricsPushHost;
private String metricsPushHost = MetricsConfiguration.DEFAULT_METRICS_PUSH_HOST;
@CommandLine.Option(
names = {"--metrics-push-port"},
paramLabel = MANDATORY_PORT_FORMAT_HELP,
description = "Port of the Prometheus Push Gateway for push mode (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer metricsPushPort = DEFAULT_METRICS_PUSH_PORT;
private Integer metricsPushPort = DEFAULT_METRICS_PUSH_PORT;
@CommandLine.Option(
names = {"--metrics-push-interval"},
@ -93,7 +154,7 @@ public class MetricsOptionGroup {
description =
"Interval in seconds to push metrics when in push mode (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer metricsPushInterval = 15;
private Integer metricsPushInterval = 15;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
@ -102,8 +163,16 @@ public class MetricsOptionGroup {
arity = "1")
private String metricsPrometheusJob = "besu-client";
/** Returns a newly created {@link MetricsOptionGroup} with default values. */
public MetricsOptionGroup() {}
/**
* Returns a newly created {@link MetricsOptions} with default values.
*
* @return new instance
*/
public static MetricsOptions create() {
return new MetricsOptions();
}
private MetricsOptions() {}
/**
* Returns whether metrics are enabled.
@ -194,4 +263,26 @@ public class MetricsOptionGroup {
public String getMetricsPrometheusJob() {
return metricsPrometheusJob;
}
@CommandLine.ArgGroup(validate = false)
private final MetricsOptions.Unstable unstableOptions = new MetricsOptions.Unstable();
static class Unstable {
private static final String TIMERS_ENABLED_FLAG = "--Xmetrics-timers-enabled";
private static final String IDLE_TIMEOUT_FLAG = "--Xmetrics-idle-timeout";
@CommandLine.Option(
names = TIMERS_ENABLED_FLAG,
hidden = true,
description = "Whether to enable timer metrics (default: ${DEFAULT-VALUE}).")
private Boolean timersEnabled = MetricsConfiguration.DEFAULT_METRICS_TIMERS_ENABLED;
@CommandLine.Option(
hidden = true,
names = {IDLE_TIMEOUT_FLAG},
paramLabel = "<INTEGER>",
description = "Timeout for metrics TCP connections, in seconds (default: ${DEFAULT-VALUE})",
arity = "1")
private int idleTimeout = MetricsConfiguration.DEFAULT_METRICS_IDLE_TIMEOUT_SECONDS;
}
}

@ -0,0 +1,225 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
import org.hyperledger.besu.cli.DefaultCommandValues;
import org.hyperledger.besu.cli.converter.PercentageConverter;
import org.hyperledger.besu.cli.converter.SubnetInfoConverter;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.p2p.discovery.P2PDiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.util.NetworkUtility;
import org.hyperledger.besu.util.number.Fraction;
import org.hyperledger.besu.util.number.Percentage;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.net.util.SubnetUtils;
import org.apache.tuweni.bytes.Bytes;
import picocli.CommandLine;
/** Command line options for configuring P2P discovery on the node. */
public class P2PDiscoveryOptions implements CLIOptions<P2PDiscoveryConfiguration> {
/** Default constructor */
public P2PDiscoveryOptions() {}
// Public IP stored to prevent having to research it each time we need it.
private InetAddress autoDiscoveredDefaultIP = null;
/** Completely disables P2P within Besu. */
@CommandLine.Option(
names = {"--p2p-enabled"},
description = "Enable P2P functionality (default: ${DEFAULT-VALUE})",
arity = "1")
public final Boolean p2pEnabled = true;
/** Boolean option to indicate if peers should be discovered. */
@CommandLine.Option(
names = {"--discovery-enabled"},
description = "Enable P2P discovery (default: ${DEFAULT-VALUE})",
arity = "1")
public final Boolean peerDiscoveryEnabled = true;
/**
* A list of bootstrap nodes can be passed and a hardcoded list will be used otherwise by the
* Runner.
*/
// NOTE: we have no control over default value here.
@CommandLine.Option(
names = {"--bootnodes"},
paramLabel = "<enode://id@host:port>",
description =
"Comma separated enode URLs for P2P discovery bootstrap. "
+ "Default is a predefined list.",
split = ",",
arity = "0..*")
public final List<String> bootNodes = null;
/** The IP the node advertises to peers for P2P communication. */
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--p2p-host"},
paramLabel = DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP,
description = "IP address this node advertises to its peers (default: ${DEFAULT-VALUE})",
arity = "1")
public String p2pHost = autoDiscoverDefaultIP().getHostAddress();
/** The network interface address on which this node listens for P2P communication. */
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--p2p-interface"},
paramLabel = DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP,
description =
"The network interface address on which this node listens for P2P communication (default: ${DEFAULT-VALUE})",
arity = "1")
public String p2pInterface = NetworkUtility.INADDR_ANY;
/** The port on which this node listens for P2P communication. */
@CommandLine.Option(
names = {"--p2p-port"},
paramLabel = DefaultCommandValues.MANDATORY_PORT_FORMAT_HELP,
description = "Port on which to listen for P2P communication (default: ${DEFAULT-VALUE})",
arity = "1")
public final Integer p2pPort = EnodeURLImpl.DEFAULT_LISTENING_PORT;
/** The maximum number of peers this node can connect to. */
@CommandLine.Option(
names = {"--max-peers", "--p2p-peer-upper-bound"},
paramLabel = DefaultCommandValues.MANDATORY_INTEGER_FORMAT_HELP,
description = "Maximum P2P connections that can be established (default: ${DEFAULT-VALUE})")
public final Integer maxPeers = DefaultCommandValues.DEFAULT_MAX_PEERS;
/** Boolean option to limit the number of P2P connections initiated remotely. */
@CommandLine.Option(
names = {"--remote-connections-limit-enabled"},
description =
"Whether to limit the number of P2P connections initiated remotely. (default: ${DEFAULT-VALUE})")
public final Boolean isLimitRemoteWireConnectionsEnabled = true;
/** The maximum percentage of P2P connections that can be initiated remotely. */
@CommandLine.Option(
names = {"--remote-connections-max-percentage"},
paramLabel = DefaultCommandValues.MANDATORY_DOUBLE_FORMAT_HELP,
description =
"The maximum percentage of P2P connections that can be initiated remotely. Must be between 0 and 100 inclusive. (default: ${DEFAULT-VALUE})",
arity = "1",
converter = PercentageConverter.class)
public final Percentage maxRemoteConnectionsPercentage =
Fraction.fromFloat(DefaultCommandValues.DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED)
.toPercentage();
/** The URL to use for DNS discovery. */
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--discovery-dns-url"},
description = "Specifies the URL to use for DNS discovery")
public String discoveryDnsUrl = null;
/** Boolean option to allow for incoming connections to be prioritized randomly. */
@CommandLine.Option(
names = {"--random-peer-priority-enabled"},
description =
"Allow for incoming connections to be prioritized randomly. This will prevent (typically small, stable) networks from forming impenetrable peer cliques. (default: ${DEFAULT-VALUE})")
public final Boolean randomPeerPriority = Boolean.FALSE;
/** A list of node IDs to ban from the P2P network. */
@CommandLine.Option(
names = {"--banned-node-ids", "--banned-node-id"},
paramLabel = DefaultCommandValues.MANDATORY_NODE_ID_FORMAT_HELP,
description = "A list of node IDs to ban from the P2P network.",
split = ",",
arity = "1..*")
void setBannedNodeIds(final List<String> values) {
try {
bannedNodeIds =
values.stream()
.filter(value -> !value.isEmpty())
.map(EnodeURLImpl::parseNodeId)
.collect(Collectors.toList());
} catch (final IllegalArgumentException e) {
throw new CommandLine.ParameterException(
new CommandLine(this), "Invalid ids supplied to '--banned-node-ids'. " + e.getMessage());
}
}
// 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.
@CommandLine.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<>();
/**
* Auto-discovers the default IP of the client.
*
* @return machine loopback address
*/
// Loopback IP is used by default as this is how smokeTests require it to be
// and it's probably a good security behaviour to default only on the localhost.
public InetAddress autoDiscoverDefaultIP() {
autoDiscoveredDefaultIP =
Optional.ofNullable(autoDiscoveredDefaultIP).orElseGet(InetAddress::getLoopbackAddress);
return autoDiscoveredDefaultIP;
}
@CommandLine.Option(
names = {"--net-restrict"},
arity = "1..*",
split = ",",
converter = SubnetInfoConverter.class,
description =
"Comma-separated list of allowed IP subnets (e.g., '192.168.1.0/24,10.0.0.0/8').")
private List<SubnetUtils.SubnetInfo> allowedSubnets;
@Override
public P2PDiscoveryConfiguration toDomainObject() {
return new P2PDiscoveryConfiguration(
p2pEnabled,
peerDiscoveryEnabled,
p2pHost,
p2pInterface,
p2pPort,
maxPeers,
isLimitRemoteWireConnectionsEnabled,
maxRemoteConnectionsPercentage,
randomPeerPriority,
bannedNodeIds,
allowedSubnets,
poaDiscoveryRetryBootnodes,
bootNodes,
discoveryDnsUrl);
}
@Override
public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new P2PDiscoveryOptions());
}
}

@ -30,6 +30,7 @@ import org.slf4j.Logger;
import picocli.CommandLine;
/** Handles configuration options for permissions in Besu. */
// TODO: implement CLIOption<PermissioningConfiguration>
public class PermissionsOptions {
@CommandLine.Option(
names = {"--permissions-nodes-config-file-enabled"},

@ -0,0 +1,121 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.storage;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_RECEIPT_COMPACTION_ENABLED;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import picocli.CommandLine;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
/** The Data storage CLI options. */
public class DataStorageOptions implements CLIOptions<DataStorageConfiguration> {
private static final String DATA_STORAGE_FORMAT = "--data-storage-format";
// Use Bonsai DB
@Option(
names = {DATA_STORAGE_FORMAT},
description =
"Format to store trie data in. Either FOREST or BONSAI (default: ${DEFAULT-VALUE}).",
arity = "1")
private DataStorageFormat dataStorageFormat = DataStorageFormat.BONSAI;
@Option(
names = "--receipt-compaction-enabled",
description = "Enables compact storing of receipts (default: ${DEFAULT-VALUE})",
fallbackValue = "true")
private Boolean receiptCompactionEnabled = DEFAULT_RECEIPT_COMPACTION_ENABLED;
/**
* Options specific to diff-based storage modes. Holds the necessary parameters to configure
* diff-based storage, such as the Bonsai mode or Verkle in the future.
*/
@Mixin
private DiffBasedSubStorageOptions diffBasedSubStorageOptions =
DiffBasedSubStorageOptions.create();
/** Default Constructor. */
DataStorageOptions() {}
/**
* Create data storage options.
*
* @return the data storage options
*/
public static DataStorageOptions create() {
return new DataStorageOptions();
}
/**
* Validates the data storage options
*
* @param commandLine the full commandLine to check all the options specified by the user
*/
public void validate(final CommandLine commandLine) {
diffBasedSubStorageOptions.validate(commandLine, dataStorageFormat);
}
/**
* Converts to options from the configuration
*
* @param domainObject to be reversed
* @return the options that correspond to the configuration
*/
public static DataStorageOptions fromConfig(final DataStorageConfiguration domainObject) {
final DataStorageOptions dataStorageOptions = DataStorageOptions.create();
dataStorageOptions.dataStorageFormat = domainObject.getDataStorageFormat();
dataStorageOptions.receiptCompactionEnabled = domainObject.getReceiptCompactionEnabled();
dataStorageOptions.diffBasedSubStorageOptions =
DiffBasedSubStorageOptions.fromConfig(domainObject.getDiffBasedSubStorageConfiguration());
return dataStorageOptions;
}
@Override
public DataStorageConfiguration toDomainObject() {
final ImmutableDataStorageConfiguration.Builder builder =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(dataStorageFormat)
.receiptCompactionEnabled(receiptCompactionEnabled)
.diffBasedSubStorageConfiguration(diffBasedSubStorageOptions.toDomainObject());
return builder.build();
}
@Override
public List<String> getCLIOptions() {
final List<String> cliOptions = CommandLineUtils.getCLIOptions(this, new DataStorageOptions());
cliOptions.addAll(diffBasedSubStorageOptions.getCLIOptions());
return cliOptions;
}
/**
* Normalize data storage format string.
*
* @return the normalized string
*/
public String normalizeDataStorageFormat() {
return StringUtils.capitalize(dataStorageFormat.toString().toLowerCase(Locale.ROOT));
}
}

@ -0,0 +1,217 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.storage;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DEFAULT_LIMIT_TRIE_LOGS_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DEFAULT_MAX_LAYERS_TO_LOAD;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DiffBasedUnstable.DEFAULT_CODE_USING_CODE_HASH_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DiffBasedUnstable.DEFAULT_FULL_FLAT_DB_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.MINIMUM_TRIE_LOG_RETENTION_LIMIT;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDiffBasedSubStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.util.List;
import picocli.CommandLine;
import picocli.CommandLine.Option;
/** The Data storage CLI options. */
public class DiffBasedSubStorageOptions implements CLIOptions<DiffBasedSubStorageConfiguration> {
/** The maximum number of historical layers to load. */
public static final String MAX_LAYERS_TO_LOAD = "--bonsai-historical-block-limit";
@Option(
names = {MAX_LAYERS_TO_LOAD, "--bonsai-maximum-back-layers-to-load"},
paramLabel = "<LONG>",
description =
"Limit of historical layers that can be loaded with BONSAI (default: ${DEFAULT-VALUE}). When using "
+ LIMIT_TRIE_LOGS_ENABLED
+ " it will also be used as the number of layers of trie logs to retain.",
arity = "1")
private Long maxLayersToLoad = DEFAULT_MAX_LAYERS_TO_LOAD;
/** The bonsai limit trie logs enabled option name */
public static final String LIMIT_TRIE_LOGS_ENABLED = "--bonsai-limit-trie-logs-enabled";
/** The bonsai trie logs pruning window size. */
public static final String TRIE_LOG_PRUNING_WINDOW_SIZE =
"--bonsai-trie-logs-pruning-window-size";
// TODO --Xbonsai-limit-trie-logs-enabled and --Xbonsai-trie-log-pruning-enabled are deprecated,
// remove in a future release
@SuppressWarnings("ExperimentalCliOptionMustBeCorrectlyDisplayed")
@Option(
names = {
LIMIT_TRIE_LOGS_ENABLED,
"--Xbonsai-limit-trie-logs-enabled", // deprecated
"--Xbonsai-trie-log-pruning-enabled" // deprecated
},
fallbackValue = "true",
description = "Limit the number of trie logs that are retained. (default: ${DEFAULT-VALUE})")
private Boolean limitTrieLogsEnabled = DEFAULT_LIMIT_TRIE_LOGS_ENABLED;
// TODO --Xbonsai-trie-logs-pruning-window-size is deprecated, remove in a future release
@SuppressWarnings("ExperimentalCliOptionMustBeCorrectlyDisplayed")
@Option(
names = {
TRIE_LOG_PRUNING_WINDOW_SIZE,
"--Xbonsai-trie-logs-pruning-window-size" // deprecated
},
description =
"The max number of blocks to load and prune trie logs for at startup. (default: ${DEFAULT-VALUE})")
private Integer trieLogPruningWindowSize = DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE;
@CommandLine.ArgGroup(validate = false)
private final DiffBasedSubStorageOptions.Unstable unstableOptions = new Unstable();
/** Default Constructor. */
DiffBasedSubStorageOptions() {}
/** The unstable options for data storage. */
public static class Unstable {
// TODO: --Xsnapsync-synchronizer-flat-db-healing-enabled is deprecated, remove it in a future
// release
@Option(
hidden = true,
names = {
"--Xbonsai-full-flat-db-enabled",
"--Xsnapsync-synchronizer-flat-db-healing-enabled"
},
arity = "1",
description = "Enables bonsai full flat database strategy. (default: ${DEFAULT-VALUE})")
private Boolean fullFlatDbEnabled = DEFAULT_FULL_FLAT_DB_ENABLED;
@Option(
hidden = true,
names = {"--Xbonsai-code-using-code-hash-enabled"},
arity = "1",
description =
"Enables code storage using code hash instead of by account hash. (default: ${DEFAULT-VALUE})")
private boolean codeUsingCodeHashEnabled = DEFAULT_CODE_USING_CODE_HASH_ENABLED;
@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() {}
}
/**
* Create data storage options.
*
* @return the data storage options
*/
public static DiffBasedSubStorageOptions create() {
return new DiffBasedSubStorageOptions();
}
/**
* Validates the data storage options
*
* @param commandLine the full commandLine to check all the options specified by the user
* @param dataStorageFormat the selected data storage format which determines the validation rules
* to apply.
*/
public void validate(final CommandLine commandLine, final DataStorageFormat dataStorageFormat) {
if (DataStorageFormat.BONSAI == dataStorageFormat) {
if (limitTrieLogsEnabled) {
if (maxLayersToLoad < MINIMUM_TRIE_LOG_RETENTION_LIMIT) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
MAX_LAYERS_TO_LOAD + " minimum value is %d", MINIMUM_TRIE_LOG_RETENTION_LIMIT));
}
if (trieLogPruningWindowSize <= 0) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than 0",
trieLogPruningWindowSize));
}
if (trieLogPruningWindowSize <= maxLayersToLoad) {
throw new CommandLine.ParameterException(
commandLine,
String.format(
TRIE_LOG_PRUNING_WINDOW_SIZE
+ "=%d must be greater than "
+ MAX_LAYERS_TO_LOAD
+ "=%d",
trieLogPruningWindowSize,
maxLayersToLoad));
}
}
} else {
if (unstableOptions.isParallelTxProcessingEnabled) {
throw new CommandLine.ParameterException(
commandLine,
"Transaction parallelization is not supported unless operating in a 'diffbased' mode, such as Bonsai.");
}
}
}
/**
* Converts to options from the configuration
*
* @param domainObject to be reversed
* @return the options that correspond to the configuration
*/
public static DiffBasedSubStorageOptions fromConfig(
final DiffBasedSubStorageConfiguration domainObject) {
final DiffBasedSubStorageOptions dataStorageOptions = DiffBasedSubStorageOptions.create();
dataStorageOptions.maxLayersToLoad = domainObject.getMaxLayersToLoad();
dataStorageOptions.limitTrieLogsEnabled = domainObject.getLimitTrieLogsEnabled();
dataStorageOptions.trieLogPruningWindowSize = domainObject.getTrieLogPruningWindowSize();
dataStorageOptions.unstableOptions.fullFlatDbEnabled =
domainObject.getUnstable().getFullFlatDbEnabled();
dataStorageOptions.unstableOptions.codeUsingCodeHashEnabled =
domainObject.getUnstable().getCodeStoredByCodeHashEnabled();
dataStorageOptions.unstableOptions.isParallelTxProcessingEnabled =
domainObject.getUnstable().isParallelTxProcessingEnabled();
return dataStorageOptions;
}
@Override
public final DiffBasedSubStorageConfiguration toDomainObject() {
return ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(maxLayersToLoad)
.limitTrieLogsEnabled(limitTrieLogsEnabled)
.trieLogPruningWindowSize(trieLogPruningWindowSize)
.unstable(
ImmutableDiffBasedSubStorageConfiguration.DiffBasedUnstable.builder()
.fullFlatDbEnabled(unstableOptions.fullFlatDbEnabled)
.codeStoredByCodeHashEnabled(unstableOptions.codeUsingCodeHashEnabled)
.isParallelTxProcessingEnabled(unstableOptions.isParallelTxProcessingEnabled)
.build())
.build();
}
@Override
public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new DiffBasedSubStorageOptions());
}
}

@ -1,79 +0,0 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.unstable;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import java.util.Arrays;
import java.util.List;
import picocli.CommandLine;
/** The Metrics cli options. */
public class MetricsCLIOptions implements CLIOptions<MetricsConfiguration.Builder> {
private static final String TIMERS_ENABLED_FLAG = "--Xmetrics-timers-enabled";
private static final String IDLE_TIMEOUT_FLAG = "--Xmetrics-idle-timeout";
@CommandLine.Option(
names = TIMERS_ENABLED_FLAG,
hidden = true,
description = "Whether to enable timer metrics (default: ${DEFAULT-VALUE}).")
private Boolean timersEnabled = MetricsConfiguration.DEFAULT_METRICS_TIMERS_ENABLED;
@CommandLine.Option(
hidden = true,
names = {IDLE_TIMEOUT_FLAG},
paramLabel = "<INTEGER>",
description = "Timeout for metrics TCP connections, in seconds (default: ${DEFAULT-VALUE})",
arity = "1")
private int idleTimeout = MetricsConfiguration.DEFAULT_METRICS_IDLE_TIMEOUT_SECONDS;
private MetricsCLIOptions() {}
/**
* Create metrics cli options.
*
* @return the metrics cli options
*/
public static MetricsCLIOptions create() {
return new MetricsCLIOptions();
}
/**
* From configuration metrics cli options.
*
* @param config the config
* @return the metrics cli options
*/
public static MetricsCLIOptions fromConfiguration(final MetricsConfiguration config) {
final MetricsCLIOptions metricsOptions = create();
metricsOptions.timersEnabled = config.isTimersEnabled();
metricsOptions.idleTimeout = config.getIdleTimeout();
return metricsOptions;
}
@Override
public MetricsConfiguration.Builder toDomainObject() {
return MetricsConfiguration.builder().timersEnabled(timersEnabled).idleTimeout(idleTimeout);
}
@Override
public List<String> getCLIOptions() {
return Arrays.asList(
TIMERS_ENABLED_FLAG + "=" + timersEnabled.toString(),
IDLE_TIMEOUT_FLAG + "=" + idleTimeout);
}
}

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
package org.hyperledger.besu.cli.options.unstable;
import static java.util.Arrays.asList;
import static org.hyperledger.besu.cli.DefaultCommandValues.DEFAULT_KEYSTORE_TYPE;

@ -23,6 +23,7 @@ import org.hyperledger.besu.cli.util.VersionProvider;
import java.io.PrintWriter;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.security.crypto.bcrypt.BCrypt;
import picocli.CommandLine.Command;
import picocli.CommandLine.Model.CommandSpec;
@ -75,6 +76,7 @@ public class PasswordSubCommand implements Runnable {
static class HashSubCommand implements Runnable {
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@NotEmpty
@Option(
names = "--password",
arity = "1..1",

@ -54,6 +54,7 @@ import java.util.function.Function;
import java.util.function.Supplier;
import io.vertx.core.Vertx;
import jakarta.validation.constraints.NotBlank;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -335,6 +336,7 @@ public class BlocksSubCommand implements Runnable {
arity = "1..1")
private final BlockExportFormat format = BlockExportFormat.RLP;
@NotBlank
@Option(
names = "--to",
required = true,

@ -33,6 +33,7 @@ import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
import jakarta.validation.constraints.NotBlank;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
@ -55,6 +56,7 @@ public class BackupState implements Runnable {
arity = "1..1")
private final Long block = Long.MAX_VALUE;
@NotBlank
@Option(
names = "--backup-path",
required = true,

@ -52,6 +52,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.io.Resources;
import jakarta.validation.constraints.NotBlank;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -70,6 +71,7 @@ class GenerateBlockchainConfig implements Runnable {
private final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
@NotBlank
@Option(
required = true,
names = "--config-file",
@ -78,6 +80,7 @@ class GenerateBlockchainConfig implements Runnable {
arity = "1..1")
private final File configurationFile = null;
@NotBlank
@Option(
required = true,
names = "--to",

@ -46,6 +46,7 @@ import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.validation.constraints.NotBlank;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.slf4j.Logger;
@ -64,6 +65,7 @@ public class RestoreState implements Runnable {
private static final Logger LOG = LoggerFactory.getLogger(RestoreState.class);
@NotBlank
@Option(
names = "--backup-path",
required = true,

@ -15,21 +15,22 @@
package org.hyperledger.besu.cli.subcommands.storage;
import static com.google.common.base.Preconditions.checkArgument;
import static org.hyperledger.besu.cli.options.stable.DataStorageOptions.BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD;
import static org.hyperledger.besu.cli.options.storage.DiffBasedSubStorageOptions.MAX_LAYERS_TO_LOAD;
import static org.hyperledger.besu.cli.options.storage.DiffBasedSubStorageOptions.TRIE_LOG_PRUNING_WINDOW_SIZE;
import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE;
import org.hyperledger.besu.cli.options.stable.DataStorageOptions;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration;
import java.io.File;
import java.io.FileInputStream;
@ -64,7 +65,7 @@ public class TrieLogHelper {
boolean prune(
final DataStorageConfiguration config,
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final MutableBlockchain blockchain,
final Path dataDirectoryPath) {
@ -73,7 +74,7 @@ public class TrieLogHelper {
validatePruneConfiguration(config);
final long layersToRetain = config.getBonsaiMaxLayersToLoad();
final long layersToRetain = config.getDiffBasedSubStorageConfiguration().getMaxLayersToLoad();
final long chainHeight = blockchain.getChainHeadBlockNumber();
@ -102,7 +103,7 @@ public class TrieLogHelper {
// Should only be layersToRetain left but loading extra just in case of an unforeseen bug
final long countAfterPrune =
rootWorldStateStorage
.streamTrieLogKeys(layersToRetain + DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE)
.streamTrieLogKeys(layersToRetain + DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE)
.count();
if (countAfterPrune == layersToRetain) {
if (deleteFiles(batchFileNameBase, numberOfBatches)) {
@ -115,15 +116,12 @@ public class TrieLogHelper {
throw new IllegalStateException(
String.format(
"Remaining trie logs (%d) did not match %s (%d). Trie logs backup files (in %s) have not been deleted, it is safe to rerun the subcommand.",
countAfterPrune,
BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD,
layersToRetain,
batchFileNameBase));
countAfterPrune, MAX_LAYERS_TO_LOAD, layersToRetain, batchFileNameBase));
}
}
private void processTrieLogBatches(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final MutableBlockchain blockchain,
final long chainHeight,
final long lastBlockNumberToRetainTrieLogsFor,
@ -152,7 +150,7 @@ public class TrieLogHelper {
private void saveTrieLogBatches(
final String batchFileName,
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final List<Hash> trieLogKeys) {
try {
@ -164,7 +162,7 @@ public class TrieLogHelper {
}
private void restoreTrieLogBatches(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final long batchNumber,
final String batchFileNameBase) {
@ -217,7 +215,7 @@ public class TrieLogHelper {
final MutableBlockchain blockchain,
final long chainHeight,
final long lastBlockNumberToRetainTrieLogsFor,
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final long layersToRetain) {
if (lastBlockNumberToRetainTrieLogsFor < 0) {
@ -231,7 +229,7 @@ public class TrieLogHelper {
// plus extra threshold to account forks and orphans
final long clampedCountBeforePruning =
rootWorldStateStorage
.streamTrieLogKeys(layersToRetain + DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE)
.streamTrieLogKeys(layersToRetain + DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE)
.count();
if (clampedCountBeforePruning < layersToRetain) {
throw new IllegalArgumentException(
@ -257,7 +255,7 @@ public class TrieLogHelper {
}
private void recreateTrieLogs(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final long batchNumber,
final String batchFileNameBase)
throws IOException {
@ -277,7 +275,7 @@ public class TrieLogHelper {
final int chunkSize,
final List<byte[]> keys,
final IdentityHashMap<byte[], byte[]> trieLogsToRetain,
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage) {
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage) {
var updater = rootWorldStateStorage.updater();
int endIndex = Math.min(startIndex + chunkSize, keys.size());
@ -294,31 +292,31 @@ public class TrieLogHelper {
@VisibleForTesting
void validatePruneConfiguration(final DataStorageConfiguration config) {
final DiffBasedSubStorageConfiguration subStorageConfiguration =
config.getDiffBasedSubStorageConfiguration();
checkArgument(
config.getBonsaiMaxLayersToLoad()
>= DataStorageConfiguration.MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT,
subStorageConfiguration.getMaxLayersToLoad()
>= DiffBasedSubStorageConfiguration.MINIMUM_TRIE_LOG_RETENTION_LIMIT,
String.format(
BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD + " minimum value is %d",
DataStorageConfiguration.MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT));
MAX_LAYERS_TO_LOAD + " minimum value is %d",
DiffBasedSubStorageConfiguration.MINIMUM_TRIE_LOG_RETENTION_LIMIT));
checkArgument(
config.getBonsaiTrieLogPruningWindowSize() > 0,
subStorageConfiguration.getTrieLogPruningWindowSize() > 0,
String.format(
DataStorageOptions.BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than 0",
config.getBonsaiTrieLogPruningWindowSize()));
TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than 0",
subStorageConfiguration.getTrieLogPruningWindowSize()));
checkArgument(
config.getBonsaiTrieLogPruningWindowSize() > config.getBonsaiMaxLayersToLoad(),
subStorageConfiguration.getTrieLogPruningWindowSize()
> subStorageConfiguration.getMaxLayersToLoad(),
String.format(
DataStorageOptions.BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE
+ "=%d must be greater than "
+ BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD
+ "=%d",
config.getBonsaiTrieLogPruningWindowSize(),
config.getBonsaiMaxLayersToLoad()));
TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than " + MAX_LAYERS_TO_LOAD + "=%d",
subStorageConfiguration.getTrieLogPruningWindowSize(),
subStorageConfiguration.getMaxLayersToLoad()));
}
private void saveTrieLogsInFile(
final List<Hash> trieLogsKeys,
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final String batchFileName)
throws IOException {
@ -355,7 +353,7 @@ public class TrieLogHelper {
private void saveTrieLogsAsRlpInFile(
final List<Hash> trieLogsKeys,
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final String batchFileName) {
File file = new File(batchFileName);
if (file.exists()) {
@ -400,7 +398,8 @@ public class TrieLogHelper {
}
private IdentityHashMap<byte[], byte[]> getTrieLogs(
final List<Hash> trieLogKeys, final BonsaiWorldStateKeyValueStorage rootWorldStateStorage) {
final List<Hash> trieLogKeys,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage) {
IdentityHashMap<byte[], byte[]> trieLogsToRetain = new IdentityHashMap<>();
LOG.info("Obtaining trielogs from db, this may take a few minutes...");
@ -413,7 +412,7 @@ public class TrieLogHelper {
}
TrieLogCount getCount(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final int limit,
final Blockchain blockchain) {
final AtomicInteger total = new AtomicInteger();
@ -454,7 +453,7 @@ public class TrieLogHelper {
}
void importTrieLog(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage, final Path trieLogFilePath) {
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage, final Path trieLogFilePath) {
var trieLog = readTrieLogsAsRlpFromFile(trieLogFilePath.toString());
@ -464,7 +463,7 @@ public class TrieLogHelper {
}
void exportTrieLog(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage,
final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final List<Hash> trieLogHash,
final Path directoryPath)
throws IOException {

@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldSt
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.ethereum.worldstate.ImmutableDiffBasedSubStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.io.IOException;
@ -89,7 +90,11 @@ public class TrieLogSubCommand implements Runnable {
.besuCommand
.setupControllerBuilder()
.dataStorageConfiguration(
ImmutableDataStorageConfiguration.copyOf(config).withBonsaiLimitTrieLogsEnabled(false))
ImmutableDataStorageConfiguration.copyOf(config)
.withDiffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.copyOf(
config.getDiffBasedSubStorageConfiguration())
.withLimitTrieLogsEnabled(false)))
.build();
}

@ -20,7 +20,10 @@ import org.hyperledger.besu.chainexport.RlpBlockExporter;
import org.hyperledger.besu.chainimport.JsonBlockImporter;
import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.BesuCommand;
import org.hyperledger.besu.cli.options.stable.P2PDiscoveryOptions;
import org.hyperledger.besu.cli.options.unstable.RPCOptions;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.ethereum.p2p.discovery.P2PDiscoveryConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.services.BesuPluginContextImpl;
@ -53,7 +56,6 @@ public class BesuCommandModule {
new BesuPluginContextImpl(),
System.getenv(),
commandLogger);
besuCommand.toCommandLine();
return besuCommand;
}
@ -63,6 +65,18 @@ public class BesuCommandModule {
return provideFrom.metricsConfiguration();
}
@Provides
@Singleton
RPCOptions provideRPCOptions() {
return RPCOptions.create();
}
@Provides
@Singleton
P2PDiscoveryConfiguration provideP2PDiscoveryConfiguration() {
return new P2PDiscoveryOptions().toDomainObject();
}
@Provides
@Named("besuCommandLogger")
@Singleton

@ -91,6 +91,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.verkle.VerkleWorldStateProvi
import org.hyperledger.besu.ethereum.trie.diffbased.verkle.storage.VerkleWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
@ -719,7 +720,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
ethPeers.snapServerPeersNeeded(false);
}
protocolContext.setSynchronizer(Optional.of(synchronizer));
protocolContext.setSynchronizer(synchronizer);
final Optional<SnapProtocolManager> maybeSnapProtocolManager =
createSnapProtocolManager(
@ -743,15 +744,18 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
final JsonRpcMethods additionalJsonRpcMethodFactory =
createAdditionalJsonRpcMethodFactory(protocolContext, protocolSchedule, miningParameters);
if (dataStorageConfiguration.getBonsaiLimitTrieLogsEnabled()
&& DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())) {
final TrieLogManager trieLogManager =
((BonsaiWorldStateProvider) worldStateArchive).getTrieLogManager();
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage =
worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class);
final TrieLogPruner trieLogPruner =
createTrieLogPruner(worldStateKeyValueStorage, blockchain, scheduler);
trieLogManager.subscribe(trieLogPruner);
if (DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())) {
final DiffBasedSubStorageConfiguration subStorageConfiguration =
dataStorageConfiguration.getDiffBasedSubStorageConfiguration();
if (subStorageConfiguration.getLimitTrieLogsEnabled()) {
final TrieLogManager trieLogManager =
((BonsaiWorldStateProvider) worldStateArchive).getTrieLogManager();
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage =
worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class);
final TrieLogPruner trieLogPruner =
createTrieLogPruner(worldStateKeyValueStorage, blockchain, scheduler);
trieLogManager.subscribe(trieLogPruner);
}
}
final List<Closeable> closeables = new ArrayList<>();
@ -805,14 +809,15 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
final Blockchain blockchain,
final EthScheduler scheduler) {
final boolean isProofOfStake = genesisConfigOptions.getTerminalTotalDifficulty().isPresent();
final DiffBasedSubStorageConfiguration subStorageConfiguration =
dataStorageConfiguration.getDiffBasedSubStorageConfiguration();
final TrieLogPruner trieLogPruner =
new TrieLogPruner(
(BonsaiWorldStateKeyValueStorage) worldStateStorage,
blockchain,
scheduler::executeServiceTask,
dataStorageConfiguration.getBonsaiMaxLayersToLoad(),
dataStorageConfiguration.getBonsaiTrieLogPruningWindowSize(),
subStorageConfiguration.getMaxLayersToLoad(),
subStorageConfiguration.getTrieLogPruningWindowSize(),
isProofOfStake,
metricsSystem);
trieLogPruner.initialize();
@ -1094,10 +1099,14 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
case BONSAI -> {
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage =
worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class);
yield new BonsaiWorldStateProvider(
worldStateKeyValueStorage,
blockchain,
Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()),
Optional.of(
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getMaxLayersToLoad()),
bonsaiCachedMerkleTrieLoader,
besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null),
evmConfiguration);
@ -1109,8 +1118,9 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
worldStateKeyValueStorage,
blockchain,
Optional.of(
dataStorageConfiguration
.getBonsaiMaxLayersToLoad()), // TODO having verkle configuration or generic
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getMaxLayersToLoad()),
besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null),
evmConfiguration);
}

@ -253,9 +253,18 @@ public class IbftBesuControllerBuilder extends BftBesuControllerBuilder {
.getValue()
.getBlockPeriodSeconds()));
if (syncState.isInitialSyncPhaseDone()) {
ibftMiningCoordinator.enable();
}
syncState.subscribeSyncStatus(
syncStatus -> {
if (syncState.syncTarget().isPresent()) {
// We're syncing so stop doing other stuff
LOG.info("Stopping IBFT mining coordinator while we are syncing");
ibftMiningCoordinator.stop();
} else {
LOG.info("Starting IBFT mining coordinator following sync");
ibftMiningCoordinator.enable();
ibftMiningCoordinator.start();
}
});
syncState.subscribeCompletionReached(
new BesuEvents.InitialSyncCompletionListener() {

@ -301,9 +301,18 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
.getEmptyBlockPeriodSeconds());
});
if (syncState.isInitialSyncPhaseDone()) {
miningCoordinator.enable();
}
syncState.subscribeSyncStatus(
syncStatus -> {
if (syncState.syncTarget().isPresent()) {
// We're syncing so stop doing other stuff
LOG.info("Stopping QBFT mining coordinator while we are syncing");
miningCoordinator.stop();
} else {
LOG.info("Starting QBFT mining coordinator following sync");
miningCoordinator.enable();
miningCoordinator.start();
}
});
syncState.subscribeCompletionReached(
new BesuEvents.InitialSyncCompletionListener() {

@ -133,7 +133,7 @@ public class BesuEventsImpl implements BesuEvents {
public long addTransactionDroppedListener(
final TransactionDroppedListener transactionDroppedListener) {
return transactionPool.subscribeDroppedTransactions(
transactionDroppedListener::onTransactionDropped);
(transaction, reason) -> transactionDroppedListener.onTransactionDropped(transaction));
}
@Override

@ -14,9 +14,12 @@
*/
package org.hyperledger.besu.services;
import org.hyperledger.besu.datatypes.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.plugin.services.transactionpool.TransactionPoolService;
import java.util.Collection;
/** Service to enable and disable the transaction pool. */
public class TransactionPoolServiceImpl implements TransactionPoolService {
@ -40,4 +43,9 @@ public class TransactionPoolServiceImpl implements TransactionPoolService {
public void enableTransactionPool() {
transactionPool.setEnabled();
}
@Override
public Collection<? extends PendingTransaction> getPendingTransactions() {
return transactionPool.getPendingTransactions();
}
}

@ -0,0 +1,81 @@
/*
* 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.util;
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
import org.hyperledger.besu.config.GenesisConfigFile;
import java.io.IOException;
import java.math.BigInteger;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.Optional;
/**
* The Generate Ephemery Genesis Updater. Checks for update based on the set period and update the
* Ephemery genesis in memory
*/
public class EphemeryGenesisUpdater {
private static final int PERIOD_IN_DAYS = 28;
private static final long PERIOD_IN_SECONDS = (PERIOD_IN_DAYS * 24 * 60 * 60);
/**
* Constructor for EphemeryGenesisUpdater. Initializes the genesis updater for the Ephemery
* network.
*/
public EphemeryGenesisUpdater() {}
/**
* Updates the Ephemery genesis configuration based on the predefined period.
*
* @param overrides a map of configuration overrides
* @return the updated GenesisConfigFile
* @throws RuntimeException if an error occurs during the update process
*/
public static GenesisConfigFile updateGenesis(final Map<String, String> overrides)
throws RuntimeException {
GenesisConfigFile genesisConfigFile;
try {
if (EPHEMERY.getGenesisFile() == null) {
throw new IOException("Genesis file or config options are null");
}
genesisConfigFile = GenesisConfigFile.fromResource(EPHEMERY.getGenesisFile());
long genesisTimestamp = genesisConfigFile.getTimestamp();
Optional<BigInteger> genesisChainId = genesisConfigFile.getConfigOptions().getChainId();
long currentTimestamp = Instant.now().getEpochSecond();
long periodsSinceGenesis =
ChronoUnit.DAYS.between(Instant.ofEpochSecond(genesisTimestamp), Instant.now())
/ PERIOD_IN_DAYS;
long updatedTimestamp = genesisTimestamp + (periodsSinceGenesis * PERIOD_IN_SECONDS);
BigInteger updatedChainId =
genesisChainId
.orElseThrow(() -> new IllegalStateException("ChainId not present"))
.add(BigInteger.valueOf(periodsSinceGenesis));
// has a period elapsed since original ephemery genesis time? if so, override chainId and
// timestamp
if (currentTimestamp > (genesisTimestamp + PERIOD_IN_SECONDS)) {
overrides.put("chainId", String.valueOf(updatedChainId));
overrides.put("timestamp", String.valueOf(updatedTimestamp));
genesisConfigFile = genesisConfigFile.withOverrides(overrides);
}
return genesisConfigFile.withOverrides(overrides);
} catch (IOException e) {
throw new RuntimeException("Error updating ephemery genesis: " + e.getMessage(), e);
}
}
}

@ -1,6 +1,6 @@
#!/bin/bash
##
## Copyright contributors to Hyperledger Besu.
## Copyright contributors to 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

@ -15,6 +15,7 @@
package org.hyperledger.besu;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -46,20 +47,14 @@ import java.util.stream.Stream;
import com.google.common.collect.Streams;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.mockito.junit.jupiter.MockitoExtension;
@RunWith(Parameterized.class)
@ExtendWith(MockitoExtension.class)
public class ForkIdsNetworkConfigTest {
@Parameterized.Parameter public NetworkName chainName;
@Parameterized.Parameter(1)
public List<ForkId> expectedForkIds;
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return List.of(
new Object[] {
@ -149,8 +144,8 @@ public class ForkIdsNetworkConfigTest {
final AtomicLong blockNumber = new AtomicLong();
when(mockBlockchain.getChainHeadHeader()).thenReturn(mockBlockHeader);
when(mockBlockHeader.getNumber()).thenAnswer(o -> blockNumber.get());
when(mockBlockHeader.getTimestamp()).thenAnswer(o -> blockNumber.get());
lenient().when(mockBlockHeader.getNumber()).thenAnswer(o -> blockNumber.get());
lenient().when(mockBlockHeader.getTimestamp()).thenAnswer(o -> blockNumber.get());
final ForkIdManager forkIdManager =
new ForkIdManager(

@ -24,7 +24,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.config.MergeConfiguration;
import org.hyperledger.besu.consensus.common.bft.BftEventQueue;
import org.hyperledger.besu.consensus.common.bft.network.PeerConnectionTracker;
import org.hyperledger.besu.consensus.common.bft.protocol.BftProtocolManager;
@ -250,7 +250,7 @@ public final class RunnerBuilderTest {
engine.setEnabled(true);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.networkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
MergeConfiguration.setMergeEnabled(true);
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
final Runner runner =
@ -292,7 +292,7 @@ public final class RunnerBuilderTest {
wsRpc.setEnabled(true);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.networkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
MergeConfiguration.setMergeEnabled(true);
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
final JsonRpcConfiguration engineConf = JsonRpcConfiguration.createEngineDefault();
engineConf.setEnabled(true);
@ -335,7 +335,7 @@ public final class RunnerBuilderTest {
wsRpc.setEnabled(true);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.networkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
MergeConfiguration.setMergeEnabled(true);
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
final JsonRpcConfiguration engineConf = JsonRpcConfiguration.createEngineDefault();
engineConf.setEnabled(true);
@ -383,7 +383,7 @@ public final class RunnerBuilderTest {
defaultWebSockConfig.setEnabled(true);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.networkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
MergeConfiguration.setMergeEnabled(true);
final Runner runner =
new RunnerBuilder()

@ -28,7 +28,7 @@ import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.JsonUtil;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.config.MergeConfiguration;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.controller.MainnetBesuControllerBuilder;
import org.hyperledger.besu.crypto.KeyPairUtil;
@ -151,7 +151,7 @@ public final class RunnerTest {
@Test
public void fullSyncFromGenesis() throws Exception {
// set merge flag to false, otherwise this test can fail if a merge test runs first
MergeConfigOptions.setMergeEnabled(false);
MergeConfiguration.setMergeEnabled(false);
syncFromGenesis(SyncMode.FULL, getFastSyncGenesis());
}
@ -159,7 +159,7 @@ public final class RunnerTest {
@Test
public void fastSyncFromGenesis() throws Exception {
// set merge flag to false, otherwise this test can fail if a merge test runs first
MergeConfigOptions.setMergeEnabled(false);
MergeConfiguration.setMergeEnabled(false);
syncFromGenesis(SyncMode.FAST, getFastSyncGenesis());
}

@ -21,7 +21,7 @@ import static org.mockito.Mockito.mock;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.config.MergeConfiguration;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
@ -91,7 +91,7 @@ public final class RlpBlockImporterTest {
@Test
public void blockImportRejectsBadPow() throws IOException {
// set merge flag to false, otherwise this test can fail if a merge test runs first
MergeConfigOptions.setMergeEnabled(false);
MergeConfiguration.setMergeEnabled(false);
final Path source = dataDir.resolve("badpow.blocks");
BlockTestUtil.writeBadPowBlocks(source);

@ -16,9 +16,9 @@ package org.hyperledger.besu.cli;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC;
import static org.hyperledger.besu.cli.config.NetworkName.DEV;
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
import static org.hyperledger.besu.cli.config.NetworkName.EXPERIMENTAL_EIPS;
import static org.hyperledger.besu.cli.config.NetworkName.FUTURE_EIPS;
import static org.hyperledger.besu.cli.config.NetworkName.HOLESKY;
@ -32,7 +32,7 @@ import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfigura
import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.SEPOLIA_BOOTSTRAP_NODES;
import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.SEPOLIA_DISCOVERY_URL;
import static org.hyperledger.besu.plugin.services.storage.DataStorageFormat.BONSAI;
import static org.junit.Assume.assumeThat;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
@ -43,8 +43,9 @@ import static org.mockito.Mockito.verify;
import org.hyperledger.besu.BesuInfo;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.config.MergeConfiguration;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
@ -162,13 +163,13 @@ public class BesuCommandTest extends CommandTestAbstract {
// and ignore errors in case no trusted setup was already loaded
}
MergeConfigOptions.setMergeEnabled(false);
MergeConfiguration.setMergeEnabled(false);
}
@AfterEach
public void tearDown() {
MergeConfigOptions.setMergeEnabled(false);
MergeConfiguration.setMergeEnabled(false);
}
@Test
@ -1012,7 +1013,7 @@ public class BesuCommandTest extends CommandTestAbstract {
}
@Test
public void p2pHostAndPortOptionsAreRespected() {
public void p2pHostAndPortOptionsAreRespectedAndNotLeaked() {
final String host = "1.2.3.4";
final int port = 1234;
@ -1020,6 +1021,8 @@ public class BesuCommandTest extends CommandTestAbstract {
verify(mockRunnerBuilder).p2pAdvertisedHost(stringArgumentCaptor.capture());
verify(mockRunnerBuilder).p2pListenPort(intArgumentCaptor.capture());
verify(mockRunnerBuilder).metricsConfiguration(metricsConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).jsonRpcConfiguration(jsonRpcConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(stringArgumentCaptor.getValue()).isEqualTo(host);
@ -1027,6 +1030,48 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
// all other port values remain default
assertThat(metricsConfigArgumentCaptor.getValue().getPort()).isEqualTo(9545);
assertThat(metricsConfigArgumentCaptor.getValue().getPushPort()).isEqualTo(9001);
assertThat(jsonRpcConfigArgumentCaptor.getValue().getPort()).isEqualTo(8545);
// all other host values remain default
final String defaultHost = "127.0.0.1";
assertThat(metricsConfigArgumentCaptor.getValue().getHost()).isEqualTo(defaultHost);
assertThat(metricsConfigArgumentCaptor.getValue().getPushHost()).isEqualTo(defaultHost);
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHost()).isEqualTo(defaultHost);
}
@Test
public void p2pHostAndPortOptionsAreRespectedAndNotLeakedWithMetricsEnabled() {
final String host = "1.2.3.4";
final int port = 1234;
parseCommand("--p2p-host", host, "--p2p-port", String.valueOf(port), "--metrics-enabled");
verify(mockRunnerBuilder).p2pAdvertisedHost(stringArgumentCaptor.capture());
verify(mockRunnerBuilder).p2pListenPort(intArgumentCaptor.capture());
verify(mockRunnerBuilder).metricsConfiguration(metricsConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).jsonRpcConfiguration(jsonRpcConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(stringArgumentCaptor.getValue()).isEqualTo(host);
assertThat(intArgumentCaptor.getValue()).isEqualTo(port);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
// all other port values remain default
assertThat(metricsConfigArgumentCaptor.getValue().getPort()).isEqualTo(9545);
assertThat(metricsConfigArgumentCaptor.getValue().getPushPort()).isEqualTo(9001);
assertThat(jsonRpcConfigArgumentCaptor.getValue().getPort()).isEqualTo(8545);
// all other host values remain default
final String defaultHost = "127.0.0.1";
assertThat(metricsConfigArgumentCaptor.getValue().getHost()).isEqualTo(defaultHost);
assertThat(metricsConfigArgumentCaptor.getValue().getPushHost()).isEqualTo(defaultHost);
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHost()).isEqualTo(defaultHost);
}
@Test
@ -1345,7 +1390,7 @@ public class BesuCommandTest extends CommandTestAbstract {
}
@Test
public void bonsaiLimitTrieLogsEnabledByDefault() {
public void diffbasedLimitTrieLogsEnabledByDefault() {
parseCommand();
verify(mockControllerBuilder)
.dataStorageConfiguration(dataStorageConfigurationArgumentCaptor.capture());
@ -1353,7 +1398,11 @@ public class BesuCommandTest extends CommandTestAbstract {
final DataStorageConfiguration dataStorageConfiguration =
dataStorageConfigurationArgumentCaptor.getValue();
assertThat(dataStorageConfiguration.getDataStorageFormat()).isEqualTo(BONSAI);
assertThat(dataStorageConfiguration.getBonsaiLimitTrieLogsEnabled()).isTrue();
assertThat(
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getLimitTrieLogsEnabled())
.isTrue();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@ -1368,7 +1417,11 @@ public class BesuCommandTest extends CommandTestAbstract {
final DataStorageConfiguration dataStorageConfiguration =
dataStorageConfigurationArgumentCaptor.getValue();
assertThat(dataStorageConfiguration.getDataStorageFormat()).isEqualTo(BONSAI);
assertThat(dataStorageConfiguration.getBonsaiLimitTrieLogsEnabled()).isFalse();
assertThat(
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getLimitTrieLogsEnabled())
.isFalse();
verify(mockLogger)
.warn(
"Forcing {}, since it cannot be enabled with --sync-mode={} and --data-storage-format={}.",
@ -1403,7 +1456,8 @@ public class BesuCommandTest extends CommandTestAbstract {
final DataStorageConfiguration dataStorageConfiguration =
dataStorageConfigurationArgumentCaptor.getValue();
assertThat(dataStorageConfiguration.getDataStorageFormat()).isEqualTo(BONSAI);
assertThat(dataStorageConfiguration.getBonsaiMaxLayersToLoad()).isEqualTo(11);
assertThat(dataStorageConfiguration.getDiffBasedSubStorageConfiguration().getMaxLayersToLoad())
.isEqualTo(11);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@ -1863,6 +1917,20 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void ephemeryValuesAreUsed() {
parseCommand("--network", "ephemery");
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilder).build();
assertThat(NetworkName.valueOf(String.valueOf(EPHEMERY))).isEqualTo(EPHEMERY);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void classicValuesAreUsed() {
parseCommand("--network", "classic");
@ -2263,7 +2331,7 @@ public class BesuCommandTest extends CommandTestAbstract {
}
@Test
public void staticNodesFileOptionValidParamenter() throws IOException {
public void staticNodesFileOptionValidParameter() throws IOException {
final Path staticNodeTempFile =
createTempFile(
"static-nodes-goodformat.json",
@ -2332,7 +2400,7 @@ public class BesuCommandTest extends CommandTestAbstract {
@Test
public void logsWarningWhenFailToLoadJemalloc() {
assumeThat(PlatformDetector.getOSType(), is("linux"));
assumeTrue(PlatformDetector.getOSType().equals("linux"));
setEnvironmentVariable("BESU_USING_JEMALLOC", "true");
parseCommand();
verify(mockLogger)
@ -2344,7 +2412,7 @@ public class BesuCommandTest extends CommandTestAbstract {
@Test
public void logsSuggestInstallingJemallocWhenEnvVarNotPresent() {
assumeThat(PlatformDetector.getOSType(), is("linux"));
assumeTrue(PlatformDetector.getOSType().equals("linux"));
parseCommand();
verify(mockLogger)
.info("jemalloc library not found, memory usage may be reduced by installing it");
@ -2492,8 +2560,9 @@ public class BesuCommandTest extends CommandTestAbstract {
besuCommand
.getDataStorageOptions()
.toDomainObject()
.getDiffBasedSubStorageConfiguration()
.getUnstable()
.getBonsaiFullFlatDbEnabled())
.getFullFlatDbEnabled())
.isTrue();
}
@ -2504,8 +2573,9 @@ public class BesuCommandTest extends CommandTestAbstract {
besuCommand
.dataStorageOptions
.toDomainObject()
.getDiffBasedSubStorageConfiguration()
.getUnstable()
.getBonsaiFullFlatDbEnabled())
.getFullFlatDbEnabled())
.isFalse();
}

@ -36,10 +36,9 @@ import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.options.MiningOptions;
import org.hyperledger.besu.cli.options.TransactionPoolOptions;
import org.hyperledger.besu.cli.options.stable.DataStorageOptions;
import org.hyperledger.besu.cli.options.stable.EthstatsOptions;
import org.hyperledger.besu.cli.options.storage.DataStorageOptions;
import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions;
import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions;
import org.hyperledger.besu.cli.options.unstable.NetworkingOptions;
import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions;
import org.hyperledger.besu.components.BesuComponent;
@ -114,6 +113,7 @@ import io.opentelemetry.api.GlobalOpenTelemetry;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.json.JsonObject;
import jakarta.validation.constraints.NotEmpty;
import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.tuweni.bytes.Bytes;
@ -610,10 +610,6 @@ public abstract class CommandTestAbstract {
return dataStorageOptions;
}
public MetricsCLIOptions getMetricsCLIOptions() {
return unstableMetricsCLIOptions;
}
public void close() {
if (vertx != null) {
final AtomicBoolean closed = new AtomicBoolean(false);
@ -626,6 +622,7 @@ public abstract class CommandTestAbstract {
@CommandLine.Command
public static class TestBesuCommandWithRequiredOption extends TestBesuCommand {
@NotEmpty
@CommandLine.Option(
names = {"--accept-terms-and-conditions"},
description = "You must explicitly accept terms and conditions",

@ -95,6 +95,16 @@ class ConfigurationOverviewBuilderTest {
assertThat(syncModeSet).contains("Sync mode: fast");
}
@Test
void setSyncMinPeers() {
final String noSyncMinPeersSet = builder.build();
assertThat(noSyncMinPeersSet).doesNotContain("Sync min peers:");
builder.setSyncMinPeers(3);
final String syncMinPeersSet = builder.build();
assertThat(syncMinPeersSet).contains("Sync min peers: 3");
}
@Test
void setRpcPort() {
final String noRpcPortSet = builder.build();
@ -152,7 +162,7 @@ class ConfigurationOverviewBuilderTest {
}
@Test
void setBonsaiLimitTrieLogsEnabled() {
void setDiffbasedLimitTrieLogsEnabled() {
final String noTrieLogRetentionLimitSet = builder.build();
assertThat(noTrieLogRetentionLimitSet).doesNotContain("Limit trie logs enabled");

@ -39,9 +39,7 @@ class NetworkDeprecationMessageTest {
@ParameterizedTest
@EnumSource(
value = NetworkName.class,
names = {
"MAINNET", "SEPOLIA", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "LUKSO",
})
names = {"MAINNET", "SEPOLIA", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "LUKSO", "EPHEMERY"})
void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) {
assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network))
.isInstanceOf(AssertionError.class);

@ -16,8 +16,7 @@ package org.hyperledger.besu.cli;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assume.assumeThat;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ -415,10 +414,9 @@ public class PrivacyOptionsTest extends CommandTestAbstract {
@Test
public void privEnclaveKeyFileDoesNotExist() {
assumeThat(
"Ignored if system language is not English",
System.getProperty("user.language"),
startsWith("en"));
assumeTrue(
System.getProperty("user.language").startsWith("en"),
"Ignored if system language is not English");
parseCommand("--privacy-enabled=true", "--privacy-public-key-file", "/non/existent/file");
assertThat(commandOutput.toString(UTF_8)).isEmpty();

@ -64,7 +64,6 @@ public abstract class AbstractCLIOptionsTest<D, T extends CLIOptions<D>>
private void getCLIOptions(final D domainObject) {
T options = optionsFromDomainObject(domainObject);
final String[] cliOptions = options.getCLIOptions().toArray(new String[0]);
final TestBesuCommand cmd = parseCommand(cliOptions);
final T optionsFromCommand = getOptionsFromBesuCommand(cmd);

@ -14,15 +14,15 @@
*/
package org.hyperledger.besu.cli.options;
import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions;
import org.hyperledger.besu.cli.options.stable.MetricsOptions;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class MetricsCLIOptionsTest
extends AbstractCLIOptionsTest<MetricsConfiguration.Builder, MetricsCLIOptions> {
public class MetricsOptionsTest
extends AbstractCLIOptionsTest<MetricsConfiguration.Builder, MetricsOptions> {
@Override
protected MetricsConfiguration.Builder createDefaultDomainObject() {
@ -37,13 +37,13 @@ public class MetricsCLIOptionsTest
}
@Override
protected MetricsCLIOptions optionsFromDomainObject(
protected MetricsOptions optionsFromDomainObject(
final MetricsConfiguration.Builder domainObject) {
return MetricsCLIOptions.fromConfiguration(domainObject.build());
return MetricsOptions.fromConfiguration(domainObject.build());
}
@Override
protected MetricsCLIOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getMetricsCLIOptions();
protected MetricsOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getMetricsOptions();
}
}

@ -15,11 +15,13 @@
package org.hyperledger.besu.cli.options.stable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.MINIMUM_TRIE_LOG_RETENTION_LIMIT;
import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest;
import org.hyperledger.besu.cli.options.storage.DataStorageOptions;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDiffBasedSubStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import org.junit.jupiter.api.Test;
@ -31,7 +33,11 @@ public class DataStorageOptionsTest
public void bonsaiTrieLogPruningLimitOption() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(dataStorageConfiguration.getBonsaiTrieLogPruningWindowSize()).isEqualTo(600),
assertThat(
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getTrieLogPruningWindowSize())
.isEqualTo(600),
"--bonsai-limit-trie-logs-enabled",
"--bonsai-trie-logs-pruning-window-size",
"600");
@ -41,7 +47,11 @@ public class DataStorageOptionsTest
public void bonsaiTrieLogPruningLimitLegacyOption() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(dataStorageConfiguration.getBonsaiTrieLogPruningWindowSize()).isEqualTo(600),
assertThat(
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getTrieLogPruningWindowSize())
.isEqualTo(600),
"--Xbonsai-limit-trie-logs-enabled",
"--Xbonsai-trie-logs-pruning-window-size",
"600");
@ -51,12 +61,16 @@ public class DataStorageOptionsTest
public void bonsaiTrieLogsEnabled_explicitlySetToFalse() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(dataStorageConfiguration.getBonsaiLimitTrieLogsEnabled()).isEqualTo(false),
assertThat(
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getLimitTrieLogsEnabled())
.isEqualTo(false),
"--bonsai-limit-trie-logs-enabled=false");
}
@Test
public void bonsaiTrieLogPruningWindowSizeShouldBePositive() {
public void diffbasedTrieLogPruningWindowSizeShouldBePositive() {
internalTestFailure(
"--bonsai-trie-logs-pruning-window-size=0 must be greater than 0",
"--bonsai-limit-trie-logs-enabled",
@ -65,7 +79,7 @@ public class DataStorageOptionsTest
}
@Test
public void bonsaiTrieLogPruningWindowSizeShouldBeAboveRetentionLimit() {
public void diffbasedTrieLogPruningWindowSizeShouldBeAboveRetentionLimit() {
internalTestFailure(
"--bonsai-trie-logs-pruning-window-size=512 must be greater than --bonsai-historical-block-limit=512",
"--bonsai-limit-trie-logs-enabled",
@ -77,8 +91,11 @@ public class DataStorageOptionsTest
public void bonsaiTrieLogRetentionLimitOption() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(dataStorageConfiguration.getBonsaiMaxLayersToLoad())
.isEqualTo(MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT + 1),
assertThat(
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getMaxLayersToLoad())
.isEqualTo(MINIMUM_TRIE_LOG_RETENTION_LIMIT + 1),
"--bonsai-limit-trie-logs-enabled",
"--bonsai-historical-block-limit",
"513");
@ -88,8 +105,11 @@ public class DataStorageOptionsTest
public void bonsaiTrieLogRetentionLimitOption_boundaryTest() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(dataStorageConfiguration.getBonsaiMaxLayersToLoad())
.isEqualTo(MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT),
assertThat(
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getMaxLayersToLoad())
.isEqualTo(MINIMUM_TRIE_LOG_RETENTION_LIMIT),
"--bonsai-limit-trie-logs-enabled",
"--bonsai-historical-block-limit",
"512");
@ -105,22 +125,28 @@ public class DataStorageOptionsTest
}
@Test
public void bonsaiCodeUsingCodeHashEnabledCanBeEnabled() {
public void diffbasedCodeUsingCodeHashEnabledCanBeEnabled() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(
dataStorageConfiguration.getUnstable().getBonsaiCodeStoredByCodeHashEnabled())
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getUnstable()
.getCodeStoredByCodeHashEnabled())
.isEqualTo(true),
"--Xbonsai-code-using-code-hash-enabled",
"true");
}
@Test
public void bonsaiCodeUsingCodeHashEnabledCanBeDisabled() {
public void diffbasedCodeUsingCodeHashEnabledCanBeDisabled() {
internalTestSuccess(
dataStorageConfiguration ->
assertThat(
dataStorageConfiguration.getUnstable().getBonsaiCodeStoredByCodeHashEnabled())
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getUnstable()
.getCodeStoredByCodeHashEnabled())
.isEqualTo(false),
"--Xbonsai-code-using-code-hash-enabled",
"false");
@ -159,9 +185,12 @@ public class DataStorageOptionsTest
protected DataStorageConfiguration createCustomizedDomainObject() {
return ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(DataStorageFormat.BONSAI)
.bonsaiMaxLayersToLoad(513L)
.bonsaiLimitTrieLogsEnabled(true)
.bonsaiTrieLogPruningWindowSize(514)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(513L)
.limitTrieLogsEnabled(true)
.trieLogPruningWindowSize(514)
.build())
.build();
}

@ -17,7 +17,7 @@ package org.hyperledger.besu.cli.subcommands.storage;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE;
import static org.hyperledger.besu.plugin.services.storage.DataStorageFormat.BONSAI;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactor
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDiffBasedSubStorageConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.io.FileNotFoundException;
@ -134,8 +135,11 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(3L)
.bonsaiLimitTrieLogsEnabled(true)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(3L)
.limitTrieLogsEnabled(true)
.build())
.build();
mockBlockchainBase();
@ -172,8 +176,11 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(2L)
.bonsaiLimitTrieLogsEnabled(true)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(2L)
.limitTrieLogsEnabled(true)
.build())
.build();
when(blockchain.getChainHeadBlockNumber()).thenReturn(5L);
@ -192,8 +199,11 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(10L)
.bonsaiLimitTrieLogsEnabled(true)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(10L)
.limitTrieLogsEnabled(true)
.build())
.build();
when(blockchain.getChainHeadBlockNumber()).thenReturn(5L);
@ -212,8 +222,11 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(2L)
.bonsaiLimitTrieLogsEnabled(true)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(2L)
.limitTrieLogsEnabled(true)
.build())
.build();
mockBlockchainBase();
@ -233,8 +246,11 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(6L)
.bonsaiLimitTrieLogsEnabled(true)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(6L)
.limitTrieLogsEnabled(true)
.build())
.build();
when(blockchain.getChainHeadBlockNumber()).thenReturn(5L);
@ -255,8 +271,11 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(3L)
.bonsaiLimitTrieLogsEnabled(true)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(3L)
.limitTrieLogsEnabled(true)
.build())
.build();
mockBlockchainBase();
@ -266,7 +285,7 @@ class TrieLogHelperTest {
final BonsaiWorldStateKeyValueStorage inMemoryWorldStateSpy = spy(inMemoryWorldState);
// force a different value the second time the trie log count is called
when(inMemoryWorldStateSpy.streamTrieLogKeys(3L + DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE))
when(inMemoryWorldStateSpy.streamTrieLogKeys(3L + DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE))
.thenCallRealMethod()
.thenReturn(Stream.empty());
assertThatThrownBy(
@ -284,8 +303,11 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(511L)
.bonsaiLimitTrieLogsEnabled(true)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(511L)
.limitTrieLogsEnabled(true)
.build())
.build();
TrieLogHelper helper = new TrieLogHelper();
@ -302,9 +324,12 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(512L)
.bonsaiLimitTrieLogsEnabled(true)
.bonsaiTrieLogPruningWindowSize(0)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(512L)
.limitTrieLogsEnabled(true)
.trieLogPruningWindowSize(0)
.build())
.build();
TrieLogHelper helper = new TrieLogHelper();
@ -320,9 +345,12 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(512L)
.bonsaiLimitTrieLogsEnabled(true)
.bonsaiTrieLogPruningWindowSize(512)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(512L)
.limitTrieLogsEnabled(true)
.trieLogPruningWindowSize(512)
.build())
.build();
TrieLogHelper helper = new TrieLogHelper();
@ -340,8 +368,11 @@ class TrieLogHelperTest {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(BONSAI)
.bonsaiMaxLayersToLoad(3L)
.bonsaiLimitTrieLogsEnabled(true)
.diffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.builder()
.maxLayersToLoad(3L)
.limitTrieLogsEnabled(true)
.build())
.build();
mockBlockchainBase();

@ -58,8 +58,10 @@ class TrieLogSubCommandTest extends CommandTestAbstract {
.dataStorageConfiguration(dataStorageConfigurationArgumentCaptor.capture());
final List<DataStorageConfiguration> configs =
dataStorageConfigurationArgumentCaptor.getAllValues();
assertThat(configs.get(0).getBonsaiLimitTrieLogsEnabled()).isTrue();
assertThat(configs.get(1).getBonsaiLimitTrieLogsEnabled()).isFalse();
assertThat(configs.get(0).getDiffBasedSubStorageConfiguration().getLimitTrieLogsEnabled())
.isTrue();
assertThat(configs.get(1).getDiffBasedSubStorageConfiguration().getLimitTrieLogsEnabled())
.isFalse();
}
@Test
@ -69,6 +71,11 @@ class TrieLogSubCommandTest extends CommandTestAbstract {
.dataStorageConfiguration(dataStorageConfigurationArgumentCaptor.capture());
final List<DataStorageConfiguration> configs =
dataStorageConfigurationArgumentCaptor.getAllValues();
assertThat(configs).allMatch(DataStorageConfiguration::getBonsaiLimitTrieLogsEnabled);
assertThat(configs)
.allMatch(
dataStorageConfiguration ->
dataStorageConfiguration
.getDiffBasedSubStorageConfiguration()
.getLimitTrieLogsEnabled());
}
}

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

Loading…
Cancel
Save