Merge branch 'main' into 7311-add-peertask-foundation-code

pull/7628/head
Matilda-Clerke 2 months ago committed by GitHub
commit 8718102277
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .github/workflows/BesuContainerVerify.sh
  2. 109
      .github/workflows/docker-promote.yml
  3. 398
      .github/workflows/draft-release.yml
  4. 316
      .github/workflows/release.yml
  5. 2
      CHANGELOG.md
  6. 9
      MAINTAINERS.md
  7. 7
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java
  8. 7
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java
  9. 15
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java
  10. 7
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java
  11. 8
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java
  12. 1
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java
  13. 305
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  14. 3
      besu/src/main/java/org/hyperledger/besu/cli/options/DataStorageOptions.java
  15. 1
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/ApiConfigurationOptions.java
  16. 36
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCConfiguration.java
  17. 81
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCOptions.java
  18. 1
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/GraphQlOptions.java
  19. 34
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java
  20. 1
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptionGroup.java
  21. 238
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java
  22. 1
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/PermissionsOptions.java
  23. 1
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java
  24. 2
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/P2PTLSConfigOptions.java
  25. 4
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelper.java
  26. 16
      besu/src/main/java/org/hyperledger/besu/components/BesuCommandModule.java
  27. 9
      besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java
  28. 2
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  29. 1
      besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java
  30. 2
      build.gradle
  31. 2
      config/src/main/java/org/hyperledger/besu/config/MergeConfigOptions.java
  32. 18
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java
  33. 3
      ethereum/api/src/main/resources/schema.graphqls
  34. 47
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  35. 84
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
  36. 10
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java
  37. 105
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java
  38. 39
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/P2PDiscoveryConfiguration.java
  39. 9
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/dns/DNSDaemonTest.java
  40. 6
      evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnDataLoadOperation.java
  41. 2
      plugin-api/build.gradle
  42. 9
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java

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

@ -0,0 +1,109 @@
name: Docker Promote
run-name: "Docker Promote ${{ github.event.release.name }}"
on:
release:
types: [released]
env:
registry: docker.io
GRADLE_OPTS: "-Dorg.gradle.parallel=true -Dorg.gradle.caching=true"
jobs:
validate:
runs-on: ubuntu-22.04
env:
RELEASE_VERSION: "${{ github.event.release.name }}"
steps:
- name: Pre-process Release Name
id: pre_process_release_version
run: |
# strip all whitespace
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_version=$RELEASE_VERSION" >> $GITHUB_OUTPUT # Set as output using the new syntax
outputs:
release_version: ${{ steps.pre_process_release_version.outputs.release_version }}
docker-promote:
needs: [validate]
env:
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Setup Java
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
with:
distribution: temurin
java-version: 21
cache: gradle
- name: Login to ${{ env.registry }}
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
with:
registry: ${{ env.registry }}
username: ${{ secrets.DOCKER_USER_RW }}
password: ${{ secrets.DOCKER_PASSWORD_RW }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
with:
cache-disabled: true
- name: Docker upload
run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_VERSION }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" dockerUploadRelease
- name: Docker manifest
run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_VERSION }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" manifestDockerRelease
docker-verify:
needs: [validate,docker-promote]
env:
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: 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:
TAG: ${{ matrix.combination.tag }}
VERSION: ${{ env.RELEASE_VERSION }}
CHECK_LATEST: true
- name: Stop container
run: docker stop ${{ env.CONTAINER_NAME }}

@ -0,0 +1,398 @@
name: Draft Release
run-name: "Draft Release ${{ inputs.tag }}"
on:
workflow_dispatch:
inputs:
tag:
required: true
env:
registry: docker.io
GRADLE_OPTS: "-Dorg.gradle.parallel=true -Dorg.gradle.caching=true"
jobs:
validate:
runs-on: ubuntu-22.04
env:
RELEASE_VERSION: "${{ inputs.tag }}"
steps:
- name: Check default branch
run: |
echo "Current Branch: ${{ github.ref_name }}"
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. 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: validate_release_version
run: |
# strip all whitespace
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_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.validate_release_version.outputs.release_version }}
fetch-depth: 1
outputs:
release_version: ${{ steps.validate_release_version.outputs.release_version }}
build:
runs-on: ubuntu-22.04
needs: validate
env:
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}}
steps:
- name: Checkout tag
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
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_VERSION}} -Pversion=${{env.RELEASE_VERSION}} assemble
- name: Hashes
id: hashes
run: |
cd build/distributions
echo "zipSha=$(shasum -a 256 besu*.zip)"
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_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_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_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_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_VERSION }}.tar.gz.sha256'
name: besu-${{ env.RELEASE_VERSION }}.tar.gz.sha256
compression-level: 0
test-windows:
runs-on: windows-2022
needs: ["build"]
timeout-minutes: 5
steps:
- name: Set up Java
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
with:
distribution: temurin
java-version: 21
- name: Download zip
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe
with:
pattern: besu-*.zip
merge-multiple: true
- name: Test
run: |
unzip besu-*.zip -d besu-tmp
cd besu-tmp
mv besu-* ../besu
cd ..
besu\bin\besu.bat --help
besu\bin\besu.bat --version
test-linux:
runs-on: ubuntu-22.04
needs: ["build"]
timeout-minutes: 5
steps:
- name: Set up Java
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
with:
distribution: temurin
java-version: 21
- name: Download tar.gz
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe
with:
pattern: besu-*.tar.gz
merge-multiple: true
- name: Test
run: |
tar zxvf besu-*.tar.gz
rm -f besu-*.tar.gz
mv besu-* besu-test
besu-test/bin/besu --help
besu-test/bin/besu --version
docker-lint:
runs-on: ubuntu-22.04
needs: [test-linux, test-windows]
env:
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_VERSION }}
- name: hadoLint
run: docker run --rm -i hadolint/hadolint < docker/Dockerfile
docker-publish:
needs: [validate, docker-lint]
env:
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} # Use the output from the pre_process_release job
strategy:
fail-fast: false
matrix:
platform:
- ubuntu-22.04
- besu-arm64
runs-on: ${{ matrix.platform }}
steps:
- name: Prepare
id: prep
run: |
platform=${{ matrix.platform }}
if [ "$platform" = 'ubuntu-22.04' ]; then
echo "PLATFORM_PAIR=linux-amd64" >> $GITHUB_OUTPUT
echo "ARCH=amd64" >> $GITHUB_OUTPUT
else
echo "PLATFORM_PAIR=linux-arm64" >> $GITHUB_OUTPUT
echo "ARCH=arm64" >> $GITHUB_OUTPUT
fi
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ env.RELEASE_VERSION }}
- name: short sha
id: shortSha
run: echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- 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: install goss
run: |
mkdir -p docker/reports
curl -L https://github.com/aelsabbahy/goss/releases/download/v0.4.4/goss-${{ steps.prep.outputs.PLATFORM_PAIR }} -o ./docker/tests/goss-${{ steps.prep.outputs.PLATFORM_PAIR }}
- name: login to ${{ env.registry }}
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
with:
registry: ${{ env.registry }}
username: ${{ secrets.DOCKER_USER_RW }}
password: ${{ secrets.DOCKER_PASSWORD_RW }}
- name: build and test docker
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
env:
architecture: ${{ steps.prep.outputs.ARCH }}
with:
cache-disabled: true
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_VERSION}} -Prelease.releaseVersion=${{ env.RELEASE_VERSION }}
docker-manifest:
needs: [validate, docker-publish]
runs-on: ubuntu-22.04
env:
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
steps:
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
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: login to ${{ env.registry }}
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
with:
registry: ${{ env.registry }}
username: ${{ secrets.DOCKER_USER_RW }}
password: ${{ secrets.DOCKER_PASSWORD_RW }}
- name: multi-arch docker
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:
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: Verify besu container
run: bash .github/workflows/BesuContainerVerify.sh
env:
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
needs: [validate, test-linux, test-windows]
permissions:
contents: write
env:
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
steps:
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ env.RELEASE_VERSION }}
- name: Download Besu artifacts
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe
with:
pattern: besu-${{env.RELEASE_VERSION}}*
merge-multiple: true
- name: Draft release notes
run: |
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_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_VERSION}} \
--notes-file draft-release-notes.md \
--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 }}
artifactory:
runs-on: ubuntu-22.04
needs: [validate, test-linux, test-windows]
env:
RELEASE_VERSION: ${{ needs.validate.outputs.release_version }}
steps:
- name: checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
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: Artifactory Publish
env:
ARTIFACTORY_USER: ${{ secrets.BESU_ARTIFACTORY_USER }}
ARTIFACTORY_KEY: ${{ secrets.BESU_ARTIFACTORY_TOKEN }}
run: ./gradlew -Prelease.releaseVersion=${{ env.RELEASE_VERSION }} -Pversion=${{env.RELEASE_VERSION}} artifactoryPublish

@ -1,316 +0,0 @@
name: release
on:
release:
types: [released]
env:
registry: docker.io
GRADLE_OPTS: "-Dorg.gradle.parallel=true -Dorg.gradle.caching=true"
jobs:
preprocess_release:
runs-on: ubuntu-22.04
steps:
- name: Pre-process Release Name
id: pre_process_release_name
env:
RELEASE_NAME: "${{ github.event.release.name }}"
run: |
# strip all whitespace
RELEASE_NAME="${RELEASE_NAME//[[:space:]]/}"
if [[ ! "$RELEASE_NAME" =~ ^[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
outputs:
release_name: ${{ steps.pre_process_release_name.outputs.release_name }}
artifacts:
runs-on: ubuntu-22.04
needs: preprocess_release
env:
RELEASE_NAME: ${{ needs.preprocess_release.outputs.release_name }} # Use the output from the pre_process_release job
permissions:
contents: write
outputs:
tarSha: ${{steps.hashes.outputs.tarSha}}
zipSha: ${{steps.hashes.outputs.zipSha}}
steps:
- name: checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- 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
- name: hashes
id: hashes
run: |
cd build/distributions
echo "zipSha=$(shasum -a 256 besu*.zip)"
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
- name: upload tarball
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with:
path: 'build/distributions/besu*.tar.gz'
name: besu-${{ env.RELEASE_NAME }}.tar.gz
compression-level: 0
- name: upload zipfile
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with:
path: 'build/distributions/besu*.zip'
name: besu-${{ env.RELEASE_NAME }}.zip
compression-level: 0
testWindows:
runs-on: windows-2022
needs: artifacts
timeout-minutes: 10
steps:
- name: Set up Java
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
with:
distribution: temurin
java-version: 21
- name: Download zip
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe
with:
pattern: besu-*.zip
merge-multiple: true
- name: test Besu
run: |
dir
unzip besu-*.zip -d besu-tmp
cd besu-tmp
mv besu-* ../besu
cd ..
besu\bin\besu.bat --help
besu\bin\besu.bat --version
publish:
runs-on: ubuntu-22.04
needs: [preprocess_release, testWindows, artifacts]
env:
RELEASE_NAME: ${{ needs.preprocess_release.outputs.release_name }} # Use the output from the pre_process_release job
permissions:
contents: write
steps:
- name: Download archives
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe
with:
pattern: besu-*
merge-multiple: true
path: 'build/distributions'
- name: Upload Release assets
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844
with:
append_body: true
files: |
build/distributions/besu*.tar.gz
build/distributions/besu*.zip
body: |
${{needs.artifacts.outputs.tarSha}}
${{needs.artifacts.outputs.zipSha}}
artifactoryPublish:
runs-on: ubuntu-22.04
needs: [preprocess_release, artifacts]
env:
RELEASE_NAME: ${{ needs.preprocess_release.outputs.release_name }} # Use the output from the pre_process_release job
steps:
- name: checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- 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: Artifactory Publish
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
hadolint:
runs-on: ubuntu-22.04
steps:
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- 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: hadoLint
run: docker run --rm -i hadolint/hadolint < docker/Dockerfile
buildDocker:
needs: [preprocess_release, hadolint]
env:
RELEASE_NAME: ${{ needs.preprocess_release.outputs.release_name }} # Use the output from the pre_process_release job
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
platform:
- ubuntu-22.04
- besu-arm64
runs-on: ${{ matrix.platform }}
steps:
- name: Prepare
id: prep
run: |
platform=${{ matrix.platform }}
if [ "$platform" = 'ubuntu-22.04' ]; then
echo "PLATFORM_PAIR=linux-amd64" >> $GITHUB_OUTPUT
echo "ARCH=amd64" >> $GITHUB_OUTPUT
else
echo "PLATFORM_PAIR=linux-arm64" >> $GITHUB_OUTPUT
echo "ARCH=arm64" >> $GITHUB_OUTPUT
fi
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: short sha
id: shortSha
run: echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- 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: install goss
run: |
mkdir -p docker/reports
curl -L https://github.com/aelsabbahy/goss/releases/download/v0.4.4/goss-${{ steps.prep.outputs.PLATFORM_PAIR }} -o ./docker/tests/goss-${{ steps.prep.outputs.PLATFORM_PAIR }}
- name: login to ${{ env.registry }}
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
with:
registry: ${{ env.registry }}
username: ${{ secrets.DOCKER_USER_RW }}
password: ${{ secrets.DOCKER_PASSWORD_RW }}
- name: build and test docker
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
env:
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 }}
- 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 }}
multiArch:
needs: [preprocess_release, buildDocker]
env:
RELEASE_NAME: ${{ needs.preprocess_release.outputs.release_name }} # Use the output from the pre_process_release job
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
steps:
- name: Checkout Repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- 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: login to ${{ env.registry }}
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
with:
registry: ${{ env.registry }}
username: ${{ secrets.DOCKER_USER_RW }}
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 }}
amendNotes:
needs: [preprocess_release, multiArch]
env:
RELEASE_NAME: ${{ needs.preprocess_release.outputs.release_name }} # Use the output from the pre_process_release job
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: add pull command to release notes
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844
with:
append_body: true
body: |
`docker pull ${{env.registry}}/${{secrets.DOCKER_ORG}}/besu:${{env.RELEASE_NAME}}`
dockerPromoteX64:
needs: [preprocess_release, multiArch]
env:
RELEASE_NAME: ${{ needs.preprocess_release.outputs.release_name }} # Use the output from the pre_process_release job
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
with:
distribution: temurin
java-version: 21
cache: gradle
- name: login to ${{ env.registry }}
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
with:
registry: ${{ env.registry }}
username: ${{ secrets.DOCKER_USER_RW }}
password: ${{ secrets.DOCKER_PASSWORD_RW }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1
with:
cache-disabled: true
- name: Docker upload
run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_NAME }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" dockerUploadRelease
- name: Docker manifest
run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_NAME }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" manifestDockerRelease
verifyContainer:
needs: [preprocess_release, dockerPromoteX64]
env:
RELEASE_NAME: ${{ needs.preprocess_release.outputs.release_name }} # Use the output from the pre_process_release job
runs-on: ubuntu-22.04
permissions:
contents: read
actions: write
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Trigger container verify
run: echo '{"version":"${{ env.RELEASE_NAME }}","verify-latest-version":"true"}' | gh workflow run container-verify.yml --json
env:
GH_TOKEN: ${{ github.token }}

@ -15,6 +15,8 @@
- LUKSO Cancun Hardfork [#7686](https://github.com/hyperledger/besu/pull/7686)
- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647)
- 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)
### Bug fixes
- Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575)

@ -9,19 +9,16 @@
| Name | Github | LFID |
| ---------------- | ---------------- | ---------------- |
| Ameziane Hamlat | ahamlat | ahamlat |
| Adrian Sutton | ajsutton | ajsutton |
| Antony Denyer | antonydenyer | antonydenyer |
| Antoine Toulme | atoulme | atoulme |
| Daniel Lehrner | daniellehrner | daniellehrner |
| Diego López León | diega | diega |
| Fabio Di Fabio | fab-10 | fab-10 |
| Gabriel Trintinalia | gabriel-trintinalia | gabrieltrintinalia |
| Gary Schulte | garyschulte | GarySchulte |
| Jiri Peinlich | gezero | JiriPeinlich |
| Gabriel Fukushima| gfukushima | gfukushima |
| Justin Florentine| jflo | RoboCopsGoneMad |
| Jason Frame | jframe | jframe |
| Joshua Fernandes | joshuafernandes | joshuafernandes |
| Luis Pinto | lu-pinto | lu-pinto
| Lucas Saldanha | lucassaldanha | lucassaldanha |
| Sally MacFarlane | macfarla | macfarla |
| Karim Taam | matkt | matkt |
@ -37,11 +34,15 @@
| Name | Github | LFID |
|------------------|------------------|------------------|
| Abdel Bakhta | abdelhamidbakhta | abdelhamidbakhta |
| Adrian Sutton | ajsutton | ajsutton |
| Antony Denyer | antonydenyer | antonydenyer |
| Antoine Toulme | atoulme | atoulme |
| Byron Gravenorst | bgravenorst | bgravenorst |
| Chris Hare | CjHare | cjhare |
| David Mechler | davemec | davemec |
| Edward Evans | EdJoJob | EdJoJob |
| Edward Mack | edwardmack | mackcom |
| Jiri Peinlich | gezero | JiriPeinlich |
| Frank Li | frankisawesome | frankliawesome |
| Ivaylo Kirilov | iikirilov | iikirilov |
| Madeline Murray | MadelineMurray | madelinemurray |

@ -128,6 +128,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
private boolean useWsForJsonRpc = false;
private String token = null;
private final List<String> plugins = new ArrayList<>();
private final List<String> requestedPlugins;
private final List<String> extraCLIOptions;
private final List<String> staticNodes;
private boolean isDnsEnabled = false;
@ -163,6 +164,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
final boolean secp256k1Native,
final boolean altbn128Native,
final List<String> plugins,
final List<String> requestedPlugins,
final List<String> extraCLIOptions,
final List<String> staticNodes,
final boolean isDnsEnabled,
@ -224,6 +226,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
LOG.error("Could not find plugin \"{}\" in resources", pluginName);
}
});
this.requestedPlugins = requestedPlugins;
engineRpcConfiguration.ifPresent(
config -> MergeConfigOptions.setMergeEnabled(config.isEnabled()));
this.extraCLIOptions = extraCLIOptions;
@ -738,6 +741,10 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
return plugins;
}
public List<String> getRequestedPlugins() {
return requestedPlugins;
}
@Override
public List<String> getExtraCLIOptions() {
return extraCLIOptions;

@ -17,8 +17,8 @@ package org.hyperledger.besu.tests.acceptance.dsl.node;
import static com.google.common.base.Preconditions.checkState;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.hyperledger.besu.cli.options.DataStorageOptions;
import org.hyperledger.besu.cli.options.TransactionPoolOptions;
import org.hyperledger.besu.cli.options.stable.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;
@ -451,6 +451,11 @@ public class ProcessBesuNodeRunner implements BesuNodeRunner {
params.add("--logging=" + level);
}
if (!node.getRequestedPlugins().isEmpty()) {
params.add(
"--plugins=" + node.getRequestedPlugins().stream().collect(Collectors.joining(",")));
}
params.addAll(node.getRunCommand());
return params;
}

@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.plugins.PluginConfiguration;
import org.hyperledger.besu.ethereum.core.plugins.PluginInfo;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule;
@ -302,6 +303,12 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
return toProvide.getExtraCLIOptions();
}
@Provides
@Named("RequestedPlugins")
public List<String> provideRequestedPlugins() {
return toProvide.getRequestedPlugins();
}
@Provides
Path provideDataDir() {
return toProvide.homeDirectory();
@ -469,7 +476,8 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
final RpcEndpointServiceImpl rpcEndpointServiceImpl,
final BesuConfiguration commonPluginConfiguration,
final PermissioningServiceImpl permissioningService,
final @Named("ExtraCLIOptions") List<String> extraCLIOptions) {
final @Named("ExtraCLIOptions") List<String> extraCLIOptions,
final @Named("RequestedPlugins") List<String> requestedPlugins) {
final CommandLine commandLine = new CommandLine(CommandSpec.create());
final BesuPluginContextImpl besuPluginContext = new BesuPluginContextImpl();
besuPluginContext.addService(StorageService.class, storageService);
@ -504,7 +512,10 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
besuPluginContext.addService(PrivacyPluginService.class, new PrivacyPluginServiceImpl());
besuPluginContext.initialize(
new PluginConfiguration.Builder().pluginsDir(pluginsPath).build());
new PluginConfiguration.Builder()
.pluginsDir(pluginsPath)
.requestedPlugins(requestedPlugins.stream().map(PluginInfo::new).toList())
.build());
besuPluginContext.registerPlugins();
commandLine.parseArgs(extraCLIOptions.toArray(new String[0]));

@ -64,6 +64,7 @@ public class BesuNodeConfiguration {
private final boolean secp256k1Native;
private final boolean altbn128Native;
private final List<String> plugins;
private final List<String> requestedPlugins;
private final List<String> extraCLIOptions;
private final List<String> staticNodes;
private final boolean isDnsEnabled;
@ -102,6 +103,7 @@ public class BesuNodeConfiguration {
final boolean secp256k1Native,
final boolean altbn128Native,
final List<String> plugins,
final List<String> requestedPlugins,
final List<String> extraCLIOptions,
final List<String> staticNodes,
final boolean isDnsEnabled,
@ -137,6 +139,7 @@ public class BesuNodeConfiguration {
this.secp256k1Native = secp256k1Native;
this.altbn128Native = altbn128Native;
this.plugins = plugins;
this.requestedPlugins = requestedPlugins;
this.extraCLIOptions = extraCLIOptions;
this.staticNodes = staticNodes;
this.isDnsEnabled = isDnsEnabled;
@ -239,6 +242,10 @@ public class BesuNodeConfiguration {
return plugins;
}
public List<String> getRequestedPlugins() {
return requestedPlugins;
}
public List<String> getExtraCLIOptions() {
return extraCLIOptions;
}

@ -93,6 +93,7 @@ public class BesuNodeConfigurationBuilder {
private boolean secp256K1Native = true;
private boolean altbn128Native = true;
private final List<String> plugins = new ArrayList<>();
private final List<String> requestedPlugins = new ArrayList<>();
private final List<String> extraCLIOptions = new ArrayList<>();
private List<String> staticNodes = new ArrayList<>();
private boolean isDnsEnabled = false;
@ -448,6 +449,12 @@ public class BesuNodeConfigurationBuilder {
return this;
}
public BesuNodeConfigurationBuilder requestedPlugins(final List<String> requestedPlugins) {
this.requestedPlugins.clear();
this.requestedPlugins.addAll(requestedPlugins);
return this;
}
public BesuNodeConfigurationBuilder extraCLIOptions(final List<String> extraCLIOptions) {
this.extraCLIOptions.clear();
this.extraCLIOptions.addAll(extraCLIOptions);
@ -545,6 +552,7 @@ public class BesuNodeConfigurationBuilder {
secp256K1Native,
altbn128Native,
plugins,
requestedPlugins,
extraCLIOptions,
staticNodes,
isDnsEnabled,

@ -77,6 +77,7 @@ public class BesuNodeFactory {
config.isSecp256k1Native(),
config.isAltbn128Native(),
config.getPlugins(),
config.getRequestedPlugins(),
config.getExtraCLIOptions(),
config.getStaticNodes(),
config.isDnsEnabled(),

@ -24,7 +24,6 @@ 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,22 +37,22 @@ 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.DataStorageOptions;
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.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;
@ -67,6 +66,7 @@ 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;
@ -124,6 +124,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;
@ -209,7 +210,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;
@ -247,7 +247,6 @@ 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;
@ -416,7 +415,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 +425,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 +491,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();
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;
EngineRPCOptions engineRPCOptions = new EngineRPCOptions();
@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")
@ -1409,13 +1220,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,
@ -1614,7 +1425,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private void validateOptions() {
validateRequiredOptions();
issueOptionWarnings();
validateP2PInterface(p2PDiscoveryOptionGroup.p2pInterface);
validateP2PInterface(p2PDiscoveryOptions.p2pInterface);
validateMiningParams();
validateNatParams();
validateNetStatsParams();
@ -1750,13 +1561,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).");
@ -1820,7 +1630,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
logger,
commandLine,
"--p2p-enabled",
!p2PDiscoveryOptionGroup.p2pEnabled,
!p2PDiscoveryOptions.p2pEnabled,
asList(
"--bootnodes",
"--discovery-enabled",
@ -1861,6 +1671,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private void configure() throws Exception {
p2PDiscoveryConfig = p2PDiscoveryOptions.toDomainObject();
engineRPCConfig = engineRPCOptions.toDomainObject();
checkPortClash();
checkIfRequiredPortsAreAvailable();
syncMode = getDefaultSyncModeIfNotSet();
@ -1870,25 +1682,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(),
@ -2008,32 +1813,31 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.requiredBlocks(requiredBlocks)
.reorgLoggingThreshold(reorgLoggingThreshold)
.evmConfiguration(unstableEvmOptions.toDomainObject())
.maxPeers(p2PDiscoveryOptionGroup.maxPeers)
.maxPeers(p2PDiscoveryOptions.maxPeers)
.maxRemotelyInitiatedPeers(maxRemoteInitiatedPeers)
.randomPeerPriority(p2PDiscoveryOptionGroup.randomPeerPriority)
.randomPeerPriority(p2PDiscoveryOptions.randomPeerPriority)
.chainPruningConfiguration(unstableChainPruningOptions.toDomainObject())
.cacheLastBlocks(numberOfblocksToCache)
.genesisStateHashCacheEnabled(genesisStateHashCacheEnabled)
.besuComponent(besuComponent);
}
private JsonRpcConfiguration createEngineJsonRpcConfiguration(
final Integer engineListenPort, final List<String> allowCallsFrom) {
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");
@ -2090,7 +1894,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.enabled(metricsOptionGroup.getMetricsEnabled())
.host(
Strings.isNullOrEmpty(metricsOptionGroup.getMetricsHost())
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
? p2PDiscoveryOptions.p2pHost
: metricsOptionGroup.getMetricsHost())
.port(metricsOptionGroup.getMetricsPort())
.protocol(metricsOptionGroup.getMetricsProtocol())
@ -2098,7 +1902,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.pushEnabled(metricsOptionGroup.getMetricsPushEnabled())
.pushHost(
Strings.isNullOrEmpty(metricsOptionGroup.getMetricsPushHost())
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
? p2PDiscoveryOptions.autoDiscoverDefaultIP().getHostAddress()
: metricsOptionGroup.getMetricsPushHost())
.pushPort(metricsOptionGroup.getMetricsPushPort())
.pushInterval(metricsOptionGroup.getMetricsPushInterval())
@ -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);
@ -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);
@ -2541,8 +2345,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
builder.setNetworkId(networkId);
}
if (p2PDiscoveryOptionGroup.discoveryDnsUrl != null) {
builder.setDnsDiscoveryUrl(p2PDiscoveryOptionGroup.discoveryDnsUrl);
if (p2PDiscoveryOptions.discoveryDnsUrl != null) {
builder.setDnsDiscoveryUrl(p2PDiscoveryOptions.discoveryDnsUrl);
} else {
final Optional<String> discoveryDnsUrlFromGenesis =
genesisConfigOptionsSupplier.get().getDiscoveryOptions().getDiscoveryDnsUrl();
@ -2550,9 +2354,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 +2368,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 +2503,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,15 +2528,14 @@ 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(),
@ -2859,7 +2662,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
private boolean isEngineApiEnabled() {
return engineRPCOptionGroup.overrideEngineRpcEnabled || isMergeEnabled();
return engineRPCConfig.overrideEngineRpcEnabled() || isMergeEnabled();
}
private SyncMode getDefaultSyncModeIfNotSet() {

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
package org.hyperledger.besu.cli.options;
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;
@ -22,7 +22,6 @@ import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.
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;

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

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

@ -52,6 +52,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"},
@ -265,37 +266,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.
*

@ -30,6 +30,7 @@ import java.util.Set;
import picocli.CommandLine;
/** Command line options for configuring metrics. */
// TODO: implement CLIOption<MetricsConfiguration> and rename to drop the Group
public class MetricsOptionGroup {
@CommandLine.Option(
names = {"--metrics-enabled"},

@ -0,0 +1,238 @@
/*
* 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 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.
@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"},

@ -23,6 +23,7 @@ import java.util.List;
import picocli.CommandLine;
/** The Metrics cli options. */
// TODO: combine into MetricsOptionGroup, use Unstable inner class pattern (see MiningOptions)
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";

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

@ -15,11 +15,11 @@
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.DataStorageOptions.BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD;
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 org.hyperledger.besu.cli.options.stable.DataStorageOptions;
import org.hyperledger.besu.cli.options.DataStorageOptions;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;

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

@ -30,6 +30,7 @@ import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.plugin.data.TransactionReceipt;
import org.hyperledger.besu.plugin.services.BlockchainService;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
@ -182,4 +183,12 @@ public class BlockchainServiceImpl implements BlockchainService {
}
};
}
@Override
public Optional<BigInteger> getChainId() {
if (protocolSchedule == null) {
return Optional.empty();
}
return protocolSchedule.getChainId();
}
}

@ -34,9 +34,9 @@ import org.hyperledger.besu.chainexport.RlpBlockExporter;
import org.hyperledger.besu.chainimport.JsonBlockImporter;
import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.options.DataStorageOptions;
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.unstable.EthProtocolOptions;
import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions;

@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT;
import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest;
import org.hyperledger.besu.cli.options.DataStorageOptions;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;

@ -690,7 +690,7 @@ startScripts {
"-XX:G1ConcRefinementThreads=2",
"-XX:G1HeapWastePercent=15",
"-XX:MaxGCPauseMillis=100",
"-XX:StartFlightRecording,dumponexit=true,settings=default.jfc",
"-XX:StartFlightRecording,settings=default.jfc",
"-Xlog:jfr*=off"
]
unixStartScriptGenerator.template = resources.text.fromFile("${projectDir}/besu/src/main/scripts/unixStartScript.txt")

@ -17,6 +17,8 @@ package org.hyperledger.besu.config;
import java.util.concurrent.atomic.AtomicBoolean;
/** The Merge config options. */
// TODO: naming this with Options as the suffix is misleading, it should be MergeConfig - doesn't
// use picocli
public class MergeConfigOptions {
private static final AtomicBoolean mergeEnabled = new AtomicBoolean(false);

@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.LogWithMetadata;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@ -292,6 +293,23 @@ public class TransactionAdapter extends AdapterBase {
: Optional.of((long) receipt.getStatus()));
}
/**
* Retrieves the revert reason of the transaction, if any.
*
* <p>This method uses the getReceipt method to get the receipt of the transaction. It then checks
* the revert reason of the receipt. It would be an empty Optional for successful transactions.
* Otherwise, it returns an Optional containing the revert reason.
*
* @param environment the data fetching environment.
* @return an Optional containing a Bytes object representing the revert reason of the
* transaction, or an empty Optional .
*/
public Optional<Bytes> getRevertReason(final DataFetchingEnvironment environment) {
return getReceipt(environment)
.map(TransactionReceiptWithMetadata::getReceipt)
.flatMap(TransactionReceipt::getRevertReason);
}
/**
* Retrieves the gas used by the transaction.
*

@ -579,6 +579,9 @@ type Transaction {
BlobVersionedHashes is a set of hash outputs from the blobs in the transaction.
"""
blobVersionedHashes: [Bytes32!]
"""Reason returned when transaction fails."""
revertReason: Bytes
}
"""EIP-4895"""

@ -230,16 +230,9 @@ public class TransactionSimulator {
final Account sender = updater.get(senderAddress);
final long nonce = sender != null ? sender.getNonce() : 0L;
long gasLimit =
callParams.getGasLimit() >= 0
? callParams.getGasLimit()
: blockHeaderToProcess.getGasLimit();
if (rpcGasCap > 0) {
gasLimit = rpcGasCap;
LOG.trace(
"Gas limit capped at {} for transaction simulation due to provided RPC gas cap.",
rpcGasCap);
}
final long simulationGasCap =
calculateSimulationGasCap(callParams.getGasLimit(), blockHeaderToProcess.getGasLimit());
final Wei value = callParams.getValue() != null ? callParams.getValue() : Wei.ZERO;
final Bytes payload = callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY;
@ -265,7 +258,7 @@ public class TransactionSimulator {
header,
senderAddress,
nonce,
gasLimit,
simulationGasCap,
value,
payload,
blobGasPrice);
@ -291,6 +284,38 @@ public class TransactionSimulator {
return Optional.of(new TransactionSimulatorResult(transaction, result));
}
private long calculateSimulationGasCap(
final long userProvidedGasLimit, final long blockGasLimit) {
final long simulationGasCap;
// when not set gas limit is -1
if (userProvidedGasLimit >= 0) {
if (rpcGasCap > 0 && userProvidedGasLimit > rpcGasCap) {
LOG.trace(
"User provided gas limit {} is bigger than the value of rpc-gas-cap {}, setting simulation gas cap to the latter",
userProvidedGasLimit,
rpcGasCap);
simulationGasCap = rpcGasCap;
} else {
LOG.trace("Using provided gas limit {} set as simulation gas cap", userProvidedGasLimit);
simulationGasCap = userProvidedGasLimit;
}
} else {
if (rpcGasCap > 0) {
LOG.trace(
"No user provided gas limit, setting simulation gas cap to the value of rpc-gas-cap {}",
rpcGasCap);
simulationGasCap = rpcGasCap;
} else {
simulationGasCap = blockGasLimit;
LOG.trace(
"No user provided gas limit and rpc-gas-cap options is not set, setting simulation gas cap to block gas limit {}",
blockGasLimit);
}
}
return simulationGasCap;
}
private Optional<Transaction> buildTransaction(
final CallParameter callParams,
final TransactionValidationParams transactionValidationParams,

@ -79,7 +79,8 @@ public class TransactionSimulatorTest {
private static final Address DEFAULT_FROM =
Address.fromHexString("0x0000000000000000000000000000000000000000");
private static final long GASCAP = 500L;
private static final long GAS_CAP = 500000L;
private static final long TRANSFER_GAS_LIMIT = 21000L;
private TransactionSimulator transactionSimulator;
private TransactionSimulator cappedTransactionSimulator;
@ -96,7 +97,7 @@ public class TransactionSimulatorTest {
this.transactionSimulator =
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, 0);
this.cappedTransactionSimulator =
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, GASCAP);
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, GAS_CAP);
}
@Test
@ -124,7 +125,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
@ -155,7 +156,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(Wei.ZERO)
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
@ -175,7 +176,8 @@ public class TransactionSimulatorTest {
@Test
public void shouldSetFeePerGasToZeroWhenExceedingBalanceAllowed() {
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ONE, Wei.ONE);
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ONE, Wei.ONE, TRANSFER_GAS_LIMIT);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
@ -187,7 +189,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.gasLimit(TRANSFER_GAS_LIMIT)
.maxFeePerGas(Wei.ZERO)
.maxPriorityFeePerGas(Wei.ZERO)
.to(callParameter.getTo())
@ -223,7 +225,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
@ -244,7 +246,8 @@ public class TransactionSimulatorTest {
@Test
public void shouldNotSetFeePerGasToZeroWhenExceedingBalanceIsNotAllowed() {
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ONE, Wei.ONE);
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ONE, Wei.ONE, TRANSFER_GAS_LIMIT);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
@ -256,7 +259,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.gasLimit(TRANSFER_GAS_LIMIT)
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
@ -349,7 +352,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
@ -390,7 +393,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
@ -479,7 +482,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
@ -509,7 +512,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
@ -530,7 +533,7 @@ public class TransactionSimulatorTest {
@Test
public void shouldCapGasLimitWhenOriginalTransactionExceedsGasCap() {
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GASCAP + 1);
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GAS_CAP + 1);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
@ -542,7 +545,7 @@ public class TransactionSimulatorTest {
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(GASCAP)
.gasLimit(GAS_CAP)
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
@ -566,11 +569,48 @@ public class TransactionSimulatorTest {
}
@Test
public void shouldUseRpcGasCapWhenCapIsHigherThanGasLimit() {
// generate a transaction with a gas limit that is lower than the gas cap,
// expect the gas cap to override parameter gas limit
public void shouldUseProvidedGasLimitWhenBelowRpcCapGas() {
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GASCAP - 1);
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GAS_CAP / 2);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
mockBlockchainForBlockHeader(blockHeader);
mockWorldStateForAccount(blockHeader, callParameter.getFrom(), 1L);
final Transaction expectedTransaction =
Transaction.builder()
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(GAS_CAP / 2)
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
.payload(callParameter.getPayload())
.signature(FAKE_SIGNATURE)
.build();
mockProtocolSpecForProcessWithWorldUpdater();
// call process with original transaction
cappedTransactionSimulator.process(
callParameter,
TransactionValidationParams.transactionSimulator(),
OperationTracer.NO_TRACING,
1L);
// expect overwritten transaction to be processed
verifyTransactionWasProcessed(expectedTransaction);
}
@Test
public void shouldUseRpcGasCapWhenGasLimitNoPresent() {
// generate call parameters that do not specify a gas limit,
// expect the rpc gas cap to be used for simulation
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, -1);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
@ -591,7 +631,7 @@ public class TransactionSimulatorTest {
.value(callParameter.getValue())
.payload(callParameter.getPayload())
.signature(FAKE_SIGNATURE)
.gasLimit(GASCAP)
.gasLimit(GAS_CAP)
.build();
// call process with original transaction
@ -781,7 +821,7 @@ public class TransactionSimulatorTest {
return new CallParameter(
Address.fromHexString("0x0"),
Address.fromHexString("0x0"),
0,
-1,
gasPrice,
Wei.of(0),
Bytes.EMPTY);
@ -793,7 +833,7 @@ public class TransactionSimulatorTest {
private CallParameter eip1559TransactionCallParameter(
final Wei maxFeePerGas, final Wei maxPriorityFeePerGas) {
return eip1559TransactionCallParameter(maxFeePerGas, maxPriorityFeePerGas, 0L);
return eip1559TransactionCallParameter(maxFeePerGas, maxPriorityFeePerGas, -1);
}
private CallParameter eip1559TransactionCallParameter(

@ -16,7 +16,6 @@ package org.hyperledger.besu.ethereum.eth.sync.snapsync.request;
import static org.hyperledger.besu.ethereum.eth.sync.snapsync.RequestType.STORAGE_RANGE;
import static org.hyperledger.besu.ethereum.eth.sync.snapsync.StackTrie.FlatDatabaseUpdater.noop;
import static org.hyperledger.besu.ethereum.trie.RangeManager.MAX_RANGE;
import static org.hyperledger.besu.ethereum.trie.RangeManager.MIN_RANGE;
import static org.hyperledger.besu.ethereum.trie.RangeManager.findNewBeginElementInRange;
import static org.hyperledger.besu.ethereum.trie.RangeManager.getRangeCount;
@ -192,12 +191,13 @@ public class StorageRangeDataRequest extends SnapDataRequest {
getRootHash(), accountHash, storageRoot, key, value);
childRequests.add(storageRangeDataRequest);
});
if (startKeyHash.equals(MIN_RANGE) && endKeyHash.equals(MAX_RANGE)) {
// need to heal this account storage
downloadState.addAccountToHealingList(CompactEncoding.bytesToPath(accountHash));
}
});
if (startKeyHash.equals(MIN_RANGE) && !taskElement.proofs().isEmpty()) {
// need to heal this account storage
downloadState.addAccountToHealingList(CompactEncoding.bytesToPath(accountHash));
}
return childRequests.stream();
}

@ -64,9 +64,7 @@ public class AccountHealingTrackingTest {
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG);
private WorldStateStorageCoordinator worldStateStorageCoordinator;
private WorldStateProofProvider worldStateProofProvider;
private MerkleTrie<Bytes, Bytes> accountStateTrie;
@Mock SnapWorldDownloadState snapWorldDownloadState;
@ -82,9 +80,7 @@ public class AccountHealingTrackingTest {
}
@Test
void avoidMarkingAccountWhenStorageProofValid() {
// generate valid proof
void shouldMarkAccountForHealingWhenStorageProofIsReceived() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
@ -108,7 +104,7 @@ public class AccountHealingTrackingTest {
root ->
RangeStorageEntriesCollector.collectEntries(
collector, visitor, root, Hash.ZERO));
// generate the proof
final List<Bytes> proofs =
worldStateProofProvider.getStorageProofRelatedNodes(
Hash.wrap(storageTrie.getRootHash()), accountHash, Hash.ZERO);
@ -127,11 +123,53 @@ public class AccountHealingTrackingTest {
snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>(proofs));
storageRangeDataRequest.getChildRequests(
snapWorldDownloadState, worldStateStorageCoordinator, null);
verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class));
}
@Test
void shouldNotMarkAccountForHealingWhenAllStorageIsReceivedWithoutProof() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
new StoredMerklePatriciaTrie<>(
new StoredNodeFactory<>(
(location, hash) ->
worldStateKeyValueStorage.getAccountStorageTrieNode(
accountHash, location, hash),
Function.identity(),
Function.identity()),
stateTrieAccountValue.getStorageRoot());
final RangeStorageEntriesCollector collector =
RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 10, Integer.MAX_VALUE);
final TrieIterator<Bytes> visitor = RangeStorageEntriesCollector.createVisitor(collector);
final TreeMap<Bytes32, Bytes> slots =
(TreeMap<Bytes32, Bytes>)
storageTrie.entriesFrom(
root ->
RangeStorageEntriesCollector.collectEntries(
collector, visitor, root, Hash.ZERO));
final StorageRangeDataRequest storageRangeDataRequest =
SnapDataRequest.createStorageRangeDataRequest(
Hash.wrap(accountStateTrie.getRootHash()),
accountHash,
storageTrie.getRootHash(),
Hash.ZERO,
MAX_RANGE);
storageRangeDataRequest.addResponse(
snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>());
storageRangeDataRequest.getChildRequests(
snapWorldDownloadState, worldStateStorageCoordinator, null);
verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class));
}
@Test
void markAccountOnInvalidStorageProof() {
void shouldMarkAccountForHealingOnInvalidStorageProof() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
@ -157,8 +195,7 @@ public class AccountHealingTrackingTest {
}
@Test
void markAccountOnPartialStorageRange() {
// generate valid proof
void shouldMarkAccountForHealingOnInvalidStorageWithoutProof() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
@ -174,11 +211,46 @@ public class AccountHealingTrackingTest {
stateTrieAccountValue.getStorageRoot());
final RangeStorageEntriesCollector collector =
RangeStorageEntriesCollector.createCollector(
RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 1, Integer.MAX_VALUE);
final TrieIterator<Bytes> visitor = RangeStorageEntriesCollector.createVisitor(collector);
final TreeMap<Bytes32, Bytes> slots =
(TreeMap<Bytes32, Bytes>)
storageTrie.entriesFrom(
root ->
RangeStorageEntriesCollector.collectEntries(
collector, visitor, root, Hash.ZERO));
final StorageRangeDataRequest storageRangeDataRequest =
SnapDataRequest.createStorageRangeDataRequest(
Hash.wrap(accountStateTrie.getRootHash()),
accountHash,
storageTrie.getRootHash(),
Hash.ZERO,
MAX_RANGE,
1,
Integer.MAX_VALUE); // limit to 1 in order to have a partial range
MAX_RANGE);
storageRangeDataRequest.addResponse(
snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>());
verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class));
}
@Test
void shouldMarkAccountForHealingOnPartialStorageRange() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
new StoredMerklePatriciaTrie<>(
new StoredNodeFactory<>(
(location, hash) ->
worldStateKeyValueStorage.getAccountStorageTrieNode(
accountHash, location, hash),
Function.identity(),
Function.identity()),
stateTrieAccountValue.getStorageRoot());
final RangeStorageEntriesCollector collector =
RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 1, Integer.MAX_VALUE);
final TrieIterator<Bytes> visitor = RangeStorageEntriesCollector.createVisitor(collector);
final TreeMap<Bytes32, Bytes> slots =
(TreeMap<Bytes32, Bytes>)
@ -186,7 +258,7 @@ public class AccountHealingTrackingTest {
root ->
RangeStorageEntriesCollector.collectEntries(
collector, visitor, root, Hash.ZERO));
// generate the proof
final List<Bytes> proofs =
worldStateProofProvider.getStorageProofRelatedNodes(
Hash.wrap(storageTrie.getRootHash()), accountHash, Hash.ZERO);
@ -205,14 +277,14 @@ public class AccountHealingTrackingTest {
snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>(proofs));
verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class));
// should mark during the getchild request
storageRangeDataRequest.getChildRequests(
snapWorldDownloadState, worldStateStorageCoordinator, null);
verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class));
}
@Test
void avoidMarkingAccountOnValidStorageTrieNodeDetection() {
void shouldNotMarkAccountForHealingOnValidStorageTrieNodeDetection() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
@ -223,6 +295,7 @@ public class AccountHealingTrackingTest {
Hash.wrap(accountStateTrie.getRootHash()),
Bytes.EMPTY);
storageTrieNodeHealingRequest.getExistingData(worldStateStorageCoordinator);
verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class));
}
}

@ -0,0 +1,39 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery;
import org.hyperledger.besu.util.number.Percentage;
import java.util.Collection;
import java.util.List;
import org.apache.commons.net.util.SubnetUtils;
import org.apache.tuweni.bytes.Bytes;
public record P2PDiscoveryConfiguration(
Boolean p2pEnabled,
Boolean peerDiscoveryEnabled,
String p2pHost,
String p2pInterface,
Integer p2pPort,
Integer maxPeers,
Boolean isLimitRemoteWireConnectionsEnabled,
Percentage maxRemoteConnectionsPercentage,
Boolean randomPeerPriority,
Collection<Bytes> bannedNodeIds,
List<SubnetUtils.SubnetInfo> allowedSubnets,
Boolean poaDiscoveryRetryBootnodes,
List<String> bootNodes,
String discoveryDnsUrl) {}

@ -14,8 +14,6 @@
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import static org.assertj.core.api.Assertions.assertThat;
import java.security.Security;
import java.util.concurrent.atomic.AtomicInteger;
@ -26,7 +24,6 @@ import io.vertx.junit5.Checkpoint;
import io.vertx.junit5.VertxExtension;
import io.vertx.junit5.VertxTestContext;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
@ -136,10 +133,4 @@ class DNSDaemonTest {
.setWorkerPoolSize(1);
vertx.deployVerticle(dnsDaemon, options);
}
@AfterEach
@DisplayName("Check that the vertx worker verticle is still there")
void lastChecks(final Vertx vertx) {
assertThat(vertx.deploymentIDs()).isNotEmpty().hasSize(2);
}
}

@ -16,6 +16,7 @@ package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToInt;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
@ -37,6 +38,11 @@ public class ReturnDataLoadOperation extends AbstractOperation {
@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
Code code = frame.getCode();
if (code.getEofVersion() == 0) {
return InvalidOperation.INVALID_RESULT;
}
final int offset = clampedToInt(frame.popStackItem());
Bytes returnData = frame.getReturnData();
int retunDataSize = returnData.size();

@ -71,7 +71,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files
knownHash = '5H+3gUzCwZtLByfnk11kf+kAPwykQ+WR+n3xWgyfsyY='
knownHash = '4jVaj9yW88nHbX0KmTR3dPQRvj9x8Pvh5E9Ry7KRT6w='
}
check.dependsOn('checkAPIChanges')

@ -22,6 +22,7 @@ import org.hyperledger.besu.plugin.data.BlockContext;
import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.plugin.data.TransactionReceipt;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
@ -106,5 +107,11 @@ public interface BlockchainService extends BesuService {
* @throws UnsupportedOperationException if the network is a PoS network
*/
void setSafeBlock(Hash blockHash) throws IllegalArgumentException, UnsupportedOperationException;
;
/**
* Get the chain id
*
* @return the chain id
*/
Optional<BigInteger> getChainId();
}

Loading…
Cancel
Save