mirror of https://github.com/hyperledger/besu
# Conflicts: # ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java # ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutorTest.javapull/7638/head
commit
fae39a8db7
@ -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 }} |
@ -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()); |
||||
} |
||||
} |
@ -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()); |
||||
} |
||||
} |
@ -1,102 +0,0 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.peertask; |
||||
|
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; |
||||
import org.hyperledger.besu.ethereum.p2p.peers.PeerId; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Comparator; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.function.Predicate; |
||||
import java.util.function.Supplier; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
/** |
||||
* This is a simple PeerSelector implementation that can be used the default implementation in most |
||||
* situations |
||||
*/ |
||||
public class DefaultPeerSelector implements PeerSelector { |
||||
private static final Logger LOG = LoggerFactory.getLogger(DefaultPeerSelector.class); |
||||
|
||||
private final Supplier<ProtocolSpec> protocolSpecSupplier; |
||||
private final Map<PeerId, EthPeer> ethPeersByPeerId = new ConcurrentHashMap<>(); |
||||
|
||||
public DefaultPeerSelector(final Supplier<ProtocolSpec> protocolSpecSupplier) { |
||||
this.protocolSpecSupplier = protocolSpecSupplier; |
||||
} |
||||
|
||||
/** |
||||
* Gets the highest reputation peer matching the supplied filter |
||||
* |
||||
* @param filter a filter to match prospective peers with |
||||
* @return the highest reputation peer matching the supplies filter |
||||
* @throws NoAvailablePeerException If there are no suitable peers |
||||
*/ |
||||
private EthPeer getPeer(final Predicate<EthPeer> filter) throws NoAvailablePeerException { |
||||
LOG.trace("Finding peer from pool of {} peers", ethPeersByPeerId.size()); |
||||
return ethPeersByPeerId.values().stream() |
||||
.filter(filter) |
||||
.max(Comparator.naturalOrder()) |
||||
.orElseThrow(NoAvailablePeerException::new); |
||||
} |
||||
|
||||
@Override |
||||
public EthPeer getPeer( |
||||
final Collection<EthPeer> usedEthPeers, |
||||
final long requiredPeerHeight, |
||||
final SubProtocol requiredSubProtocol) |
||||
throws NoAvailablePeerException { |
||||
return getPeer( |
||||
(candidatePeer) -> |
||||
isPeerUnused(candidatePeer, usedEthPeers) |
||||
&& (protocolSpecSupplier.get().isPoS() |
||||
|| isPeerHeightHighEnough(candidatePeer, requiredPeerHeight)) |
||||
&& isPeerProtocolSuitable(candidatePeer, requiredSubProtocol)); |
||||
} |
||||
|
||||
@Override |
||||
public Optional<EthPeer> getPeerByPeerId(final PeerId peerId) { |
||||
return Optional.ofNullable(ethPeersByPeerId.get(peerId)); |
||||
} |
||||
|
||||
@Override |
||||
public void addPeer(final EthPeer ethPeer) { |
||||
ethPeersByPeerId.put(ethPeer.getConnection().getPeer(), ethPeer); |
||||
} |
||||
|
||||
@Override |
||||
public void removePeer(final PeerId peerId) { |
||||
ethPeersByPeerId.remove(peerId); |
||||
} |
||||
|
||||
private boolean isPeerUnused(final EthPeer ethPeer, final Collection<EthPeer> usedEthPeers) { |
||||
return !usedEthPeers.contains(ethPeer); |
||||
} |
||||
|
||||
private boolean isPeerHeightHighEnough(final EthPeer ethPeer, final long requiredHeight) { |
||||
return ethPeer.chainState().getEstimatedHeight() >= requiredHeight; |
||||
} |
||||
|
||||
private boolean isPeerProtocolSuitable(final EthPeer ethPeer, final SubProtocol protocol) { |
||||
return ethPeer.getProtocolName().equals(protocol.getName()); |
||||
} |
||||
} |
@ -1,135 +0,0 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.peertask; |
||||
|
||||
import org.hyperledger.besu.ethereum.eth.EthProtocol; |
||||
import org.hyperledger.besu.ethereum.eth.SnapProtocol; |
||||
import org.hyperledger.besu.ethereum.eth.manager.ChainState; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.PeerReputation; |
||||
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; |
||||
import org.hyperledger.besu.ethereum.p2p.peers.Peer; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol; |
||||
|
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
import org.junit.jupiter.api.Assertions; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
import org.mockito.Mockito; |
||||
|
||||
public class DefaultPeerSelectorTest { |
||||
|
||||
public DefaultPeerSelector peerSelector; |
||||
|
||||
@BeforeEach |
||||
public void beforeTest() { |
||||
ProtocolSpec protocolSpec = Mockito.mock(ProtocolSpec.class); |
||||
Mockito.when(protocolSpec.isPoS()).thenReturn(false); |
||||
peerSelector = new DefaultPeerSelector(() -> protocolSpec); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetPeer() throws NoAvailablePeerException { |
||||
EthPeer expectedPeer = createTestPeer(10, EthProtocol.get(), 5); |
||||
peerSelector.addPeer(expectedPeer); |
||||
EthPeer excludedForLowChainHeightPeer = createTestPeer(5, EthProtocol.get(), 50); |
||||
peerSelector.addPeer(excludedForLowChainHeightPeer); |
||||
EthPeer excludedForWrongProtocolPeer = createTestPeer(10, SnapProtocol.get(), 50); |
||||
peerSelector.addPeer(excludedForWrongProtocolPeer); |
||||
EthPeer excludedForLowReputationPeer = createTestPeer(10, EthProtocol.get(), 1); |
||||
peerSelector.addPeer(excludedForLowReputationPeer); |
||||
EthPeer excludedForBeingAlreadyUsedPeer = createTestPeer(10, EthProtocol.get(), 50); |
||||
peerSelector.addPeer(excludedForBeingAlreadyUsedPeer); |
||||
|
||||
Set<EthPeer> usedEthPeers = new HashSet<>(); |
||||
usedEthPeers.add(excludedForBeingAlreadyUsedPeer); |
||||
|
||||
EthPeer result = peerSelector.getPeer(usedEthPeers, 10, EthProtocol.get()); |
||||
|
||||
Assertions.assertSame(expectedPeer, result); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetPeerButNoPeerMatchesFilter() { |
||||
EthPeer expectedPeer = createTestPeer(10, EthProtocol.get(), 5); |
||||
peerSelector.addPeer(expectedPeer); |
||||
EthPeer excludedForLowChainHeightPeer = createTestPeer(5, EthProtocol.get(), 50); |
||||
peerSelector.addPeer(excludedForLowChainHeightPeer); |
||||
EthPeer excludedForWrongProtocolPeer = createTestPeer(10, SnapProtocol.get(), 50); |
||||
peerSelector.addPeer(excludedForWrongProtocolPeer); |
||||
EthPeer excludedForLowReputationPeer = createTestPeer(10, EthProtocol.get(), 1); |
||||
peerSelector.addPeer(excludedForLowReputationPeer); |
||||
EthPeer excludedForBeingAlreadyUsedPeer = createTestPeer(10, EthProtocol.get(), 50); |
||||
peerSelector.addPeer(excludedForBeingAlreadyUsedPeer); |
||||
|
||||
Set<EthPeer> usedEthPeers = new HashSet<>(); |
||||
usedEthPeers.add(excludedForBeingAlreadyUsedPeer); |
||||
|
||||
Assertions.assertThrows( |
||||
NoAvailablePeerException.class, |
||||
() -> peerSelector.getPeer(usedEthPeers, 10, new MockSubProtocol())); |
||||
} |
||||
|
||||
private EthPeer createTestPeer( |
||||
final long chainHeight, final SubProtocol protocol, final int reputation) { |
||||
EthPeer ethPeer = Mockito.mock(EthPeer.class); |
||||
PeerConnection peerConnection = Mockito.mock(PeerConnection.class); |
||||
Peer peer = Mockito.mock(Peer.class); |
||||
ChainState chainState = Mockito.mock(ChainState.class); |
||||
PeerReputation peerReputation = Mockito.mock(PeerReputation.class); |
||||
|
||||
Mockito.when(ethPeer.getConnection()).thenReturn(peerConnection); |
||||
Mockito.when(peerConnection.getPeer()).thenReturn(peer); |
||||
Mockito.when(ethPeer.getProtocolName()).thenReturn(protocol.getName()); |
||||
Mockito.when(ethPeer.chainState()).thenReturn(chainState); |
||||
Mockito.when(chainState.getEstimatedHeight()).thenReturn(chainHeight); |
||||
Mockito.when(ethPeer.getReputation()).thenReturn(peerReputation); |
||||
Mockito.when(peerReputation.getScore()).thenReturn(reputation); |
||||
|
||||
Mockito.when(ethPeer.compareTo(Mockito.any(EthPeer.class))) |
||||
.thenAnswer( |
||||
(invocationOnMock) -> { |
||||
EthPeer otherPeer = invocationOnMock.getArgument(0, EthPeer.class); |
||||
return Integer.compare(reputation, otherPeer.getReputation().getScore()); |
||||
}); |
||||
return ethPeer; |
||||
} |
||||
|
||||
private static class MockSubProtocol implements SubProtocol { |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "Mock"; |
||||
} |
||||
|
||||
@Override |
||||
public int messageSpace(final int protocolVersion) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isValidMessageCode(final int protocolVersion, final int code) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public String messageName(final int protocolVersion, final int code) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
} |
||||
} |
@ -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) {} |
Loading…
Reference in new issue