Merge pull request #4808 from jimmygchen/merge-unstable-to-deneb-20231005
Merge `unstable` branch to deneb 20231005
This commit is contained in:
commit
203ac65041
113
.config/nextest.toml
Normal file
113
.config/nextest.toml
Normal file
@ -0,0 +1,113 @@
|
||||
# This is the default config used by nextest. It is embedded in the binary at
|
||||
# build time. It may be used as a template for .config/nextest.toml.
|
||||
|
||||
[store]
|
||||
# The directory under the workspace root at which nextest-related files are
|
||||
# written. Profile-specific storage is currently written to dir/<profile-name>.
|
||||
dir = "target/nextest"
|
||||
|
||||
# This section defines the default nextest profile. Custom profiles are layered
|
||||
# on top of the default profile.
|
||||
[profile.default]
|
||||
# "retries" defines the number of times a test should be retried. If set to a
|
||||
# non-zero value, tests that succeed on a subsequent attempt will be marked as
|
||||
# non-flaky. Can be overridden through the `--retries` option.
|
||||
# Examples
|
||||
# * retries = 3
|
||||
# * retries = { backoff = "fixed", count = 2, delay = "1s" }
|
||||
# * retries = { backoff = "exponential", count = 10, delay = "1s", jitter = true, max-delay = "10s" }
|
||||
retries = 0
|
||||
|
||||
# The number of threads to run tests with. Supported values are either an integer or
|
||||
# the string "num-cpus". Can be overridden through the `--test-threads` option.
|
||||
test-threads = "num-cpus"
|
||||
|
||||
# The number of threads required for each test. This is generally used in overrides to
|
||||
# mark certain tests as heavier than others. However, it can also be set as a global parameter.
|
||||
threads-required = 1
|
||||
|
||||
# Show these test statuses in the output.
|
||||
#
|
||||
# The possible values this can take are:
|
||||
# * none: no output
|
||||
# * fail: show failed (including exec-failed) tests
|
||||
# * retry: show flaky and retried tests
|
||||
# * slow: show slow tests
|
||||
# * pass: show passed tests
|
||||
# * skip: show skipped tests (most useful for CI)
|
||||
# * all: all of the above
|
||||
#
|
||||
# Each value includes all the values above it; for example, "slow" includes
|
||||
# failed and retried tests.
|
||||
#
|
||||
# Can be overridden through the `--status-level` flag.
|
||||
status-level = "pass"
|
||||
|
||||
# Similar to status-level, show these test statuses at the end of the run.
|
||||
final-status-level = "flaky"
|
||||
|
||||
# "failure-output" defines when standard output and standard error for failing tests are produced.
|
||||
# Accepted values are
|
||||
# * "immediate": output failures as soon as they happen
|
||||
# * "final": output failures at the end of the test run
|
||||
# * "immediate-final": output failures as soon as they happen and at the end of
|
||||
# the test run; combination of "immediate" and "final"
|
||||
# * "never": don't output failures at all
|
||||
#
|
||||
# For large test suites and CI it is generally useful to use "immediate-final".
|
||||
#
|
||||
# Can be overridden through the `--failure-output` option.
|
||||
failure-output = "immediate"
|
||||
|
||||
# "success-output" controls production of standard output and standard error on success. This should
|
||||
# generally be set to "never".
|
||||
success-output = "never"
|
||||
|
||||
# Cancel the test run on the first failure. For CI runs, consider setting this
|
||||
# to false.
|
||||
fail-fast = true
|
||||
|
||||
# Treat a test that takes longer than the configured 'period' as slow, and print a message.
|
||||
# See <https://nexte.st/book/slow-tests> for more information.
|
||||
#
|
||||
# Optional: specify the parameter 'terminate-after' with a non-zero integer,
|
||||
# which will cause slow tests to be terminated after the specified number of
|
||||
# periods have passed.
|
||||
# Example: slow-timeout = { period = "60s", terminate-after = 2 }
|
||||
slow-timeout = { period = "120s" }
|
||||
|
||||
# Treat a test as leaky if after the process is shut down, standard output and standard error
|
||||
# aren't closed within this duration.
|
||||
#
|
||||
# This usually happens in case of a test that creates a child process and lets it inherit those
|
||||
# handles, but doesn't clean the child process up (especially when it fails).
|
||||
#
|
||||
# See <https://nexte.st/book/leaky-tests> for more information.
|
||||
leak-timeout = "100ms"
|
||||
|
||||
[profile.default.junit]
|
||||
# Output a JUnit report into the given file inside 'store.dir/<profile-name>'.
|
||||
# If unspecified, JUnit is not written out.
|
||||
|
||||
# path = "junit.xml"
|
||||
|
||||
# The name of the top-level "report" element in JUnit report. If aggregating
|
||||
# reports across different test runs, it may be useful to provide separate names
|
||||
# for each report.
|
||||
report-name = "lighthouse-run"
|
||||
|
||||
# Whether standard output and standard error for passing tests should be stored in the JUnit report.
|
||||
# Output is stored in the <system-out> and <system-err> elements of the <testcase> element.
|
||||
store-success-output = false
|
||||
|
||||
# Whether standard output and standard error for failing tests should be stored in the JUnit report.
|
||||
# Output is stored in the <system-out> and <system-err> elements of the <testcase> element.
|
||||
#
|
||||
# Note that if a description can be extracted from the output, it is always stored in the
|
||||
# <description> element.
|
||||
store-failure-output = true
|
||||
|
||||
# This profile is activated if MIRI_SYSROOT is set.
|
||||
[profile.default-miri]
|
||||
# Miri tests take up a lot of memory, so only run 1 test at a time by default.
|
||||
test-threads = 4
|
297
.github/workflows/test-suite.yml
vendored
297
.github/workflows/test-suite.yml
vendored
@ -18,14 +18,14 @@ env:
|
||||
# Deny warnings in CI
|
||||
# Disable debug info (see https://github.com/sigp/lighthouse/issues/4005)
|
||||
RUSTFLAGS: "-D warnings -C debuginfo=0"
|
||||
# The Nightly version used for cargo-udeps, might need updating from time to time.
|
||||
PINNED_NIGHTLY: nightly-2023-04-16
|
||||
# Prevent Github API rate limiting.
|
||||
LIGHTHOUSE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Enable self-hosted runners for the sigp repo only.
|
||||
SELF_HOSTED_RUNNERS: ${{ github.repository == 'sigp/lighthouse' }}
|
||||
# Self-hosted runners need to reference a different host for `./watch` tests.
|
||||
WATCH_HOST: ${{ github.repository == 'sigp/lighthouse' && 'host.docker.internal' || 'localhost' }}
|
||||
# Disable incremental compilation
|
||||
CARGO_INCREMENTAL: 0
|
||||
jobs:
|
||||
target-branch-check:
|
||||
name: target-branch-check
|
||||
@ -34,155 +34,191 @@ jobs:
|
||||
steps:
|
||||
- name: Check that the pull request is not targeting the stable branch
|
||||
run: test ${{ github.base_ref }} != "stable"
|
||||
extract-msrv:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Extract Minimum Supported Rust Version (MSRV)
|
||||
run: |
|
||||
metadata=$(cargo metadata --no-deps --format-version 1)
|
||||
msrv=$(echo $metadata | jq -r '.packages | map(select(.name == "lighthouse")) | .[0].rust_version')
|
||||
echo "MSRV=$msrv" >> $GITHUB_OUTPUT
|
||||
id: extract_msrv
|
||||
outputs:
|
||||
MSRV: ${{ steps.extract_msrv.outputs.MSRV }}
|
||||
cargo-fmt:
|
||||
name: cargo-fmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
- name: Check formatting with cargo fmt
|
||||
run: make cargo-fmt
|
||||
release-tests-ubuntu:
|
||||
name: release-tests-ubuntu
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "large"]') || 'ubuntu-latest' }}
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
if: env.SELF_HOSTED_RUNNERS == false
|
||||
run: rustup update stable
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
bins: cargo-nextest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install Foundry (anvil)
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly-ca67d15f4abd46394b324c50e21e66f306a1162d
|
||||
- name: Run tests in release
|
||||
run: make test-release
|
||||
run: make nextest-release
|
||||
- name: Show cache stats
|
||||
if: env.SELF_HOSTED_RUNNERS == 'true'
|
||||
run: sccache --show-stats
|
||||
release-tests-windows:
|
||||
name: release-tests-windows
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "windows", "CI"]') || 'windows-2019' }}
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
if: env.SELF_HOSTED_RUNNERS == false
|
||||
run: rustup update stable
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
bins: cargo-nextest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install Foundry (anvil)
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly-ca67d15f4abd46394b324c50e21e66f306a1162d
|
||||
- name: Install make
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
run: choco install -y make
|
||||
- uses: KyleMayes/install-llvm-action@v1
|
||||
if: env.SELF_HOSTED_RUNNERS == false
|
||||
with:
|
||||
version: "15.0"
|
||||
directory: ${{ runner.temp }}/llvm
|
||||
# - uses: KyleMayes/install-llvm-action@v1
|
||||
# if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
# with:
|
||||
# version: "15.0"
|
||||
# directory: ${{ runner.temp }}/llvm
|
||||
- name: Set LIBCLANG_PATH
|
||||
run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV
|
||||
- name: Run tests in release
|
||||
run: make test-release
|
||||
run: make nextest-release
|
||||
- name: Show cache stats
|
||||
if: env.SELF_HOSTED_RUNNERS == 'true'
|
||||
run: sccache --show-stats
|
||||
beacon-chain-tests:
|
||||
name: beacon-chain-tests
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "large"]') || 'ubuntu-latest' }}
|
||||
needs: cargo-fmt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
if: env.SELF_HOSTED_RUNNERS == false
|
||||
run: rustup update stable
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
bins: cargo-nextest
|
||||
- name: Run beacon_chain tests for all known forks
|
||||
run: make test-beacon-chain
|
||||
- name: Show cache stats
|
||||
if: env.SELF_HOSTED_RUNNERS == 'true'
|
||||
run: sccache --show-stats
|
||||
op-pool-tests:
|
||||
name: op-pool-tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
bins: cargo-nextest
|
||||
- name: Run operation_pool tests for all known forks
|
||||
run: make test-op-pool
|
||||
network-tests:
|
||||
name: network-tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
- name: Run network tests for all known forks
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
bins: cargo-nextest
|
||||
- name: Run network tests for all known forks
|
||||
run: make test-network
|
||||
slasher-tests:
|
||||
name: slasher-tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
bins: cargo-nextest
|
||||
- name: Run slasher tests for all supported backends
|
||||
run: make test-slasher
|
||||
debug-tests-ubuntu:
|
||||
name: debug-tests-ubuntu
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "large"]') || 'ubuntu-latest' }}
|
||||
needs: cargo-fmt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
if: env.SELF_HOSTED_RUNNERS == false
|
||||
run: rustup update stable
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
bins: cargo-nextest
|
||||
- name: Install Foundry (anvil)
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly-ca67d15f4abd46394b324c50e21e66f306a1162d
|
||||
- name: Run tests in debug
|
||||
run: make test-debug
|
||||
run: make nextest-debug
|
||||
- name: Show cache stats
|
||||
if: env.SELF_HOSTED_RUNNERS == 'true'
|
||||
run: sccache --show-stats
|
||||
state-transition-vectors-ubuntu:
|
||||
name: state-transition-vectors-ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
- name: Run state_transition_vectors in release.
|
||||
run: make run-state-transition-tests
|
||||
ef-tests-ubuntu:
|
||||
name: ef-tests-ubuntu
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "small"]') || 'ubuntu-latest' }}
|
||||
needs: cargo-fmt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
if: env.SELF_HOSTED_RUNNERS == false
|
||||
run: rustup update stable
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
bins: cargo-nextest
|
||||
- name: Run consensus-spec-tests with blst, milagro and fake_crypto
|
||||
run: make test-ef
|
||||
run: make nextest-ef
|
||||
- name: Show cache stats
|
||||
if: env.SELF_HOSTED_RUNNERS == 'true'
|
||||
run: sccache --show-stats
|
||||
dockerfile-ubuntu:
|
||||
name: dockerfile-ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
- name: Build the root Dockerfile
|
||||
run: docker build --build-arg FEATURES=portable -t lighthouse:local .
|
||||
- name: Test the built image
|
||||
@ -190,11 +226,13 @@ jobs:
|
||||
eth1-simulator-ubuntu:
|
||||
name: eth1-simulator-ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
- name: Install Foundry (anvil)
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
@ -204,11 +242,13 @@ jobs:
|
||||
merge-transition-ubuntu:
|
||||
name: merge-transition-ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
- name: Install Foundry (anvil)
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
@ -218,21 +258,25 @@ jobs:
|
||||
no-eth1-simulator-ubuntu:
|
||||
name: no-eth1-simulator-ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
- name: Run the beacon chain sim without an eth1 connection
|
||||
run: cargo run --release --bin simulator no-eth1-sim
|
||||
syncing-simulator-ubuntu:
|
||||
name: syncing-simulator-ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
- name: Install Foundry (anvil)
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
@ -241,21 +285,28 @@ jobs:
|
||||
run: cargo run --release --bin simulator syncing-sim
|
||||
doppelganger-protection-test:
|
||||
name: doppelganger-protection-test
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "small"]') || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
- name: Install geth
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
run: |
|
||||
sudo add-apt-repository -y ppa:ethereum/ethereum
|
||||
sudo apt-get update
|
||||
sudo apt-get install ethereum
|
||||
- name: Install lighthouse and lcli
|
||||
- name: Install lighthouse
|
||||
run: |
|
||||
make
|
||||
make install-lcli
|
||||
- name: Install lcli
|
||||
# TODO(jimmy): re-enable this once we merge deneb into unstable
|
||||
# if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
run: make install-lcli
|
||||
- name: Run the doppelganger protection failure test script
|
||||
run: |
|
||||
cd scripts/tests
|
||||
@ -267,91 +318,73 @@ jobs:
|
||||
execution-engine-integration-ubuntu:
|
||||
name: execution-engine-integration-ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.20'
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.0.201'
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
cache: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Run exec engine integration tests in release
|
||||
run: make test-exec-engine
|
||||
check-benchmarks:
|
||||
name: check-benchmarks
|
||||
check-code:
|
||||
name: check-code
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
env:
|
||||
CARGO_INCREMENTAL: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
- name: Typecheck benchmark code without running it
|
||||
run: make check-benches
|
||||
clippy:
|
||||
name: clippy
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: stable
|
||||
cache-target: release
|
||||
components: rustfmt,clippy
|
||||
bins: cargo-audit
|
||||
- name: Check formatting with cargo fmt
|
||||
run: make cargo-fmt
|
||||
- name: Lint code for quality and style with Clippy
|
||||
run: make lint
|
||||
- name: Certify Cargo.lock freshness
|
||||
run: git diff --exit-code Cargo.lock
|
||||
- name: Typecheck benchmark code without running it
|
||||
run: make check-benches
|
||||
- name: Validate state_processing feature arbitrary-fuzz
|
||||
run: make arbitrary-fuzz
|
||||
- name: Run cargo audit
|
||||
run: make audit-CI
|
||||
# TODO(sean): re-enable this when we can figure it out with c-kzg
|
||||
# Issue: https://github.com/sigp/lighthouse/issues/4440
|
||||
# - name: Run cargo vendor to make sure dependencies can be vendored for packaging, reproducibility and archival purpose
|
||||
# run: CARGO_HOME=$(readlink -f $HOME) make vendor
|
||||
check-msrv:
|
||||
name: check-msrv
|
||||
runs-on: ubuntu-latest
|
||||
needs: [cargo-fmt, extract-msrv]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust @ MSRV (${{ needs.extract-msrv.outputs.MSRV }})
|
||||
run: rustup override set ${{ needs.extract-msrv.outputs.MSRV }}
|
||||
- name: Install Rust at Minimum Supported Rust Version (MSRV)
|
||||
run: |
|
||||
metadata=$(cargo metadata --no-deps --format-version 1)
|
||||
msrv=$(echo $metadata | jq -r '.packages | map(select(.name == "lighthouse")) | .[0].rust_version')
|
||||
rustup override set $msrv
|
||||
- name: Run cargo check
|
||||
run: cargo check --workspace
|
||||
arbitrary-check:
|
||||
name: arbitrary-check
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
- name: Validate state_processing feature arbitrary-fuzz
|
||||
run: make arbitrary-fuzz
|
||||
cargo-audit:
|
||||
name: cargo-audit
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
run: rustup update stable
|
||||
- name: Run cargo audit to identify known security vulnerabilities reported to the RustSec Advisory Database
|
||||
run: make audit
|
||||
# TODO(sean): re-enable this when we can figure it out with c-kzg
|
||||
# Issue: https://github.com/sigp/lighthouse/issues/4440
|
||||
# cargo-vendor:
|
||||
# name: cargo-vendor
|
||||
# runs-on: ubuntu-latest
|
||||
# needs: cargo-fmt
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - name: Run cargo vendor to make sure dependencies can be vendored for packaging, reproducibility and archival purpose
|
||||
# run: CARGO_HOME=$(readlink -f $HOME) make vendor
|
||||
cargo-udeps:
|
||||
name: cargo-udeps
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust (${{ env.PINNED_NIGHTLY }})
|
||||
run: rustup toolchain install $PINNED_NIGHTLY
|
||||
- name: Install cargo-udeps
|
||||
run: cargo install cargo-udeps --locked --force
|
||||
- name: Get latest version of nightly Rust
|
||||
uses: moonrepo/setup-rust@v1
|
||||
with:
|
||||
channel: nightly
|
||||
bins: cargo-udeps
|
||||
cache: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Create Cargo config dir
|
||||
run: mkdir -p .cargo
|
||||
- name: Install custom Cargo config
|
||||
|
587
Cargo.lock
generated
587
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -137,7 +137,7 @@ r2d2 = "0.8"
|
||||
rand = "0.8"
|
||||
rayon = "1.7"
|
||||
regex = "1"
|
||||
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "stream", "rustls-tls"] }
|
||||
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "stream", "rustls-tls", "native-tls-vendored"] }
|
||||
ring = "0.16"
|
||||
rusqlite = { version = "0.28", features = ["bundled"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
@ -157,7 +157,7 @@ superstruct = "0.6"
|
||||
syn = "1"
|
||||
sysinfo = "0.26"
|
||||
tempfile = "3"
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "sync"] }
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "sync", "signal"] }
|
||||
tokio-stream = { version = "0.1", features = ["sync"] }
|
||||
tokio-util = { version = "0.6", features = ["codec", "compat", "time"] }
|
||||
tree_hash = "0.5"
|
||||
|
39
Makefile
39
Makefile
@ -108,11 +108,21 @@ build-release-tarballs:
|
||||
test-release:
|
||||
cargo test --workspace --release --exclude ef_tests --exclude beacon_chain --exclude slasher --exclude network
|
||||
|
||||
# Runs the full workspace tests in **release**, without downloading any additional
|
||||
# test vectors, using nextest.
|
||||
nextest-release:
|
||||
cargo nextest run --workspace --release --exclude ef_tests --exclude beacon_chain --exclude slasher --exclude network
|
||||
|
||||
# Runs the full workspace tests in **debug**, without downloading any additional test
|
||||
# vectors.
|
||||
test-debug:
|
||||
cargo test --workspace --exclude ef_tests --exclude beacon_chain --exclude network
|
||||
|
||||
# Runs the full workspace tests in **debug**, without downloading any additional test
|
||||
# vectors, using nextest.
|
||||
nextest-debug:
|
||||
cargo nextest run --workspace --exclude ef_tests --exclude beacon_chain --exclude network
|
||||
|
||||
# Runs cargo-fmt (linter).
|
||||
cargo-fmt:
|
||||
cargo fmt --all -- --check
|
||||
@ -129,17 +139,25 @@ run-ef-tests:
|
||||
cargo test --release -p ef_tests --features "ef_tests,$(EF_TEST_FEATURES),milagro"
|
||||
./$(EF_TESTS)/check_all_files_accessed.py $(EF_TESTS)/.accessed_file_log.txt $(EF_TESTS)/consensus-spec-tests
|
||||
|
||||
# Runs EF test vectors with nextest
|
||||
nextest-run-ef-tests:
|
||||
rm -rf $(EF_TESTS)/.accessed_file_log.txt
|
||||
cargo nextest run --release -p ef_tests --features "ef_tests,$(EF_TEST_FEATURES)"
|
||||
cargo nextest run --release -p ef_tests --features "ef_tests,$(EF_TEST_FEATURES),fake_crypto"
|
||||
cargo nextest run --release -p ef_tests --features "ef_tests,$(EF_TEST_FEATURES),milagro"
|
||||
./$(EF_TESTS)/check_all_files_accessed.py $(EF_TESTS)/.accessed_file_log.txt $(EF_TESTS)/consensus-spec-tests
|
||||
|
||||
# Run the tests in the `beacon_chain` crate for all known forks.
|
||||
test-beacon-chain: $(patsubst %,test-beacon-chain-%,$(FORKS))
|
||||
|
||||
test-beacon-chain-%:
|
||||
env FORK_NAME=$* cargo test --release --features fork_from_env,slasher/lmdb -p beacon_chain
|
||||
env FORK_NAME=$* cargo nextest run --release --features fork_from_env,slasher/lmdb -p beacon_chain
|
||||
|
||||
# Run the tests in the `operation_pool` crate for all known forks.
|
||||
test-op-pool: $(patsubst %,test-op-pool-%,$(FORKS))
|
||||
|
||||
test-op-pool-%:
|
||||
env FORK_NAME=$* cargo test --release \
|
||||
env FORK_NAME=$* cargo nextest run --release \
|
||||
--features 'beacon_chain/fork_from_env'\
|
||||
-p operation_pool
|
||||
|
||||
@ -147,15 +165,15 @@ test-op-pool-%:
|
||||
test-network: $(patsubst %,test-network-%,$(FORKS))
|
||||
|
||||
test-network-%:
|
||||
env FORK_NAME=$* cargo test --release \
|
||||
env FORK_NAME=$* cargo nextest run --release \
|
||||
--features 'fork_from_env' \
|
||||
-p network
|
||||
|
||||
# Run the tests in the `slasher` crate for all supported database backends.
|
||||
test-slasher:
|
||||
cargo test --release -p slasher --features lmdb
|
||||
cargo test --release -p slasher --no-default-features --features mdbx
|
||||
cargo test --release -p slasher --features lmdb,mdbx # both backends enabled
|
||||
cargo nextest run --release -p slasher --features lmdb
|
||||
cargo nextest run --release -p slasher --no-default-features --features mdbx
|
||||
cargo nextest run --release -p slasher --features lmdb,mdbx # both backends enabled
|
||||
|
||||
# Runs only the tests/state_transition_vectors tests.
|
||||
run-state-transition-tests:
|
||||
@ -164,6 +182,9 @@ run-state-transition-tests:
|
||||
# Downloads and runs the EF test vectors.
|
||||
test-ef: make-ef-tests run-ef-tests
|
||||
|
||||
# Downloads and runs the EF test vectors with nextest.
|
||||
nextest-ef: make-ef-tests nextest-run-ef-tests
|
||||
|
||||
# Runs tests checking interop between Lighthouse and execution clients.
|
||||
test-exec-engine:
|
||||
make -C $(EXECUTION_ENGINE_INTEGRATION) test
|
||||
@ -213,8 +234,12 @@ arbitrary-fuzz:
|
||||
cargo check -p slashing_protection --features arbitrary-fuzz
|
||||
|
||||
# Runs cargo audit (Audit Cargo.lock files for crates with security vulnerabilities reported to the RustSec Advisory Database)
|
||||
audit:
|
||||
audit: install-audit audit-CI
|
||||
|
||||
install-audit:
|
||||
cargo install --force cargo-audit
|
||||
|
||||
audit-CI:
|
||||
cargo audit
|
||||
|
||||
# Runs `cargo vendor` to make sure dependencies can be vendored for packaging, reproducibility and archival purpose.
|
||||
|
@ -20,8 +20,8 @@ use execution_layer::test_utils::generate_genesis_header;
|
||||
use execution_layer::{
|
||||
auth::JwtKey,
|
||||
test_utils::{
|
||||
ExecutionBlockGenerator, MockBuilder, MockBuilderServer, MockExecutionLayer,
|
||||
DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK,
|
||||
ExecutionBlockGenerator, MockBuilder, MockExecutionLayer, DEFAULT_JWT_SECRET,
|
||||
DEFAULT_TERMINAL_BLOCK,
|
||||
},
|
||||
ExecutionLayer,
|
||||
};
|
||||
@ -663,7 +663,10 @@ where
|
||||
.execution_block_generator()
|
||||
}
|
||||
|
||||
pub fn set_mock_builder(&mut self, beacon_url: SensitiveUrl) -> MockBuilderServer {
|
||||
pub fn set_mock_builder(
|
||||
&mut self,
|
||||
beacon_url: SensitiveUrl,
|
||||
) -> impl futures::Future<Output = ()> {
|
||||
let mock_el = self
|
||||
.mock_execution_layer
|
||||
.as_ref()
|
||||
@ -672,7 +675,7 @@ where
|
||||
let mock_el_url = SensitiveUrl::parse(mock_el.server.url().as_str()).unwrap();
|
||||
|
||||
// Create the builder, listening on a free port.
|
||||
let (mock_builder, mock_builder_server) = MockBuilder::new_for_testing(
|
||||
let (mock_builder, (addr, mock_builder_server)) = MockBuilder::new_for_testing(
|
||||
mock_el_url,
|
||||
beacon_url,
|
||||
self.spec.clone(),
|
||||
@ -680,8 +683,7 @@ where
|
||||
);
|
||||
|
||||
// Set the builder URL in the execution layer now that its port is known.
|
||||
let builder_listen_addr = mock_builder_server.local_addr();
|
||||
let port = builder_listen_addr.port();
|
||||
let port = addr.port();
|
||||
mock_el
|
||||
.el
|
||||
.set_builder_url(
|
||||
|
@ -42,12 +42,6 @@ lazy_static = { workspace = true }
|
||||
ethers-core = { workspace = true }
|
||||
builder_client = { path = "../builder_client" }
|
||||
fork_choice = { workspace = true }
|
||||
#PR: https://github.com/ralexstokes/mev-rs/pull/124
|
||||
mev-rs = { git = "https://github.com/jimmygchen/mev-rs", rev = "dedc77a" }
|
||||
axum = "0.6"
|
||||
hyper = "0.14"
|
||||
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "12508c1f9b0c8f4bf4c5e9b6d441e840c1b37fd9" }
|
||||
ssz_rs = "0.9.0"
|
||||
tokio-stream = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
keccak-hash = "0.10.0"
|
||||
|
@ -1,51 +1,30 @@
|
||||
use crate::test_utils::{DEFAULT_BUILDER_PAYLOAD_VALUE_WEI, DEFAULT_JWT_SECRET};
|
||||
use crate::{Config, ExecutionLayer, PayloadAttributes};
|
||||
use async_trait::async_trait;
|
||||
use eth2::types::{BlobsBundle, BlockId, StateId, ValidatorId};
|
||||
use eth2::{BeaconNodeHttpClient, Timeouts};
|
||||
pub use ethereum_consensus::state_transition::Context;
|
||||
use ethereum_consensus::{
|
||||
crypto::{SecretKey, Signature},
|
||||
primitives::{BlsPublicKey, BlsSignature, ExecutionAddress, Hash32, Root, U256},
|
||||
state_transition::Error,
|
||||
};
|
||||
use fork_choice::ForkchoiceUpdateParameters;
|
||||
use mev_rs::{
|
||||
blinded_block_provider::Server as BlindedBlockProviderServer,
|
||||
signing::{sign_builder_message, verify_signed_builder_message},
|
||||
types::{
|
||||
bellatrix::{
|
||||
BuilderBid as BuilderBidBellatrix, SignedBuilderBid as SignedBuilderBidBellatrix,
|
||||
},
|
||||
capella::{BuilderBid as BuilderBidCapella, SignedBuilderBid as SignedBuilderBidCapella},
|
||||
deneb::{BuilderBid as BuilderBidDeneb, SignedBuilderBid as SignedBuilderBidDeneb},
|
||||
BidRequest, BuilderBid, ExecutionPayload as ServerPayload, SignedBlindedBeaconBlock,
|
||||
SignedBuilderBid, SignedValidatorRegistration,
|
||||
},
|
||||
Error as MevError,
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_rs::{Merkleized, SimpleSerialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::future::Future;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use task_executor::TaskExecutor;
|
||||
use tempfile::NamedTempFile;
|
||||
use tree_hash::TreeHash;
|
||||
use types::builder_bid::BlindedBlobsBundle;
|
||||
use types::builder_bid::{
|
||||
BuilderBid, BuilderBidCapella, BuilderBidDeneb, BuilderBidMerge, SignedBuilderBid,
|
||||
};
|
||||
use types::{
|
||||
Address, BeaconState, ChainSpec, EthSpec, ExecPayload, ExecutionPayload,
|
||||
ExecutionPayloadHeader, ForkName, ForkVersionedResponse, Hash256, Slot, Uint256,
|
||||
ExecutionPayloadHeaderRefMut, ForkName, ForkVersionedResponse, Hash256, PublicKeyBytes,
|
||||
Signature, SignedBlindedBeaconBlock, SignedRoot, SignedValidatorRegistrationData, Slot,
|
||||
Uint256,
|
||||
};
|
||||
|
||||
pub type MockBuilderServer = axum::Server<
|
||||
hyper::server::conn::AddrIncoming,
|
||||
axum::routing::IntoMakeService<axum::routing::Router>,
|
||||
>;
|
||||
use types::{ExecutionBlockHash, SecretKey};
|
||||
use warp::{Filter, Rejection};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Operation {
|
||||
@ -60,115 +39,156 @@ pub enum Operation {
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
fn apply<B: BidStuff>(self, bid: &mut B) -> Result<(), MevError> {
|
||||
fn apply<E: EthSpec, B: BidStuff<E>>(self, bid: &mut B) {
|
||||
match self {
|
||||
Operation::FeeRecipient(fee_recipient) => {
|
||||
*bid.fee_recipient_mut() = to_ssz_rs(&fee_recipient)?
|
||||
}
|
||||
Operation::GasLimit(gas_limit) => *bid.gas_limit_mut() = gas_limit as u64,
|
||||
Operation::Value(value) => *bid.value_mut() = to_ssz_rs(&value)?,
|
||||
Operation::ParentHash(parent_hash) => *bid.parent_hash_mut() = to_ssz_rs(&parent_hash)?,
|
||||
Operation::PrevRandao(prev_randao) => *bid.prev_randao_mut() = to_ssz_rs(&prev_randao)?,
|
||||
Operation::BlockNumber(block_number) => *bid.block_number_mut() = block_number as u64,
|
||||
Operation::Timestamp(timestamp) => *bid.timestamp_mut() = timestamp as u64,
|
||||
Operation::WithdrawalsRoot(root) => *bid.withdrawals_root_mut()? = to_ssz_rs(&root)?,
|
||||
Operation::FeeRecipient(fee_recipient) => bid.set_fee_recipient(fee_recipient),
|
||||
Operation::GasLimit(gas_limit) => bid.set_gas_limit(gas_limit as u64),
|
||||
Operation::Value(value) => bid.set_value(value),
|
||||
Operation::ParentHash(parent_hash) => bid.set_parent_hash(parent_hash),
|
||||
Operation::PrevRandao(prev_randao) => bid.set_prev_randao(prev_randao),
|
||||
Operation::BlockNumber(block_number) => bid.set_block_number(block_number as u64),
|
||||
Operation::Timestamp(timestamp) => bid.set_timestamp(timestamp as u64),
|
||||
Operation::WithdrawalsRoot(root) => bid.set_withdrawals_root(root),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Custom(String);
|
||||
|
||||
impl warp::reject::Reject for Custom {}
|
||||
|
||||
// contains functions we need for BuilderBids.. not sure what to call this
|
||||
pub trait BidStuff {
|
||||
fn fee_recipient_mut(&mut self) -> &mut ExecutionAddress;
|
||||
fn gas_limit_mut(&mut self) -> &mut u64;
|
||||
fn value_mut(&mut self) -> &mut U256;
|
||||
fn parent_hash_mut(&mut self) -> &mut Hash32;
|
||||
fn prev_randao_mut(&mut self) -> &mut Hash32;
|
||||
fn block_number_mut(&mut self) -> &mut u64;
|
||||
fn timestamp_mut(&mut self) -> &mut u64;
|
||||
fn withdrawals_root_mut(&mut self) -> Result<&mut Root, MevError>;
|
||||
pub trait BidStuff<E: EthSpec> {
|
||||
fn set_fee_recipient(&mut self, fee_recipient_address: Address);
|
||||
fn set_gas_limit(&mut self, gas_limit: u64);
|
||||
fn set_value(&mut self, value: Uint256);
|
||||
fn set_parent_hash(&mut self, parent_hash: Hash256);
|
||||
fn set_prev_randao(&mut self, randao: Hash256);
|
||||
fn set_block_number(&mut self, block_number: u64);
|
||||
fn set_timestamp(&mut self, timestamp: u64);
|
||||
fn set_withdrawals_root(&mut self, withdrawals_root: Hash256);
|
||||
|
||||
fn sign_builder_message(
|
||||
&mut self,
|
||||
signing_key: &SecretKey,
|
||||
context: &Context,
|
||||
) -> Result<BlsSignature, Error>;
|
||||
fn sign_builder_message(&mut self, sk: &SecretKey, spec: &ChainSpec) -> Signature;
|
||||
|
||||
fn to_signed_bid(self, signature: BlsSignature) -> SignedBuilderBid;
|
||||
fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid<E>;
|
||||
}
|
||||
|
||||
macro_rules! map_builder_bid {
|
||||
($self_ident:ident, |$var:ident| $expr:expr) => {
|
||||
match $self_ident {
|
||||
BuilderBid::Bellatrix($var) => $expr,
|
||||
BuilderBid::Capella($var) => $expr,
|
||||
BuilderBid::Deneb($var) => $expr,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl BidStuff for BuilderBid {
|
||||
fn fee_recipient_mut(&mut self) -> &mut ExecutionAddress {
|
||||
map_builder_bid!(self, |bid| &mut bid.header.fee_recipient)
|
||||
}
|
||||
|
||||
fn gas_limit_mut(&mut self) -> &mut u64 {
|
||||
map_builder_bid!(self, |bid| &mut bid.header.gas_limit)
|
||||
}
|
||||
|
||||
fn value_mut(&mut self) -> &mut U256 {
|
||||
map_builder_bid!(self, |bid| &mut bid.value)
|
||||
}
|
||||
|
||||
fn parent_hash_mut(&mut self) -> &mut Hash32 {
|
||||
map_builder_bid!(self, |bid| &mut bid.header.parent_hash)
|
||||
}
|
||||
|
||||
fn prev_randao_mut(&mut self) -> &mut Hash32 {
|
||||
map_builder_bid!(self, |bid| &mut bid.header.prev_randao)
|
||||
}
|
||||
|
||||
fn block_number_mut(&mut self) -> &mut u64 {
|
||||
map_builder_bid!(self, |bid| &mut bid.header.block_number)
|
||||
}
|
||||
|
||||
fn timestamp_mut(&mut self) -> &mut u64 {
|
||||
map_builder_bid!(self, |bid| &mut bid.header.timestamp)
|
||||
}
|
||||
|
||||
fn withdrawals_root_mut(&mut self) -> Result<&mut Root, MevError> {
|
||||
match self {
|
||||
Self::Bellatrix(_) => Err(MevError::InvalidFork),
|
||||
Self::Capella(bid) => Ok(&mut bid.header.withdrawals_root),
|
||||
Self::Deneb(bid) => Ok(&mut bid.header.withdrawals_root),
|
||||
impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
|
||||
fn set_fee_recipient(&mut self, fee_recipient: Address) {
|
||||
match self.to_mut().header_mut() {
|
||||
ExecutionPayloadHeaderRefMut::Merge(header) => {
|
||||
header.fee_recipient = fee_recipient;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Capella(header) => {
|
||||
header.fee_recipient = fee_recipient;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Deneb(header) => {
|
||||
header.fee_recipient = fee_recipient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sign_builder_message(
|
||||
&mut self,
|
||||
signing_key: &SecretKey,
|
||||
context: &Context,
|
||||
) -> Result<Signature, Error> {
|
||||
map_builder_bid!(self, |message| sign_builder_message(
|
||||
message,
|
||||
signing_key,
|
||||
context
|
||||
))
|
||||
fn set_gas_limit(&mut self, gas_limit: u64) {
|
||||
match self.to_mut().header_mut() {
|
||||
ExecutionPayloadHeaderRefMut::Merge(header) => {
|
||||
header.gas_limit = gas_limit;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Capella(header) => {
|
||||
header.gas_limit = gas_limit;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Deneb(header) => {
|
||||
header.gas_limit = gas_limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid {
|
||||
match self {
|
||||
Self::Bellatrix(message) => {
|
||||
SignedBuilderBid::Bellatrix(SignedBuilderBidBellatrix { message, signature })
|
||||
fn set_value(&mut self, value: Uint256) {
|
||||
*self.value_mut() = value;
|
||||
}
|
||||
|
||||
fn set_parent_hash(&mut self, parent_hash: Hash256) {
|
||||
match self.to_mut().header_mut() {
|
||||
ExecutionPayloadHeaderRefMut::Merge(header) => {
|
||||
header.parent_hash = ExecutionBlockHash::from_root(parent_hash);
|
||||
}
|
||||
Self::Capella(message) => {
|
||||
SignedBuilderBid::Capella(SignedBuilderBidCapella { message, signature })
|
||||
ExecutionPayloadHeaderRefMut::Capella(header) => {
|
||||
header.parent_hash = ExecutionBlockHash::from_root(parent_hash);
|
||||
}
|
||||
Self::Deneb(message) => {
|
||||
SignedBuilderBid::Deneb(SignedBuilderBidDeneb { message, signature })
|
||||
ExecutionPayloadHeaderRefMut::Deneb(header) => {
|
||||
header.parent_hash = ExecutionBlockHash::from_root(parent_hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_prev_randao(&mut self, prev_randao: Hash256) {
|
||||
match self.to_mut().header_mut() {
|
||||
ExecutionPayloadHeaderRefMut::Merge(header) => {
|
||||
header.prev_randao = prev_randao;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Capella(header) => {
|
||||
header.prev_randao = prev_randao;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Deneb(header) => {
|
||||
header.prev_randao = prev_randao;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_block_number(&mut self, block_number: u64) {
|
||||
match self.to_mut().header_mut() {
|
||||
ExecutionPayloadHeaderRefMut::Merge(header) => {
|
||||
header.block_number = block_number;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Capella(header) => {
|
||||
header.block_number = block_number;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Deneb(header) => {
|
||||
header.block_number = block_number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_timestamp(&mut self, timestamp: u64) {
|
||||
match self.to_mut().header_mut() {
|
||||
ExecutionPayloadHeaderRefMut::Merge(header) => {
|
||||
header.timestamp = timestamp;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Capella(header) => {
|
||||
header.timestamp = timestamp;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Deneb(header) => {
|
||||
header.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_withdrawals_root(&mut self, withdrawals_root: Hash256) {
|
||||
match self.to_mut().header_mut() {
|
||||
ExecutionPayloadHeaderRefMut::Merge(_) => {
|
||||
panic!("no withdrawals before capella")
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Capella(header) => {
|
||||
header.withdrawals_root = withdrawals_root;
|
||||
}
|
||||
ExecutionPayloadHeaderRefMut::Deneb(header) => {
|
||||
header.withdrawals_root = withdrawals_root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sign_builder_message(&mut self, sk: &SecretKey, spec: &ChainSpec) -> Signature {
|
||||
let domain = spec.get_builder_domain();
|
||||
let message = self.signing_root(domain);
|
||||
sk.sign(message)
|
||||
}
|
||||
|
||||
fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid<E> {
|
||||
SignedBuilderBid {
|
||||
message: self,
|
||||
signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -176,8 +196,7 @@ pub struct MockBuilder<E: EthSpec> {
|
||||
el: ExecutionLayer<E>,
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
spec: ChainSpec,
|
||||
context: Arc<Context>,
|
||||
val_registration_cache: Arc<RwLock<HashMap<BlsPublicKey, SignedValidatorRegistration>>>,
|
||||
val_registration_cache: Arc<RwLock<HashMap<PublicKeyBytes, SignedValidatorRegistrationData>>>,
|
||||
builder_sk: SecretKey,
|
||||
operations: Arc<RwLock<Vec<Operation>>>,
|
||||
invalidate_signatures: Arc<RwLock<bool>>,
|
||||
@ -189,7 +208,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
beacon_url: SensitiveUrl,
|
||||
spec: ChainSpec,
|
||||
executor: TaskExecutor,
|
||||
) -> (Self, MockBuilderServer) {
|
||||
) -> (Self, (SocketAddr, impl Future<Output = ()>)) {
|
||||
let file = NamedTempFile::new().unwrap();
|
||||
let path = file.path().into();
|
||||
std::fs::write(&path, hex::encode(DEFAULT_JWT_SECRET)).unwrap();
|
||||
@ -205,23 +224,14 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
let el =
|
||||
ExecutionLayer::from_config(config, executor.clone(), executor.log().clone()).unwrap();
|
||||
|
||||
// This should probably be done for all fields, we only update ones we are testing with so far.
|
||||
let mut context = Context::for_mainnet();
|
||||
context.terminal_total_difficulty = to_ssz_rs(&spec.terminal_total_difficulty).unwrap();
|
||||
context.terminal_block_hash = to_ssz_rs(&spec.terminal_block_hash).unwrap();
|
||||
context.terminal_block_hash_activation_epoch =
|
||||
to_ssz_rs(&spec.terminal_block_hash_activation_epoch).unwrap();
|
||||
|
||||
let builder = MockBuilder::new(
|
||||
el,
|
||||
BeaconNodeHttpClient::new(beacon_url, Timeouts::set_all(Duration::from_secs(1))),
|
||||
spec,
|
||||
context,
|
||||
);
|
||||
let host: Ipv4Addr = Ipv4Addr::LOCALHOST;
|
||||
let port = 0;
|
||||
let provider = BlindedBlockProviderServer::new(host, port, builder.clone());
|
||||
let server = provider.serve();
|
||||
let server = serve(host, port, builder.clone()).expect("mock builder server should start");
|
||||
(builder, server)
|
||||
}
|
||||
|
||||
@ -229,15 +239,13 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
el: ExecutionLayer<E>,
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
spec: ChainSpec,
|
||||
context: Context,
|
||||
) -> Self {
|
||||
let sk = SecretKey::random(&mut rand::thread_rng()).unwrap();
|
||||
let sk = SecretKey::random();
|
||||
Self {
|
||||
el,
|
||||
beacon_client,
|
||||
// Should keep spec and context consistent somehow
|
||||
spec,
|
||||
context: Arc::new(context),
|
||||
val_registration_cache: Arc::new(RwLock::new(HashMap::new())),
|
||||
builder_sk: sk,
|
||||
operations: Arc::new(RwLock::new(vec![])),
|
||||
@ -259,296 +267,335 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
*self.invalidate_signatures.write() = false;
|
||||
}
|
||||
|
||||
fn apply_operations<B: BidStuff>(&self, bid: &mut B) -> Result<(), MevError> {
|
||||
fn apply_operations<B: BidStuff<E>>(&self, bid: &mut B) {
|
||||
let mut guard = self.operations.write();
|
||||
while let Some(op) = guard.pop() {
|
||||
op.apply(bid)?;
|
||||
op.apply(bid);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pubkey(&self) -> ethereum_consensus::crypto::PublicKey {
|
||||
self.builder_sk.public_key()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<E: EthSpec> mev_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
async fn register_validators(
|
||||
&self,
|
||||
registrations: &mut [SignedValidatorRegistration],
|
||||
) -> Result<(), MevError> {
|
||||
for registration in registrations {
|
||||
let pubkey = registration.message.public_key.clone();
|
||||
let message = &mut registration.message;
|
||||
verify_signed_builder_message(
|
||||
message,
|
||||
®istration.signature,
|
||||
&pubkey,
|
||||
&self.context,
|
||||
)?;
|
||||
self.val_registration_cache.write().insert(
|
||||
registration.message.public_key.clone(),
|
||||
registration.clone(),
|
||||
);
|
||||
}
|
||||
pub fn serve<E: EthSpec>(
|
||||
listen_addr: Ipv4Addr,
|
||||
listen_port: u16,
|
||||
builder: MockBuilder<E>,
|
||||
) -> Result<(SocketAddr, impl Future<Output = ()>), crate::test_utils::Error> {
|
||||
let inner_ctx = builder.clone();
|
||||
let ctx_filter = warp::any().map(move || inner_ctx.clone());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
let prefix = warp::path("eth")
|
||||
.and(warp::path("v1"))
|
||||
.and(warp::path("builder"));
|
||||
|
||||
async fn fetch_best_bid(&self, bid_request: &BidRequest) -> Result<SignedBuilderBid, MevError> {
|
||||
let slot = Slot::new(bid_request.slot);
|
||||
let fork = self.spec.fork_name_at_slot::<E>(slot);
|
||||
let signed_cached_data = self
|
||||
.val_registration_cache
|
||||
.read()
|
||||
.get(&bid_request.public_key)
|
||||
.ok_or_else(|| convert_err("missing registration"))?
|
||||
.clone();
|
||||
let cached_data = signed_cached_data.message;
|
||||
let validators = prefix
|
||||
.and(warp::path("validators"))
|
||||
.and(warp::body::json())
|
||||
.and(warp::path::end())
|
||||
.and(ctx_filter.clone())
|
||||
.and_then(
|
||||
|registrations: Vec<SignedValidatorRegistrationData>, builder: MockBuilder<E>| async move {
|
||||
for registration in registrations {
|
||||
if !registration.verify_signature(&builder.spec) {
|
||||
return Err(reject("invalid signature"));
|
||||
}
|
||||
builder
|
||||
.val_registration_cache
|
||||
.write()
|
||||
.insert(registration.message.pubkey, registration);
|
||||
}
|
||||
Ok(warp::reply())
|
||||
},
|
||||
);
|
||||
|
||||
let head = self
|
||||
.beacon_client
|
||||
.get_beacon_blocks::<E>(BlockId::Head)
|
||||
.await
|
||||
.map_err(convert_err)?
|
||||
.ok_or_else(|| convert_err("missing head block"))?;
|
||||
let blinded_block = prefix
|
||||
.and(warp::path("blinded_blocks"))
|
||||
.and(warp::body::json())
|
||||
.and(warp::path::end())
|
||||
.and(ctx_filter.clone())
|
||||
.and_then(
|
||||
|block: SignedBlindedBeaconBlock<E>, builder: MockBuilder<E>| async move {
|
||||
let slot = block.slot();
|
||||
let root = match block {
|
||||
SignedBlindedBeaconBlock::Base(_) | types::SignedBeaconBlock::Altair(_) => {
|
||||
return Err(reject("invalid fork"));
|
||||
}
|
||||
SignedBlindedBeaconBlock::Merge(block) => {
|
||||
block.message.body.execution_payload.tree_hash_root()
|
||||
}
|
||||
SignedBlindedBeaconBlock::Capella(block) => {
|
||||
block.message.body.execution_payload.tree_hash_root()
|
||||
}
|
||||
SignedBlindedBeaconBlock::Deneb(block) => {
|
||||
block.message.body.execution_payload.tree_hash_root()
|
||||
}
|
||||
};
|
||||
|
||||
let block = head.data.message();
|
||||
let head_block_root = block.tree_hash_root();
|
||||
let head_execution_hash = block
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(convert_err)?
|
||||
.block_hash();
|
||||
if head_execution_hash != from_ssz_rs(&bid_request.parent_hash)? {
|
||||
return Err(custom_err(format!(
|
||||
"head mismatch: {} {}",
|
||||
head_execution_hash, bid_request.parent_hash
|
||||
)));
|
||||
}
|
||||
let fork_name = builder.spec.fork_name_at_slot::<E>(slot);
|
||||
let payload = builder
|
||||
.el
|
||||
.get_payload_by_root(&root)
|
||||
.ok_or_else(|| reject("missing payload for tx root"))?;
|
||||
let resp = ForkVersionedResponse {
|
||||
version: Some(fork_name),
|
||||
data: payload,
|
||||
};
|
||||
|
||||
let finalized_execution_hash = self
|
||||
.beacon_client
|
||||
.get_beacon_blocks::<E>(BlockId::Finalized)
|
||||
.await
|
||||
.map_err(convert_err)?
|
||||
.ok_or_else(|| convert_err("missing finalized block"))?
|
||||
.data
|
||||
.message()
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(convert_err)?
|
||||
.block_hash();
|
||||
let json_payload = serde_json::to_string(&resp)
|
||||
.map_err(|_| reject("coudn't serialize response"))?;
|
||||
Ok::<_, warp::reject::Rejection>(
|
||||
warp::http::Response::builder()
|
||||
.status(200)
|
||||
.body(
|
||||
serde_json::to_string(&json_payload)
|
||||
.map_err(|_| reject("nvalid JSON"))?,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let justified_execution_hash = self
|
||||
.beacon_client
|
||||
.get_beacon_blocks::<E>(BlockId::Justified)
|
||||
.await
|
||||
.map_err(convert_err)?
|
||||
.ok_or_else(|| convert_err("missing finalized block"))?
|
||||
.data
|
||||
.message()
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(convert_err)?
|
||||
.block_hash();
|
||||
let status = prefix
|
||||
.and(warp::path("status"))
|
||||
.then(|| async { warp::reply() });
|
||||
|
||||
let val_index = self
|
||||
.beacon_client
|
||||
.get_beacon_states_validator_id(
|
||||
StateId::Head,
|
||||
&ValidatorId::PublicKey(from_ssz_rs(&cached_data.public_key)?),
|
||||
)
|
||||
.await
|
||||
.map_err(convert_err)?
|
||||
.ok_or_else(|| convert_err("missing validator from state"))?
|
||||
.data
|
||||
.index;
|
||||
let fee_recipient = from_ssz_rs(&cached_data.fee_recipient)?;
|
||||
let slots_since_genesis = slot.as_u64() - self.spec.genesis_slot.as_u64();
|
||||
let header = prefix
|
||||
.and(warp::path("header"))
|
||||
.and(warp::path::param::<Slot>().or_else(|_| async { Err(reject("Invalid slot")) }))
|
||||
.and(
|
||||
warp::path::param::<ExecutionBlockHash>()
|
||||
.or_else(|_| async { Err(reject("Invalid parent hash")) }),
|
||||
)
|
||||
.and(
|
||||
warp::path::param::<PublicKeyBytes>()
|
||||
.or_else(|_| async { Err(reject("Invalid pubkey")) }),
|
||||
)
|
||||
.and(warp::path::end())
|
||||
.and(ctx_filter.clone())
|
||||
.and_then(
|
||||
|slot: Slot,
|
||||
parent_hash: ExecutionBlockHash,
|
||||
pubkey: PublicKeyBytes,
|
||||
builder: MockBuilder<E>| async move {
|
||||
let fork = builder.spec.fork_name_at_slot::<E>(slot);
|
||||
let signed_cached_data = builder
|
||||
.val_registration_cache
|
||||
.read()
|
||||
.get(&pubkey)
|
||||
.ok_or_else(|| reject("missing registration"))?
|
||||
.clone();
|
||||
let cached_data = signed_cached_data.message;
|
||||
|
||||
let genesis_time = self
|
||||
.beacon_client
|
||||
.get_beacon_genesis()
|
||||
.await
|
||||
.map_err(convert_err)?
|
||||
.data
|
||||
.genesis_time;
|
||||
let timestamp = (slots_since_genesis * self.spec.seconds_per_slot) + genesis_time;
|
||||
|
||||
let head_state: BeaconState<E> = self
|
||||
.beacon_client
|
||||
.get_debug_beacon_states(StateId::Head)
|
||||
.await
|
||||
.map_err(convert_err)?
|
||||
.ok_or_else(|| custom_err("missing head state".to_string()))?
|
||||
.data;
|
||||
let prev_randao = head_state
|
||||
.get_randao_mix(head_state.current_epoch())
|
||||
.map_err(convert_err)?;
|
||||
let expected_withdrawals = match fork {
|
||||
ForkName::Base | ForkName::Altair | ForkName::Merge => None,
|
||||
ForkName::Capella | ForkName::Deneb => Some(
|
||||
self.beacon_client
|
||||
.get_expected_withdrawals(&StateId::Head)
|
||||
let head = builder
|
||||
.beacon_client
|
||||
.get_beacon_blocks::<E>(BlockId::Head)
|
||||
.await
|
||||
.unwrap()
|
||||
.data,
|
||||
),
|
||||
};
|
||||
.map_err(|_| reject("couldn't get head"))?
|
||||
.ok_or_else(|| reject("missing head block"))?;
|
||||
|
||||
let payload_attributes = match fork {
|
||||
// the withdrawals root is filled in by operations, but we supply the valid withdrawals
|
||||
// first to avoid polluting the execution block generator with invalid payload attributes
|
||||
// NOTE: this was part of an effort to add payload attribute uniqueness checks,
|
||||
// which was abandoned because it broke too many tests in subtle ways.
|
||||
ForkName::Merge | ForkName::Capella => PayloadAttributes::new(
|
||||
timestamp,
|
||||
*prev_randao,
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
None,
|
||||
),
|
||||
ForkName::Deneb => PayloadAttributes::new(
|
||||
timestamp,
|
||||
*prev_randao,
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
Some(head_block_root),
|
||||
),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(MevError::InvalidFork);
|
||||
}
|
||||
};
|
||||
let block = head.data.message();
|
||||
let head_block_root = block.tree_hash_root();
|
||||
let head_execution_hash = block
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(|_| reject("pre-merge block"))?
|
||||
.block_hash();
|
||||
if head_execution_hash != parent_hash {
|
||||
return Err(reject("head mismatch"));
|
||||
}
|
||||
|
||||
self.el
|
||||
.insert_proposer(slot, head_block_root, val_index, payload_attributes.clone())
|
||||
.await;
|
||||
let finalized_execution_hash = builder
|
||||
.beacon_client
|
||||
.get_beacon_blocks::<E>(BlockId::Finalized)
|
||||
.await
|
||||
.map_err(|_| reject("couldn't get finalized block"))?
|
||||
.ok_or_else(|| reject("missing finalized block"))?
|
||||
.data
|
||||
.message()
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(|_| reject("pre-merge block"))?
|
||||
.block_hash();
|
||||
|
||||
let forkchoice_update_params = ForkchoiceUpdateParameters {
|
||||
head_root: Hash256::zero(),
|
||||
head_hash: None,
|
||||
justified_hash: Some(justified_execution_hash),
|
||||
finalized_hash: Some(finalized_execution_hash),
|
||||
};
|
||||
let justified_execution_hash = builder
|
||||
.beacon_client
|
||||
.get_beacon_blocks::<E>(BlockId::Justified)
|
||||
.await
|
||||
.map_err(|_| reject("couldn't get justified block"))?
|
||||
.ok_or_else(|| reject("missing justified block"))?
|
||||
.data
|
||||
.message()
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(|_| reject("pre-merge block"))?
|
||||
.block_hash();
|
||||
|
||||
let (payload, _block_value, maybe_blobs_bundle): (
|
||||
ExecutionPayload<E>,
|
||||
Uint256,
|
||||
Option<BlobsBundle<E>>,
|
||||
) = self
|
||||
.el
|
||||
.get_full_payload_caching(
|
||||
head_execution_hash,
|
||||
&payload_attributes,
|
||||
forkchoice_update_params,
|
||||
fork,
|
||||
)
|
||||
.await
|
||||
.map_err(convert_err)?
|
||||
.into();
|
||||
let val_index = builder
|
||||
.beacon_client
|
||||
.get_beacon_states_validator_id(StateId::Head, &ValidatorId::PublicKey(pubkey))
|
||||
.await
|
||||
.map_err(|_| reject("couldn't get validator"))?
|
||||
.ok_or_else(|| reject("missing validator"))?
|
||||
.data
|
||||
.index;
|
||||
let fee_recipient = cached_data.fee_recipient;
|
||||
let slots_since_genesis = slot.as_u64() - builder.spec.genesis_slot.as_u64();
|
||||
|
||||
let header = match payload {
|
||||
ExecutionPayload::Merge(payload) => ExecutionPayloadHeader::Merge((&payload).into()),
|
||||
ExecutionPayload::Capella(payload) => {
|
||||
ExecutionPayloadHeader::Capella((&payload).into())
|
||||
}
|
||||
ExecutionPayload::Deneb(payload) => ExecutionPayloadHeader::Deneb((&payload).into()),
|
||||
};
|
||||
let genesis_data = builder
|
||||
.beacon_client
|
||||
.get_beacon_genesis()
|
||||
.await
|
||||
.map_err(|_| reject("couldn't get beacon genesis"))?
|
||||
.data;
|
||||
let genesis_time = genesis_data.genesis_time;
|
||||
let timestamp =
|
||||
(slots_since_genesis * builder.spec.seconds_per_slot) + genesis_time;
|
||||
|
||||
let mut message = match fork {
|
||||
ForkName::Deneb => {
|
||||
let blinded_blobs: BlindedBlobsBundle<E> =
|
||||
maybe_blobs_bundle.map(Into::into).unwrap_or_default();
|
||||
BuilderBid::Deneb(BuilderBidDeneb {
|
||||
header: to_ssz_rs(&header)?,
|
||||
blinded_blobs_bundle: to_ssz_rs(&blinded_blobs)?,
|
||||
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
|
||||
public_key: self.builder_sk.public_key(),
|
||||
})
|
||||
}
|
||||
ForkName::Capella => BuilderBid::Capella(BuilderBidCapella {
|
||||
header: to_ssz_rs(&header)?,
|
||||
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
|
||||
public_key: self.builder_sk.public_key(),
|
||||
}),
|
||||
ForkName::Merge => BuilderBid::Bellatrix(BuilderBidBellatrix {
|
||||
header: to_ssz_rs(&header)?,
|
||||
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
|
||||
public_key: self.builder_sk.public_key(),
|
||||
}),
|
||||
ForkName::Base | ForkName::Altair => return Err(MevError::InvalidFork),
|
||||
};
|
||||
*message.gas_limit_mut() = cached_data.gas_limit;
|
||||
let head_state: BeaconState<E> = builder
|
||||
.beacon_client
|
||||
.get_debug_beacon_states(StateId::Head)
|
||||
.await
|
||||
.map_err(|_| reject("couldn't get state"))?
|
||||
.ok_or_else(|| reject("missing state"))?
|
||||
.data;
|
||||
let prev_randao = head_state
|
||||
.get_randao_mix(head_state.current_epoch())
|
||||
.map_err(|_| reject("couldn't get prev randao"))?;
|
||||
let expected_withdrawals = match fork {
|
||||
ForkName::Base | ForkName::Altair | ForkName::Merge => None,
|
||||
ForkName::Capella | ForkName::Deneb => Some(
|
||||
builder
|
||||
.beacon_client
|
||||
.get_expected_withdrawals(&StateId::Head)
|
||||
.await
|
||||
.unwrap()
|
||||
.data,
|
||||
),
|
||||
};
|
||||
|
||||
self.apply_operations(&mut message)?;
|
||||
let mut signature =
|
||||
message.sign_builder_message(&self.builder_sk, self.context.as_ref())?;
|
||||
let payload_attributes = match fork {
|
||||
// the withdrawals root is filled in by operations, but we supply the valid withdrawals
|
||||
// first to avoid polluting the execution block generator with invalid payload attributes
|
||||
// NOTE: this was part of an effort to add payload attribute uniqueness checks,
|
||||
// which was abandoned because it broke too many tests in subtle ways.
|
||||
ForkName::Merge | ForkName::Capella => PayloadAttributes::new(
|
||||
timestamp,
|
||||
*prev_randao,
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
None,
|
||||
),
|
||||
ForkName::Deneb => PayloadAttributes::new(
|
||||
timestamp,
|
||||
*prev_randao,
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
Some(head_block_root),
|
||||
),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(reject("invalid fork"));
|
||||
}
|
||||
};
|
||||
|
||||
if *self.invalidate_signatures.read() {
|
||||
signature = Signature::default();
|
||||
}
|
||||
builder
|
||||
.el
|
||||
.insert_proposer(slot, head_block_root, val_index, payload_attributes.clone())
|
||||
.await;
|
||||
|
||||
Ok(message.to_signed_bid(signature))
|
||||
}
|
||||
let forkchoice_update_params = ForkchoiceUpdateParameters {
|
||||
head_root: Hash256::zero(),
|
||||
head_hash: None,
|
||||
justified_hash: Some(justified_execution_hash),
|
||||
finalized_hash: Some(finalized_execution_hash),
|
||||
};
|
||||
|
||||
async fn open_bid(
|
||||
&self,
|
||||
signed_block: &mut SignedBlindedBeaconBlock,
|
||||
) -> Result<ServerPayload, MevError> {
|
||||
let node = match signed_block {
|
||||
SignedBlindedBeaconBlock::Bellatrix(block) => {
|
||||
block.message.body.execution_payload_header.hash_tree_root()
|
||||
}
|
||||
SignedBlindedBeaconBlock::Capella(block) => {
|
||||
block.message.body.execution_payload_header.hash_tree_root()
|
||||
}
|
||||
SignedBlindedBeaconBlock::Deneb(block_and_blobs) => block_and_blobs
|
||||
.signed_blinded_block
|
||||
.message
|
||||
.body
|
||||
.execution_payload_header
|
||||
.hash_tree_root(),
|
||||
}
|
||||
.map_err(convert_err)?;
|
||||
let (payload, _block_value, maybe_blobs_bundle): (
|
||||
ExecutionPayload<E>,
|
||||
Uint256,
|
||||
Option<BlobsBundle<E>>,
|
||||
) = builder
|
||||
.el
|
||||
.get_full_payload_caching(
|
||||
head_execution_hash,
|
||||
&payload_attributes,
|
||||
forkchoice_update_params,
|
||||
fork,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| reject("couldn't get payload"))?
|
||||
.into();
|
||||
|
||||
let payload = self
|
||||
.el
|
||||
.get_payload_by_root(&from_ssz_rs(&node)?)
|
||||
.ok_or_else(|| convert_err("missing payload for tx root"))?;
|
||||
let mut message = match fork {
|
||||
ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb {
|
||||
header: payload
|
||||
.as_deneb()
|
||||
.map_err(|_| reject("incorrect payload variant"))?
|
||||
.into(),
|
||||
blinded_blobs_bundle: maybe_blobs_bundle
|
||||
.map(Into::into)
|
||||
.unwrap_or_default(),
|
||||
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
|
||||
pubkey: builder.builder_sk.public_key().compress(),
|
||||
}),
|
||||
ForkName::Capella => BuilderBid::Capella(BuilderBidCapella {
|
||||
header: payload
|
||||
.as_capella()
|
||||
.map_err(|_| reject("incorrect payload variant"))?
|
||||
.into(),
|
||||
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
|
||||
pubkey: builder.builder_sk.public_key().compress(),
|
||||
}),
|
||||
ForkName::Merge => BuilderBid::Merge(BuilderBidMerge {
|
||||
header: payload
|
||||
.as_merge()
|
||||
.map_err(|_| reject("incorrect payload variant"))?
|
||||
.into(),
|
||||
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
|
||||
pubkey: builder.builder_sk.public_key().compress(),
|
||||
}),
|
||||
ForkName::Base | ForkName::Altair => return Err(reject("invalid fork")),
|
||||
};
|
||||
|
||||
let fork = payload.payload_ref().fork_name();
|
||||
let resp = ForkVersionedResponse {
|
||||
version: Some(fork),
|
||||
data: payload,
|
||||
};
|
||||
message.set_gas_limit(cached_data.gas_limit);
|
||||
|
||||
let json_payload = serde_json::to_string(&resp).map_err(convert_err)?;
|
||||
serde_json::from_str(json_payload.as_str()).map_err(convert_err)
|
||||
}
|
||||
builder.apply_operations(&mut message);
|
||||
|
||||
let mut signature =
|
||||
message.sign_builder_message(&builder.builder_sk, &builder.spec);
|
||||
|
||||
if *builder.invalidate_signatures.read() {
|
||||
signature = Signature::empty();
|
||||
}
|
||||
|
||||
let fork_name = builder
|
||||
.spec
|
||||
.fork_name_at_epoch(slot.epoch(E::slots_per_epoch()));
|
||||
let signed_bid = SignedBuilderBid { message, signature };
|
||||
let resp = ForkVersionedResponse {
|
||||
version: Some(fork_name),
|
||||
data: signed_bid,
|
||||
};
|
||||
let json_bid = serde_json::to_string(&resp)
|
||||
.map_err(|_| reject("coudn't serialize signed bid"))?;
|
||||
Ok::<_, Rejection>(
|
||||
warp::http::Response::builder()
|
||||
.status(200)
|
||||
.body(json_bid)
|
||||
.unwrap(),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let routes = warp::post()
|
||||
.and(validators.or(blinded_block))
|
||||
.or(warp::get().and(status).or(header))
|
||||
.map(|reply| warp::reply::with_header(reply, "Server", "lighthouse-mock-builder-server"));
|
||||
|
||||
let (listening_socket, server) = warp::serve(routes)
|
||||
.try_bind_ephemeral(SocketAddrV4::new(listen_addr, listen_port))
|
||||
.expect("mock builder server should start");
|
||||
Ok((listening_socket, server))
|
||||
}
|
||||
|
||||
pub fn from_ssz_rs<T: SimpleSerialize, U: Decode>(ssz_rs_data: &T) -> Result<U, MevError> {
|
||||
U::from_ssz_bytes(
|
||||
ssz_rs::serialize(ssz_rs_data)
|
||||
.map_err(convert_err)?
|
||||
.as_ref(),
|
||||
)
|
||||
.map_err(convert_err)
|
||||
}
|
||||
|
||||
pub fn to_ssz_rs<T: Encode, U: SimpleSerialize>(ssz_data: &T) -> Result<U, MevError> {
|
||||
ssz_rs::deserialize::<U>(&ssz_data.as_ssz_bytes()).map_err(convert_err)
|
||||
}
|
||||
|
||||
pub fn convert_err<E: Debug>(e: E) -> MevError {
|
||||
custom_err(format!("{e:?}"))
|
||||
}
|
||||
|
||||
// This is a bit of a hack since the `Custom` variant was removed from `mev_rs::Error`.
|
||||
pub fn custom_err(s: String) -> MevError {
|
||||
MevError::Consensus(ethereum_consensus::state_transition::Error::Io(
|
||||
std::io::Error::new(std::io::ErrorKind::Other, s),
|
||||
))
|
||||
fn reject(msg: &'static str) -> Rejection {
|
||||
warp::reject::custom(Custom(msg.to_string()))
|
||||
}
|
||||
|
@ -29,10 +29,7 @@ pub use execution_block_generator::{
|
||||
Block, ExecutionBlockGenerator,
|
||||
};
|
||||
pub use hook::Hook;
|
||||
pub use mock_builder::{
|
||||
convert_err, custom_err, from_ssz_rs, to_ssz_rs, Context as MockBuilderContext, MockBuilder,
|
||||
MockBuilderServer, Operation,
|
||||
};
|
||||
pub use mock_builder::{MockBuilder, Operation};
|
||||
pub use mock_execution_layer::MockExecutionLayer;
|
||||
|
||||
pub const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400;
|
||||
|
@ -1632,13 +1632,19 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
|block_id: BlockId,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>| {
|
||||
task_spawner.blocking_json_task(Priority::P1, move || {
|
||||
let (block, execution_optimistic, finalized) =
|
||||
block_id.blinded_block(&chain)?;
|
||||
Ok(api_types::GenericResponse::from(api_types::RootData::from(
|
||||
block.canonical_root(),
|
||||
))
|
||||
.add_execution_optimistic_finalized(execution_optimistic, finalized))
|
||||
// Prioritise requests for the head block root, as it is used by some VCs (including
|
||||
// the Lighthouse VC) to create sync committee messages.
|
||||
let priority = if let BlockId(eth2::types::BlockId::Head) = block_id {
|
||||
Priority::P0
|
||||
} else {
|
||||
Priority::P1
|
||||
};
|
||||
task_spawner.blocking_json_task(priority, move || {
|
||||
let (block_root, execution_optimistic, finalized) = block_id.root(&chain)?;
|
||||
Ok(
|
||||
api_types::GenericResponse::from(api_types::RootData::from(block_root))
|
||||
.add_execution_optimistic_finalized(execution_optimistic, finalized),
|
||||
)
|
||||
})
|
||||
},
|
||||
);
|
||||
|
@ -267,11 +267,7 @@ impl ApiTester {
|
||||
|
||||
// Start the mock builder service prior to building the chain out.
|
||||
harness.runtime.task_executor.spawn(
|
||||
async move {
|
||||
if let Err(e) = mock_builder_server.await {
|
||||
panic!("error in mock builder server: {e:?}");
|
||||
}
|
||||
},
|
||||
async move { mock_builder_server.await },
|
||||
"mock_builder_server",
|
||||
);
|
||||
|
||||
|
@ -11,11 +11,17 @@ use libp2p::Multiaddr;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::num::NonZeroU16;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use types::{ForkContext, ForkName};
|
||||
|
||||
pub const DEFAULT_IPV4_ADDRESS: Ipv4Addr = Ipv4Addr::UNSPECIFIED;
|
||||
pub const DEFAULT_TCP_PORT: u16 = 9000u16;
|
||||
pub const DEFAULT_DISC_PORT: u16 = 9000u16;
|
||||
pub const DEFAULT_QUIC_PORT: u16 = 9001u16;
|
||||
|
||||
/// The cache time is set to accommodate the circulation time of an attestation.
|
||||
///
|
||||
/// The p2p spec declares that we accept attestations within the following range:
|
||||
@ -59,22 +65,22 @@ pub struct Config {
|
||||
pub enr_address: (Option<Ipv4Addr>, Option<Ipv6Addr>),
|
||||
|
||||
/// The udp ipv4 port to broadcast to peers in order to reach back for discovery.
|
||||
pub enr_udp4_port: Option<u16>,
|
||||
pub enr_udp4_port: Option<NonZeroU16>,
|
||||
|
||||
/// The quic ipv4 port to broadcast to peers in order to reach back for libp2p services.
|
||||
pub enr_quic4_port: Option<u16>,
|
||||
pub enr_quic4_port: Option<NonZeroU16>,
|
||||
|
||||
/// The tcp ipv4 port to broadcast to peers in order to reach back for libp2p services.
|
||||
pub enr_tcp4_port: Option<u16>,
|
||||
pub enr_tcp4_port: Option<NonZeroU16>,
|
||||
|
||||
/// The udp ipv6 port to broadcast to peers in order to reach back for discovery.
|
||||
pub enr_udp6_port: Option<u16>,
|
||||
pub enr_udp6_port: Option<NonZeroU16>,
|
||||
|
||||
/// The tcp ipv6 port to broadcast to peers in order to reach back for libp2p services.
|
||||
pub enr_tcp6_port: Option<u16>,
|
||||
pub enr_tcp6_port: Option<NonZeroU16>,
|
||||
|
||||
/// The quic ipv6 port to broadcast to peers in order to reach back for libp2p services.
|
||||
pub enr_quic6_port: Option<u16>,
|
||||
pub enr_quic6_port: Option<NonZeroU16>,
|
||||
|
||||
/// Target number of connected peers.
|
||||
pub target_peers: usize,
|
||||
@ -304,10 +310,10 @@ impl Default for Config {
|
||||
.expect("The total rate limit has been specified"),
|
||||
);
|
||||
let listen_addresses = ListenAddress::V4(ListenAddr {
|
||||
addr: Ipv4Addr::UNSPECIFIED,
|
||||
disc_port: 9000,
|
||||
quic_port: 9001,
|
||||
tcp_port: 9000,
|
||||
addr: DEFAULT_IPV4_ADDRESS,
|
||||
disc_port: DEFAULT_DISC_PORT,
|
||||
quic_port: DEFAULT_QUIC_PORT,
|
||||
tcp_port: DEFAULT_TCP_PORT,
|
||||
});
|
||||
|
||||
let discv5_listen_config =
|
||||
|
@ -158,11 +158,11 @@ pub fn create_enr_builder_from_config<T: EnrKey>(
|
||||
}
|
||||
|
||||
if let Some(udp4_port) = config.enr_udp4_port {
|
||||
builder.udp4(udp4_port);
|
||||
builder.udp4(udp4_port.get());
|
||||
}
|
||||
|
||||
if let Some(udp6_port) = config.enr_udp6_port {
|
||||
builder.udp6(udp6_port);
|
||||
builder.udp6(udp6_port.get());
|
||||
}
|
||||
|
||||
if enable_libp2p {
|
||||
@ -171,35 +171,45 @@ pub fn create_enr_builder_from_config<T: EnrKey>(
|
||||
// the related fields should only be added when both QUIC and libp2p are enabled
|
||||
if !config.disable_quic_support {
|
||||
// If we are listening on ipv4, add the quic ipv4 port.
|
||||
if let Some(quic4_port) = config
|
||||
.enr_quic4_port
|
||||
.or_else(|| config.listen_addrs().v4().map(|v4_addr| v4_addr.quic_port))
|
||||
{
|
||||
builder.add_value(QUIC_ENR_KEY, &quic4_port);
|
||||
if let Some(quic4_port) = config.enr_quic4_port.or_else(|| {
|
||||
config
|
||||
.listen_addrs()
|
||||
.v4()
|
||||
.and_then(|v4_addr| v4_addr.quic_port.try_into().ok())
|
||||
}) {
|
||||
builder.add_value(QUIC_ENR_KEY, &quic4_port.get());
|
||||
}
|
||||
|
||||
// If we are listening on ipv6, add the quic ipv6 port.
|
||||
if let Some(quic6_port) = config
|
||||
.enr_quic6_port
|
||||
.or_else(|| config.listen_addrs().v6().map(|v6_addr| v6_addr.quic_port))
|
||||
{
|
||||
builder.add_value(QUIC6_ENR_KEY, &quic6_port);
|
||||
if let Some(quic6_port) = config.enr_quic6_port.or_else(|| {
|
||||
config
|
||||
.listen_addrs()
|
||||
.v6()
|
||||
.and_then(|v6_addr| v6_addr.quic_port.try_into().ok())
|
||||
}) {
|
||||
builder.add_value(QUIC6_ENR_KEY, &quic6_port.get());
|
||||
}
|
||||
}
|
||||
|
||||
// If the ENR port is not set, and we are listening over that ip version, use the listening port instead.
|
||||
let tcp4_port = config
|
||||
.enr_tcp4_port
|
||||
.or_else(|| config.listen_addrs().v4().map(|v4_addr| v4_addr.tcp_port));
|
||||
let tcp4_port = config.enr_tcp4_port.or_else(|| {
|
||||
config
|
||||
.listen_addrs()
|
||||
.v4()
|
||||
.and_then(|v4_addr| v4_addr.tcp_port.try_into().ok())
|
||||
});
|
||||
if let Some(tcp4_port) = tcp4_port {
|
||||
builder.tcp4(tcp4_port);
|
||||
builder.tcp4(tcp4_port.get());
|
||||
}
|
||||
|
||||
let tcp6_port = config
|
||||
.enr_tcp6_port
|
||||
.or_else(|| config.listen_addrs().v6().map(|v6_addr| v6_addr.tcp_port));
|
||||
let tcp6_port = config.enr_tcp6_port.or_else(|| {
|
||||
config
|
||||
.listen_addrs()
|
||||
.v6()
|
||||
.and_then(|v6_addr| v6_addr.tcp_port.try_into().ok())
|
||||
});
|
||||
if let Some(tcp6_port) = tcp6_port {
|
||||
builder.tcp6(tcp6_port);
|
||||
builder.tcp6(tcp6_port.get());
|
||||
}
|
||||
}
|
||||
builder
|
||||
|
@ -21,10 +21,11 @@ pub use libp2p::identity::{Keypair, PublicKey};
|
||||
use enr::{ATTESTATION_BITFIELD_ENR_KEY, ETH2_ENR_KEY, SYNC_COMMITTEE_BITFIELD_ENR_KEY};
|
||||
use futures::prelude::*;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use libp2p::multiaddr::Protocol;
|
||||
use libp2p::swarm::behaviour::{DialFailure, FromSwarm};
|
||||
use libp2p::swarm::THandlerInEvent;
|
||||
pub use libp2p::{
|
||||
core::{ConnectedPoint, Multiaddr},
|
||||
core::{transport::ListenerId, ConnectedPoint, Multiaddr},
|
||||
identity::PeerId,
|
||||
swarm::{
|
||||
dummy::ConnectionHandler, ConnectionId, DialError, NetworkBehaviour, NotifyHandler,
|
||||
@ -77,6 +78,19 @@ pub struct DiscoveredPeers {
|
||||
pub peers: HashMap<Enr, Option<Instant>>,
|
||||
}
|
||||
|
||||
/// Specifies which port numbers should be modified after start of the discovery service
|
||||
#[derive(Debug)]
|
||||
pub struct UpdatePorts {
|
||||
/// TCP port associated wih IPv4 address (if present)
|
||||
pub tcp4: bool,
|
||||
/// TCP port associated wih IPv6 address (if present)
|
||||
pub tcp6: bool,
|
||||
/// QUIC port associated wih IPv4 address (if present)
|
||||
pub quic4: bool,
|
||||
/// QUIC port associated wih IPv6 address (if present)
|
||||
pub quic6: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct SubnetQuery {
|
||||
subnet: Subnet,
|
||||
@ -177,12 +191,8 @@ pub struct Discovery<TSpec: EthSpec> {
|
||||
/// always false.
|
||||
pub started: bool,
|
||||
|
||||
/// This keeps track of whether an external UDP port change should also indicate an internal
|
||||
/// TCP port change. As we cannot detect our external TCP port, we assume that the external UDP
|
||||
/// port is also our external TCP port. This assumption only holds if the user has not
|
||||
/// explicitly set their ENR TCP port via the CLI config. The first indicates tcp4 and the
|
||||
/// second indicates tcp6.
|
||||
update_tcp_port: (bool, bool),
|
||||
/// Specifies whether various port numbers should be updated after the discovery service has been started
|
||||
update_ports: UpdatePorts,
|
||||
|
||||
/// Logger for the discovery behaviour.
|
||||
log: slog::Logger,
|
||||
@ -300,10 +310,12 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
let update_tcp_port = (
|
||||
config.enr_tcp4_port.is_none(),
|
||||
config.enr_tcp6_port.is_none(),
|
||||
);
|
||||
let update_ports = UpdatePorts {
|
||||
tcp4: config.enr_tcp4_port.is_none(),
|
||||
tcp6: config.enr_tcp6_port.is_none(),
|
||||
quic4: config.enr_quic4_port.is_none(),
|
||||
quic6: config.enr_quic6_port.is_none(),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
cached_enrs: LruCache::new(50),
|
||||
@ -314,7 +326,7 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
discv5,
|
||||
event_stream,
|
||||
started: !config.disable_discovery,
|
||||
update_tcp_port,
|
||||
update_ports,
|
||||
log,
|
||||
enr_dir,
|
||||
})
|
||||
@ -555,8 +567,6 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
if let Ok(node_id) = peer_id_to_node_id(peer_id) {
|
||||
// If we could convert this peer id, remove it from the DHT and ban it from discovery.
|
||||
self.discv5.ban_node(&node_id, None);
|
||||
// Remove the node from the routing table.
|
||||
self.discv5.remove_node(&node_id);
|
||||
}
|
||||
|
||||
for ip_address in ip_addresses {
|
||||
@ -1006,8 +1016,8 @@ impl<TSpec: EthSpec> NetworkBehaviour for Discovery<TSpec> {
|
||||
// Discv5 will have updated our local ENR. We save the updated version
|
||||
// to disk.
|
||||
|
||||
if (self.update_tcp_port.0 && socket_addr.is_ipv4())
|
||||
|| (self.update_tcp_port.1 && socket_addr.is_ipv6())
|
||||
if (self.update_ports.tcp4 && socket_addr.is_ipv4())
|
||||
|| (self.update_ports.tcp6 && socket_addr.is_ipv6())
|
||||
{
|
||||
// Update the TCP port in the ENR
|
||||
self.discv5.update_local_enr_socket(socket_addr, true);
|
||||
@ -1036,12 +1046,79 @@ impl<TSpec: EthSpec> NetworkBehaviour for Discovery<TSpec> {
|
||||
FromSwarm::DialFailure(DialFailure { peer_id, error, .. }) => {
|
||||
self.on_dial_failure(peer_id, error)
|
||||
}
|
||||
FromSwarm::NewListenAddr(ev) => {
|
||||
let addr = ev.addr;
|
||||
let listener_id = ev.listener_id;
|
||||
|
||||
trace!(self.log, "Received NewListenAddr event from swarm"; "listener_id" => ?listener_id, "addr" => ?addr);
|
||||
|
||||
let mut addr_iter = addr.iter();
|
||||
|
||||
let attempt_enr_update = match addr_iter.next() {
|
||||
Some(Protocol::Ip4(_)) => match (addr_iter.next(), addr_iter.next()) {
|
||||
(Some(Protocol::Tcp(port)), None) => {
|
||||
if !self.update_ports.tcp4 {
|
||||
debug!(self.log, "Skipping ENR update"; "multiaddr" => ?addr);
|
||||
return;
|
||||
}
|
||||
|
||||
self.update_enr_tcp_port(port)
|
||||
}
|
||||
(Some(Protocol::Udp(port)), Some(Protocol::QuicV1)) => {
|
||||
if !self.update_ports.quic4 {
|
||||
debug!(self.log, "Skipping ENR update"; "multiaddr" => ?addr);
|
||||
return;
|
||||
}
|
||||
|
||||
self.update_enr_quic_port(port)
|
||||
}
|
||||
_ => {
|
||||
debug!(self.log, "Encountered unacceptable multiaddr for listening (unsupported transport)"; "addr" => ?addr);
|
||||
return;
|
||||
}
|
||||
},
|
||||
Some(Protocol::Ip6(_)) => match (addr_iter.next(), addr_iter.next()) {
|
||||
(Some(Protocol::Tcp(port)), None) => {
|
||||
if !self.update_ports.tcp6 {
|
||||
debug!(self.log, "Skipping ENR update"; "multiaddr" => ?addr);
|
||||
return;
|
||||
}
|
||||
|
||||
self.update_enr_tcp_port(port)
|
||||
}
|
||||
(Some(Protocol::Udp(port)), Some(Protocol::QuicV1)) => {
|
||||
if !self.update_ports.quic6 {
|
||||
debug!(self.log, "Skipping ENR update"; "multiaddr" => ?addr);
|
||||
return;
|
||||
}
|
||||
|
||||
self.update_enr_quic_port(port)
|
||||
}
|
||||
_ => {
|
||||
debug!(self.log, "Encountered unacceptable multiaddr for listening (unsupported transport)"; "addr" => ?addr);
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
debug!(self.log, "Encountered unacceptable multiaddr for listening (no IP)"; "addr" => ?addr);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let local_enr: Enr = self.discv5.local_enr();
|
||||
|
||||
match attempt_enr_update {
|
||||
Ok(_) => {
|
||||
info!(self.log, "Updated local ENR"; "enr" => local_enr.to_base64(), "seq" => local_enr.seq(), "id"=> %local_enr.node_id(), "ip4" => ?local_enr.ip4(), "udp4"=> ?local_enr.udp4(), "tcp4" => ?local_enr.tcp4(), "tcp6" => ?local_enr.tcp6(), "udp6" => ?local_enr.udp6())
|
||||
}
|
||||
Err(e) => warn!(self.log, "Failed to update ENR"; "error" => ?e),
|
||||
}
|
||||
}
|
||||
FromSwarm::ConnectionEstablished(_)
|
||||
| FromSwarm::ConnectionClosed(_)
|
||||
| FromSwarm::AddressChange(_)
|
||||
| FromSwarm::ListenFailure(_)
|
||||
| FromSwarm::NewListener(_)
|
||||
| FromSwarm::NewListenAddr(_)
|
||||
| FromSwarm::ExpiredListenAddr(_)
|
||||
| FromSwarm::ListenerError(_)
|
||||
| FromSwarm::ListenerClosed(_)
|
||||
|
@ -415,7 +415,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
/// Reports if a peer is banned or not.
|
||||
///
|
||||
/// This is used to determine if we should accept incoming connections.
|
||||
pub fn ban_status(&self, peer_id: &PeerId) -> BanResult {
|
||||
pub fn ban_status(&self, peer_id: &PeerId) -> Option<BanResult> {
|
||||
self.network_globals.peers.read().ban_status(peer_id)
|
||||
}
|
||||
|
||||
@ -815,7 +815,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
) -> bool {
|
||||
{
|
||||
let mut peerdb = self.network_globals.peers.write();
|
||||
if !matches!(peerdb.ban_status(peer_id), BanResult::NotBanned) {
|
||||
if peerdb.ban_status(peer_id).is_some() {
|
||||
// don't connect if the peer is banned
|
||||
error!(self.log, "Connection has been allowed to a banned peer"; "peer_id" => %peer_id);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! Implementation of [`NetworkBehaviour`] for the [`PeerManager`].
|
||||
|
||||
use std::net::IpAddr;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::StreamExt;
|
||||
@ -8,17 +9,17 @@ use libp2p::identity::PeerId;
|
||||
use libp2p::swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm};
|
||||
use libp2p::swarm::dial_opts::{DialOpts, PeerCondition};
|
||||
use libp2p::swarm::dummy::ConnectionHandler;
|
||||
use libp2p::swarm::{ConnectionId, NetworkBehaviour, PollParameters, ToSwarm};
|
||||
use slog::{debug, error};
|
||||
use libp2p::swarm::{ConnectionDenied, ConnectionId, NetworkBehaviour, PollParameters, ToSwarm};
|
||||
use slog::{debug, error, trace};
|
||||
use types::EthSpec;
|
||||
|
||||
use crate::discovery::enr_ext::EnrExt;
|
||||
use crate::peer_manager::peerdb::BanResult;
|
||||
use crate::rpc::GoodbyeReason;
|
||||
use crate::types::SyncState;
|
||||
use crate::{metrics, ClearDialError};
|
||||
|
||||
use super::peerdb::BanResult;
|
||||
use super::{ConnectingType, PeerManager, PeerManagerEvent, ReportSource};
|
||||
use super::{ConnectingType, PeerManager, PeerManagerEvent};
|
||||
|
||||
impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
|
||||
type ConnectionHandler = ConnectionHandler;
|
||||
@ -169,26 +170,64 @@ impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_pending_inbound_connection(
|
||||
&mut self,
|
||||
_connection_id: ConnectionId,
|
||||
_local_addr: &libp2p::Multiaddr,
|
||||
remote_addr: &libp2p::Multiaddr,
|
||||
) -> Result<(), ConnectionDenied> {
|
||||
// get the IP address to verify it's not banned.
|
||||
let ip = match remote_addr.iter().next() {
|
||||
Some(libp2p::multiaddr::Protocol::Ip6(ip)) => IpAddr::V6(ip),
|
||||
Some(libp2p::multiaddr::Protocol::Ip4(ip)) => IpAddr::V4(ip),
|
||||
_ => {
|
||||
return Err(ConnectionDenied::new(format!(
|
||||
"Connection to peer rejected: invalid multiaddr: {remote_addr}"
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
if self.network_globals.peers.read().is_ip_banned(&ip) {
|
||||
return Err(ConnectionDenied::new(format!(
|
||||
"Connection to peer rejected: peer {ip} is banned"
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_established_inbound_connection(
|
||||
&mut self,
|
||||
_connection_id: ConnectionId,
|
||||
_peer: PeerId,
|
||||
peer_id: PeerId,
|
||||
_local_addr: &libp2p::Multiaddr,
|
||||
_remote_addr: &libp2p::Multiaddr,
|
||||
) -> Result<libp2p::swarm::THandler<Self>, libp2p::swarm::ConnectionDenied> {
|
||||
// TODO: we might want to check if we accept this peer or not in the future.
|
||||
remote_addr: &libp2p::Multiaddr,
|
||||
) -> Result<libp2p::swarm::THandler<Self>, ConnectionDenied> {
|
||||
trace!(self.log, "Inbound connection"; "peer_id" => %peer_id, "multiaddr" => %remote_addr);
|
||||
// We already checked if the peer was banned on `handle_pending_inbound_connection`.
|
||||
if let Some(BanResult::BadScore) = self.ban_status(&peer_id) {
|
||||
return Err(ConnectionDenied::new(
|
||||
"Connection to peer rejected: peer has a bad score",
|
||||
));
|
||||
}
|
||||
Ok(ConnectionHandler)
|
||||
}
|
||||
|
||||
fn handle_established_outbound_connection(
|
||||
&mut self,
|
||||
_connection_id: ConnectionId,
|
||||
_peer: PeerId,
|
||||
_addr: &libp2p::Multiaddr,
|
||||
peer_id: PeerId,
|
||||
addr: &libp2p::Multiaddr,
|
||||
_role_override: libp2p::core::Endpoint,
|
||||
) -> Result<libp2p::swarm::THandler<Self>, libp2p::swarm::ConnectionDenied> {
|
||||
// TODO: we might want to check if we accept this peer or not in the future.
|
||||
Ok(ConnectionHandler)
|
||||
trace!(self.log, "Outbound connection"; "peer_id" => %peer_id, "multiaddr" => %addr);
|
||||
match self.ban_status(&peer_id) {
|
||||
Some(cause) => {
|
||||
error!(self.log, "Connected a banned peer. Rejecting connection"; "peer_id" => %peer_id);
|
||||
Err(ConnectionDenied::new(cause))
|
||||
}
|
||||
None => Ok(ConnectionHandler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,10 +254,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
|
||||
// increment prometheus metrics
|
||||
if self.metrics_enabled {
|
||||
let remote_addr = match endpoint {
|
||||
ConnectedPoint::Dialer { address, .. } => address,
|
||||
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
|
||||
};
|
||||
let remote_addr = endpoint.get_remote_address();
|
||||
match remote_addr.iter().find(|proto| {
|
||||
matches!(
|
||||
proto,
|
||||
@ -241,28 +277,6 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
|
||||
}
|
||||
|
||||
// Check to make sure the peer is not supposed to be banned
|
||||
match self.ban_status(&peer_id) {
|
||||
// TODO: directly emit the ban event?
|
||||
BanResult::BadScore => {
|
||||
// This is a faulty state
|
||||
error!(self.log, "Connected to a banned peer. Re-banning"; "peer_id" => %peer_id);
|
||||
// Disconnect the peer.
|
||||
self.goodbye_peer(&peer_id, GoodbyeReason::Banned, ReportSource::PeerManager);
|
||||
// Re-ban the peer to prevent repeated errors.
|
||||
self.events.push(PeerManagerEvent::Banned(peer_id, vec![]));
|
||||
return;
|
||||
}
|
||||
BanResult::BannedIp(ip_addr) => {
|
||||
// A good peer has connected to us via a banned IP address. We ban the peer and
|
||||
// prevent future connections.
|
||||
debug!(self.log, "Peer connected via banned IP. Banning"; "peer_id" => %peer_id, "banned_ip" => %ip_addr);
|
||||
self.goodbye_peer(&peer_id, GoodbyeReason::BannedIP, ReportSource::PeerManager);
|
||||
return;
|
||||
}
|
||||
BanResult::NotBanned => {}
|
||||
}
|
||||
|
||||
// Count dialing peers in the limit if the peer dialed us.
|
||||
let count_dialing = endpoint.is_listener();
|
||||
// Check the connection limits
|
||||
@ -326,11 +340,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
// reference so that peer manager can track this peer.
|
||||
self.inject_disconnect(&peer_id);
|
||||
|
||||
let remote_addr = match endpoint {
|
||||
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
|
||||
ConnectedPoint::Dialer { address, .. } => address,
|
||||
};
|
||||
|
||||
let remote_addr = endpoint.get_remote_address();
|
||||
// Update the prometheus metrics
|
||||
if self.metrics_enabled {
|
||||
match remote_addr.iter().find(|proto| {
|
||||
|
@ -3,10 +3,13 @@ use peer_info::{ConnectionDirection, PeerConnectionStatus, PeerInfo};
|
||||
use rand::seq::SliceRandom;
|
||||
use score::{PeerAction, ReportSource, Score, ScoreState};
|
||||
use slog::{crit, debug, error, trace, warn};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::IpAddr;
|
||||
use std::time::Instant;
|
||||
use std::{cmp::Ordering, fmt::Display};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::Formatter,
|
||||
};
|
||||
use sync_status::SyncStatus;
|
||||
use types::EthSpec;
|
||||
|
||||
@ -136,26 +139,18 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current [`BanResult`] of the peer. This doesn't check the connection state, rather the
|
||||
/// Returns the current [`BanResult`] of the peer if banned. This doesn't check the connection state, rather the
|
||||
/// underlying score of the peer. A peer may be banned but still in the connected state
|
||||
/// temporarily.
|
||||
///
|
||||
/// This is used to determine if we should accept incoming connections or not.
|
||||
pub fn ban_status(&self, peer_id: &PeerId) -> BanResult {
|
||||
if let Some(peer) = self.peers.get(peer_id) {
|
||||
match peer.score_state() {
|
||||
ScoreState::Banned => BanResult::BadScore,
|
||||
_ => {
|
||||
if let Some(ip) = self.ip_is_banned(peer) {
|
||||
BanResult::BannedIp(ip)
|
||||
} else {
|
||||
BanResult::NotBanned
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BanResult::NotBanned
|
||||
}
|
||||
pub fn ban_status(&self, peer_id: &PeerId) -> Option<BanResult> {
|
||||
self.peers
|
||||
.get(peer_id)
|
||||
.and_then(|peer| match peer.score_state() {
|
||||
ScoreState::Banned => Some(BanResult::BadScore),
|
||||
_ => self.ip_is_banned(peer).map(BanResult::BannedIp),
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if the peer's known addresses are currently banned.
|
||||
@ -1183,23 +1178,25 @@ pub enum BanOperation {
|
||||
}
|
||||
|
||||
/// When checking if a peer is banned, it can be banned for multiple reasons.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum BanResult {
|
||||
/// The peer's score is too low causing it to be banned.
|
||||
BadScore,
|
||||
/// The peer should be banned because it is connecting from a banned IP address.
|
||||
BannedIp(IpAddr),
|
||||
/// The peer is not banned.
|
||||
NotBanned,
|
||||
}
|
||||
|
||||
// Helper function for unit tests
|
||||
#[cfg(test)]
|
||||
impl BanResult {
|
||||
pub fn is_banned(&self) -> bool {
|
||||
!matches!(self, BanResult::NotBanned)
|
||||
impl Display for BanResult {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
BanResult::BadScore => write!(f, "Peer has a bad score"),
|
||||
BanResult::BannedIp(addr) => write!(f, "Peer address: {} is banned", addr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for BanResult {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BannedPeersCount {
|
||||
/// The number of banned peers in the database.
|
||||
@ -1852,11 +1849,11 @@ mod tests {
|
||||
}
|
||||
|
||||
//check that ip1 and ip2 are banned but ip3-5 not
|
||||
assert!(pdb.ban_status(&p1).is_banned());
|
||||
assert!(pdb.ban_status(&p2).is_banned());
|
||||
assert!(!pdb.ban_status(&p3).is_banned());
|
||||
assert!(!pdb.ban_status(&p4).is_banned());
|
||||
assert!(!pdb.ban_status(&p5).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_some());
|
||||
assert!(pdb.ban_status(&p2).is_some());
|
||||
assert!(pdb.ban_status(&p3).is_none());
|
||||
assert!(pdb.ban_status(&p4).is_none());
|
||||
assert!(pdb.ban_status(&p5).is_none());
|
||||
|
||||
//ban also the last peer in peers
|
||||
let _ = pdb.report_peer(
|
||||
@ -1868,11 +1865,11 @@ mod tests {
|
||||
pdb.inject_disconnect(&peers[BANNED_PEERS_PER_IP_THRESHOLD + 1]);
|
||||
|
||||
//check that ip1-ip4 are banned but ip5 not
|
||||
assert!(pdb.ban_status(&p1).is_banned());
|
||||
assert!(pdb.ban_status(&p2).is_banned());
|
||||
assert!(pdb.ban_status(&p3).is_banned());
|
||||
assert!(pdb.ban_status(&p4).is_banned());
|
||||
assert!(!pdb.ban_status(&p5).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_some());
|
||||
assert!(pdb.ban_status(&p2).is_some());
|
||||
assert!(pdb.ban_status(&p3).is_some());
|
||||
assert!(pdb.ban_status(&p4).is_some());
|
||||
assert!(pdb.ban_status(&p5).is_none());
|
||||
|
||||
//peers[0] gets unbanned
|
||||
reset_score(&mut pdb, &peers[0]);
|
||||
@ -1880,11 +1877,11 @@ mod tests {
|
||||
let _ = pdb.shrink_to_fit();
|
||||
|
||||
//nothing changed
|
||||
assert!(pdb.ban_status(&p1).is_banned());
|
||||
assert!(pdb.ban_status(&p2).is_banned());
|
||||
assert!(pdb.ban_status(&p3).is_banned());
|
||||
assert!(pdb.ban_status(&p4).is_banned());
|
||||
assert!(!pdb.ban_status(&p5).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_some());
|
||||
assert!(pdb.ban_status(&p2).is_some());
|
||||
assert!(pdb.ban_status(&p3).is_some());
|
||||
assert!(pdb.ban_status(&p4).is_some());
|
||||
assert!(pdb.ban_status(&p5).is_none());
|
||||
|
||||
//peers[1] gets unbanned
|
||||
reset_score(&mut pdb, &peers[1]);
|
||||
@ -1892,11 +1889,11 @@ mod tests {
|
||||
let _ = pdb.shrink_to_fit();
|
||||
|
||||
//all ips are unbanned
|
||||
assert!(!pdb.ban_status(&p1).is_banned());
|
||||
assert!(!pdb.ban_status(&p2).is_banned());
|
||||
assert!(!pdb.ban_status(&p3).is_banned());
|
||||
assert!(!pdb.ban_status(&p4).is_banned());
|
||||
assert!(!pdb.ban_status(&p5).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_none());
|
||||
assert!(pdb.ban_status(&p2).is_none());
|
||||
assert!(pdb.ban_status(&p3).is_none());
|
||||
assert!(pdb.ban_status(&p4).is_none());
|
||||
assert!(pdb.ban_status(&p5).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1921,8 +1918,8 @@ mod tests {
|
||||
}
|
||||
|
||||
// check ip is banned
|
||||
assert!(pdb.ban_status(&p1).is_banned());
|
||||
assert!(!pdb.ban_status(&p2).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_some());
|
||||
assert!(pdb.ban_status(&p2).is_none());
|
||||
|
||||
// unban a peer
|
||||
reset_score(&mut pdb, &peers[0]);
|
||||
@ -1930,8 +1927,8 @@ mod tests {
|
||||
let _ = pdb.shrink_to_fit();
|
||||
|
||||
// check not banned anymore
|
||||
assert!(!pdb.ban_status(&p1).is_banned());
|
||||
assert!(!pdb.ban_status(&p2).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_none());
|
||||
assert!(pdb.ban_status(&p2).is_none());
|
||||
|
||||
// unban all peers
|
||||
for p in &peers {
|
||||
@ -1950,8 +1947,8 @@ mod tests {
|
||||
}
|
||||
|
||||
// both IP's are now banned
|
||||
assert!(pdb.ban_status(&p1).is_banned());
|
||||
assert!(pdb.ban_status(&p2).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_some());
|
||||
assert!(pdb.ban_status(&p2).is_some());
|
||||
|
||||
// unban all peers
|
||||
for p in &peers {
|
||||
@ -1967,16 +1964,16 @@ mod tests {
|
||||
}
|
||||
|
||||
// nothing is banned
|
||||
assert!(!pdb.ban_status(&p1).is_banned());
|
||||
assert!(!pdb.ban_status(&p2).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_none());
|
||||
assert!(pdb.ban_status(&p2).is_none());
|
||||
|
||||
// reban last peer
|
||||
let _ = pdb.report_peer(&peers[0], PeerAction::Fatal, ReportSource::PeerManager, "");
|
||||
pdb.inject_disconnect(&peers[0]);
|
||||
|
||||
//Ip's are banned again
|
||||
assert!(pdb.ban_status(&p1).is_banned());
|
||||
assert!(pdb.ban_status(&p2).is_banned());
|
||||
assert!(pdb.ban_status(&p1).is_some());
|
||||
assert!(pdb.ban_status(&p2).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -20,8 +20,6 @@ where
|
||||
AppReqId: ReqId,
|
||||
TSpec: EthSpec,
|
||||
{
|
||||
/// Peers banned.
|
||||
pub banned_peers: libp2p::allow_block_list::Behaviour<libp2p::allow_block_list::BlockedPeers>,
|
||||
/// Keep track of active and pending connections to enforce hard limits.
|
||||
pub connection_limits: libp2p::connection_limits::Behaviour,
|
||||
/// The routing pub-sub mechanism for eth2.
|
||||
|
@ -27,6 +27,7 @@ use gossipsub_scoring_parameters::{lighthouse_gossip_thresholds, PeerScoreSettin
|
||||
use libp2p::bandwidth::BandwidthSinks;
|
||||
use libp2p::gossipsub::{
|
||||
self, IdentTopic as Topic, MessageAcceptance, MessageAuthenticity, MessageId, PublishError,
|
||||
TopicScoreParams,
|
||||
};
|
||||
use libp2p::identify;
|
||||
use libp2p::multiaddr::{Multiaddr, Protocol as MProtocol};
|
||||
@ -353,11 +354,8 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
libp2p::connection_limits::Behaviour::new(limits)
|
||||
};
|
||||
|
||||
let banned_peers = libp2p::allow_block_list::Behaviour::default();
|
||||
|
||||
let behaviour = {
|
||||
Behaviour {
|
||||
banned_peers,
|
||||
gossipsub,
|
||||
eth2_rpc,
|
||||
discovery,
|
||||
@ -637,6 +635,38 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove topic weight from all topics that don't have the given fork digest.
|
||||
pub fn remove_topic_weight_except(&mut self, except: [u8; 4]) {
|
||||
let new_param = TopicScoreParams {
|
||||
topic_weight: 0.0,
|
||||
..Default::default()
|
||||
};
|
||||
let subscriptions = self.network_globals.gossipsub_subscriptions.read().clone();
|
||||
for topic in subscriptions
|
||||
.iter()
|
||||
.filter(|topic| topic.fork_digest != except)
|
||||
{
|
||||
let libp2p_topic: Topic = topic.clone().into();
|
||||
match self
|
||||
.gossipsub_mut()
|
||||
.set_topic_params(libp2p_topic, new_param.clone())
|
||||
{
|
||||
Ok(_) => debug!(self.log, "Removed topic weight"; "topic" => %topic),
|
||||
Err(e) => {
|
||||
warn!(self.log, "Failed to remove topic weight"; "topic" => %topic, "error" => e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the scoring parameters for a topic if set.
|
||||
pub fn get_topic_params(&self, topic: GossipTopic) -> Option<&TopicScoreParams> {
|
||||
self.swarm
|
||||
.behaviour()
|
||||
.gossipsub
|
||||
.get_topic_params(&topic.into())
|
||||
}
|
||||
|
||||
/// Subscribes to a gossipsub topic.
|
||||
///
|
||||
/// Returns `true` if the subscription was successful and `false` otherwise.
|
||||
@ -1445,15 +1475,10 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
Some(NetworkEvent::PeerDisconnected(peer_id))
|
||||
}
|
||||
PeerManagerEvent::Banned(peer_id, associated_ips) => {
|
||||
self.swarm.behaviour_mut().banned_peers.block_peer(peer_id);
|
||||
self.discovery_mut().ban_peer(&peer_id, associated_ips);
|
||||
None
|
||||
}
|
||||
PeerManagerEvent::UnBanned(peer_id, associated_ips) => {
|
||||
self.swarm
|
||||
.behaviour_mut()
|
||||
.banned_peers
|
||||
.unblock_peer(peer_id);
|
||||
self.discovery_mut().unban_peer(&peer_id, associated_ips);
|
||||
None
|
||||
}
|
||||
@ -1502,7 +1527,6 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
let maybe_event = match swarm_event {
|
||||
SwarmEvent::Behaviour(behaviour_event) => match behaviour_event {
|
||||
// Handle sub-behaviour events.
|
||||
BehaviourEvent::BannedPeers(void) => void::unreachable(void),
|
||||
BehaviourEvent::Gossipsub(ge) => self.inject_gs_event(ge),
|
||||
BehaviourEvent::Eth2Rpc(re) => self.inject_rpc_event(re),
|
||||
// Inform the peer manager about discovered peers.
|
||||
|
@ -978,9 +978,17 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
||||
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore);
|
||||
return None;
|
||||
}
|
||||
Err(BlockError::BlockIsAlreadyKnown) => {
|
||||
debug!(
|
||||
self.log,
|
||||
"Gossip block is already known";
|
||||
"block_root" => %block_root,
|
||||
);
|
||||
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore);
|
||||
return None;
|
||||
}
|
||||
Err(e @ BlockError::FutureSlot { .. })
|
||||
| Err(e @ BlockError::WouldRevertFinalizedSlot { .. })
|
||||
| Err(e @ BlockError::BlockIsAlreadyKnown)
|
||||
| Err(e @ BlockError::NotFinalizedDescendant { .. }) => {
|
||||
debug!(self.log, "Could not verify block for gossip. Ignoring the block";
|
||||
"error" => %e);
|
||||
|
@ -215,15 +215,18 @@ pub struct NetworkService<T: BeaconChainTypes> {
|
||||
}
|
||||
|
||||
impl<T: BeaconChainTypes> NetworkService<T> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub async fn start(
|
||||
async fn build(
|
||||
beacon_chain: Arc<BeaconChain<T>>,
|
||||
config: &NetworkConfig,
|
||||
executor: task_executor::TaskExecutor,
|
||||
gossipsub_registry: Option<&'_ mut Registry>,
|
||||
beacon_processor_send: BeaconProcessorSend<T::EthSpec>,
|
||||
beacon_processor_reprocess_tx: mpsc::Sender<ReprocessQueueMessage>,
|
||||
) -> error::Result<(Arc<NetworkGlobals<T::EthSpec>>, NetworkSenders<T::EthSpec>)> {
|
||||
) -> error::Result<(
|
||||
NetworkService<T>,
|
||||
Arc<NetworkGlobals<T::EthSpec>>,
|
||||
NetworkSenders<T::EthSpec>,
|
||||
)> {
|
||||
let network_log = executor.log().clone();
|
||||
// build the channels for external comms
|
||||
let (network_senders, network_recievers) = NetworkSenders::new();
|
||||
@ -369,6 +372,28 @@ impl<T: BeaconChainTypes> NetworkService<T> {
|
||||
enable_light_client_server: config.enable_light_client_server,
|
||||
};
|
||||
|
||||
Ok((network_service, network_globals, network_senders))
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub async fn start(
|
||||
beacon_chain: Arc<BeaconChain<T>>,
|
||||
config: &NetworkConfig,
|
||||
executor: task_executor::TaskExecutor,
|
||||
gossipsub_registry: Option<&'_ mut Registry>,
|
||||
beacon_processor_send: BeaconProcessorSend<T::EthSpec>,
|
||||
beacon_processor_reprocess_tx: mpsc::Sender<ReprocessQueueMessage>,
|
||||
) -> error::Result<(Arc<NetworkGlobals<T::EthSpec>>, NetworkSenders<T::EthSpec>)> {
|
||||
let (network_service, network_globals, network_senders) = Self::build(
|
||||
beacon_chain,
|
||||
config,
|
||||
executor.clone(),
|
||||
gossipsub_registry,
|
||||
beacon_processor_send,
|
||||
beacon_processor_reprocess_tx,
|
||||
)
|
||||
.await?;
|
||||
|
||||
network_service.spawn_service(executor);
|
||||
|
||||
Ok((network_globals, network_senders))
|
||||
@ -885,9 +910,10 @@ impl<T: BeaconChainTypes> NetworkService<T> {
|
||||
|
||||
fn update_next_fork(&mut self) {
|
||||
let new_enr_fork_id = self.beacon_chain.enr_fork_id();
|
||||
let new_fork_digest = new_enr_fork_id.fork_digest;
|
||||
|
||||
let fork_context = &self.fork_context;
|
||||
if let Some(new_fork_name) = fork_context.from_context_bytes(new_enr_fork_id.fork_digest) {
|
||||
if let Some(new_fork_name) = fork_context.from_context_bytes(new_fork_digest) {
|
||||
info!(
|
||||
self.log,
|
||||
"Transitioned to new fork";
|
||||
@ -910,6 +936,10 @@ impl<T: BeaconChainTypes> NetworkService<T> {
|
||||
Box::pin(next_fork_subscriptions_delay(&self.beacon_chain).into());
|
||||
self.next_unsubscribe = Box::pin(Some(tokio::time::sleep(unsubscribe_delay)).into());
|
||||
info!(self.log, "Network will unsubscribe from old fork gossip topics in a few epochs"; "remaining_epochs" => UNSUBSCRIBE_DELAY_EPOCHS);
|
||||
|
||||
// Remove topic weight from old fork topics to prevent peers that left on the mesh on
|
||||
// old topics from being penalized for not sending us messages.
|
||||
self.libp2p.remove_topic_weight_except(new_fork_digest);
|
||||
} else {
|
||||
crit!(self.log, "Unknown new enr fork id"; "new_fork_id" => ?new_enr_fork_id);
|
||||
}
|
||||
|
@ -4,14 +4,26 @@ mod tests {
|
||||
use crate::persisted_dht::load_dht;
|
||||
use crate::{NetworkConfig, NetworkService};
|
||||
use beacon_chain::test_utils::BeaconChainHarness;
|
||||
use beacon_processor::BeaconProcessorChannels;
|
||||
use lighthouse_network::Enr;
|
||||
use beacon_chain::BeaconChainTypes;
|
||||
use beacon_processor::{BeaconProcessorChannels, BeaconProcessorConfig};
|
||||
use futures::StreamExt;
|
||||
use lighthouse_network::types::{GossipEncoding, GossipKind};
|
||||
use lighthouse_network::{Enr, GossipTopic};
|
||||
use slog::{o, Drain, Level, Logger};
|
||||
use sloggers::{null::NullLoggerBuilder, Build};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use tokio::runtime::Runtime;
|
||||
use types::MinimalEthSpec as E;
|
||||
use types::{Epoch, EthSpec, ForkName, MinimalEthSpec, SubnetId};
|
||||
|
||||
impl<T: BeaconChainTypes> NetworkService<T> {
|
||||
fn get_topic_params(
|
||||
&self,
|
||||
topic: GossipTopic,
|
||||
) -> Option<&lighthouse_network::libp2p::gossipsub::TopicScoreParams> {
|
||||
self.libp2p.get_topic_params(topic)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_logger(actual_log: bool) -> Logger {
|
||||
if actual_log {
|
||||
@ -35,7 +47,7 @@ mod tests {
|
||||
fn test_dht_persistence() {
|
||||
let log = get_logger(false);
|
||||
|
||||
let beacon_chain = BeaconChainHarness::builder(E)
|
||||
let beacon_chain = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.deterministic_keypairs(8)
|
||||
.fresh_ephemeral_store()
|
||||
@ -102,4 +114,126 @@ mod tests {
|
||||
"should have persisted the second ENR to store"
|
||||
);
|
||||
}
|
||||
|
||||
// Test removing topic weight on old topics when a fork happens.
|
||||
#[test]
|
||||
fn test_removing_topic_weight_on_old_topics() {
|
||||
let runtime = Arc::new(Runtime::new().unwrap());
|
||||
|
||||
// Capella spec
|
||||
let mut spec = MinimalEthSpec::default_spec();
|
||||
spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||
spec.capella_fork_epoch = Some(Epoch::new(1));
|
||||
|
||||
// Build beacon chain.
|
||||
let beacon_chain = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.spec(spec.clone())
|
||||
.deterministic_keypairs(8)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
.build()
|
||||
.chain;
|
||||
let (next_fork_name, _) = beacon_chain.duration_to_next_fork().expect("next fork");
|
||||
assert_eq!(next_fork_name, ForkName::Capella);
|
||||
|
||||
// Build network service.
|
||||
let (mut network_service, network_globals, _network_senders) = runtime.block_on(async {
|
||||
let (_, exit) = exit_future::signal();
|
||||
let (shutdown_tx, _) = futures::channel::mpsc::channel(1);
|
||||
let executor = task_executor::TaskExecutor::new(
|
||||
Arc::downgrade(&runtime),
|
||||
exit,
|
||||
get_logger(false),
|
||||
shutdown_tx,
|
||||
);
|
||||
|
||||
let mut config = NetworkConfig::default();
|
||||
config.set_ipv4_listening_address(std::net::Ipv4Addr::UNSPECIFIED, 21214, 21214, 21215);
|
||||
config.discv5_config.table_filter = |_| true; // Do not ignore local IPs
|
||||
config.upnp_enabled = false;
|
||||
|
||||
let beacon_processor_channels =
|
||||
BeaconProcessorChannels::new(&BeaconProcessorConfig::default());
|
||||
NetworkService::build(
|
||||
beacon_chain.clone(),
|
||||
&config,
|
||||
executor.clone(),
|
||||
None,
|
||||
beacon_processor_channels.beacon_processor_tx,
|
||||
beacon_processor_channels.work_reprocessing_tx,
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
// Subscribe to the topics.
|
||||
runtime.block_on(async {
|
||||
while network_globals.gossipsub_subscriptions.read().len() < 2 {
|
||||
if let Some(msg) = network_service.attestation_service.next().await {
|
||||
network_service.on_attestation_service_msg(msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure the service is subscribed to the topics.
|
||||
let (old_topic1, old_topic2) = {
|
||||
let mut subnets = SubnetId::compute_subnets_for_epoch::<MinimalEthSpec>(
|
||||
network_globals.local_enr().node_id().raw().into(),
|
||||
beacon_chain.epoch().unwrap(),
|
||||
&spec,
|
||||
)
|
||||
.unwrap()
|
||||
.0
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(2, subnets.len());
|
||||
|
||||
let old_fork_digest = beacon_chain.enr_fork_id().fork_digest;
|
||||
let old_topic1 = GossipTopic::new(
|
||||
GossipKind::Attestation(subnets.pop().unwrap()),
|
||||
GossipEncoding::SSZSnappy,
|
||||
old_fork_digest,
|
||||
);
|
||||
let old_topic2 = GossipTopic::new(
|
||||
GossipKind::Attestation(subnets.pop().unwrap()),
|
||||
GossipEncoding::SSZSnappy,
|
||||
old_fork_digest,
|
||||
);
|
||||
|
||||
(old_topic1, old_topic2)
|
||||
};
|
||||
let subscriptions = network_globals.gossipsub_subscriptions.read().clone();
|
||||
assert_eq!(2, subscriptions.len());
|
||||
assert!(subscriptions.contains(&old_topic1));
|
||||
assert!(subscriptions.contains(&old_topic2));
|
||||
let old_topic_params1 = network_service
|
||||
.get_topic_params(old_topic1.clone())
|
||||
.expect("topic score params");
|
||||
assert!(old_topic_params1.topic_weight > 0.0);
|
||||
let old_topic_params2 = network_service
|
||||
.get_topic_params(old_topic2.clone())
|
||||
.expect("topic score params");
|
||||
assert!(old_topic_params2.topic_weight > 0.0);
|
||||
|
||||
// Advance slot to the next fork
|
||||
for _ in 0..MinimalEthSpec::slots_per_epoch() {
|
||||
beacon_chain.slot_clock.advance_slot();
|
||||
}
|
||||
|
||||
// Run `NetworkService::update_next_fork()`.
|
||||
runtime.block_on(async {
|
||||
network_service.update_next_fork();
|
||||
});
|
||||
|
||||
// Check that topic_weight on the old topics has been zeroed.
|
||||
let old_topic_params1 = network_service
|
||||
.get_topic_params(old_topic1)
|
||||
.expect("topic score params");
|
||||
assert_eq!(0.0, old_topic_params1.topic_weight);
|
||||
|
||||
let old_topic_params2 = network_service
|
||||
.get_topic_params(old_topic2)
|
||||
.expect("topic score params");
|
||||
assert_eq!(0.0, old_topic_params2.topic_weight);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use std::fmt::Debug;
|
||||
use std::fs;
|
||||
use std::net::Ipv6Addr;
|
||||
use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs};
|
||||
use std::num::NonZeroU16;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
@ -1216,23 +1217,23 @@ pub fn set_network_config(
|
||||
if let Some(enr_udp_port_str) = cli_args.value_of("enr-udp-port") {
|
||||
config.enr_udp4_port = Some(
|
||||
enr_udp_port_str
|
||||
.parse::<u16>()
|
||||
.map_err(|_| format!("Invalid discovery port: {}", enr_udp_port_str))?,
|
||||
.parse::<NonZeroU16>()
|
||||
.map_err(|_| format!("Invalid ENR discovery port: {}", enr_udp_port_str))?,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(enr_quic_port_str) = cli_args.value_of("enr-quic-port") {
|
||||
config.enr_quic4_port = Some(
|
||||
enr_quic_port_str
|
||||
.parse::<u16>()
|
||||
.map_err(|_| format!("Invalid quic port: {}", enr_quic_port_str))?,
|
||||
.parse::<NonZeroU16>()
|
||||
.map_err(|_| format!("Invalid ENR quic port: {}", enr_quic_port_str))?,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(enr_tcp_port_str) = cli_args.value_of("enr-tcp-port") {
|
||||
config.enr_tcp4_port = Some(
|
||||
enr_tcp_port_str
|
||||
.parse::<u16>()
|
||||
.parse::<NonZeroU16>()
|
||||
.map_err(|_| format!("Invalid ENR TCP port: {}", enr_tcp_port_str))?,
|
||||
);
|
||||
}
|
||||
@ -1240,23 +1241,23 @@ pub fn set_network_config(
|
||||
if let Some(enr_udp_port_str) = cli_args.value_of("enr-udp6-port") {
|
||||
config.enr_udp6_port = Some(
|
||||
enr_udp_port_str
|
||||
.parse::<u16>()
|
||||
.map_err(|_| format!("Invalid discovery port: {}", enr_udp_port_str))?,
|
||||
.parse::<NonZeroU16>()
|
||||
.map_err(|_| format!("Invalid ENR discovery port: {}", enr_udp_port_str))?,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(enr_quic_port_str) = cli_args.value_of("enr-quic6-port") {
|
||||
config.enr_quic6_port = Some(
|
||||
enr_quic_port_str
|
||||
.parse::<u16>()
|
||||
.map_err(|_| format!("Invalid quic port: {}", enr_quic_port_str))?,
|
||||
.parse::<NonZeroU16>()
|
||||
.map_err(|_| format!("Invalid ENR quic port: {}", enr_quic_port_str))?,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(enr_tcp_port_str) = cli_args.value_of("enr-tcp6-port") {
|
||||
config.enr_tcp6_port = Some(
|
||||
enr_tcp_port_str
|
||||
.parse::<u16>()
|
||||
.parse::<NonZeroU16>()
|
||||
.map_err(|_| format!("Invalid ENR TCP port: {}", enr_tcp_port_str))?,
|
||||
);
|
||||
}
|
||||
@ -1264,25 +1265,38 @@ pub fn set_network_config(
|
||||
if cli_args.is_present("enr-match") {
|
||||
// Match the IP and UDP port in the ENR.
|
||||
|
||||
// Set the ENR address to localhost if the address is unspecified.
|
||||
if let Some(ipv4_addr) = config.listen_addrs().v4().cloned() {
|
||||
// ensure the port is valid to be advertised
|
||||
let disc_port = ipv4_addr
|
||||
.disc_port
|
||||
.try_into()
|
||||
.map_err(|_| "enr-match can only be used with non-zero listening ports")?;
|
||||
|
||||
// Set the ENR address to localhost if the address is unspecified.
|
||||
let ipv4_enr_addr = if ipv4_addr.addr == Ipv4Addr::UNSPECIFIED {
|
||||
Ipv4Addr::LOCALHOST
|
||||
} else {
|
||||
ipv4_addr.addr
|
||||
};
|
||||
config.enr_address.0 = Some(ipv4_enr_addr);
|
||||
config.enr_udp4_port = Some(ipv4_addr.disc_port);
|
||||
config.enr_udp4_port = Some(disc_port);
|
||||
}
|
||||
|
||||
if let Some(ipv6_addr) = config.listen_addrs().v6().cloned() {
|
||||
// ensure the port is valid to be advertised
|
||||
let disc_port = ipv6_addr
|
||||
.disc_port
|
||||
.try_into()
|
||||
.map_err(|_| "enr-match can only be used with non-zero listening ports")?;
|
||||
|
||||
// Set the ENR address to localhost if the address is unspecified.
|
||||
let ipv6_enr_addr = if ipv6_addr.addr == Ipv6Addr::UNSPECIFIED {
|
||||
Ipv6Addr::LOCALHOST
|
||||
} else {
|
||||
ipv6_addr.addr
|
||||
};
|
||||
config.enr_address.1 = Some(ipv6_enr_addr);
|
||||
config.enr_udp6_port = Some(ipv6_addr.disc_port);
|
||||
config.enr_udp6_port = Some(disc_port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,19 +60,25 @@ impl<T: EthSpec> BootNodeConfig<T> {
|
||||
|
||||
// Set the Enr Discovery ports to the listening ports if not present.
|
||||
if let Some(listening_addr_v4) = network_config.listen_addrs().v4() {
|
||||
network_config.enr_udp4_port = Some(
|
||||
network_config
|
||||
.enr_udp4_port
|
||||
.unwrap_or(listening_addr_v4.disc_port),
|
||||
)
|
||||
if network_config.enr_udp4_port.is_none() {
|
||||
network_config.enr_udp4_port =
|
||||
Some(network_config.enr_udp4_port.unwrap_or(
|
||||
listening_addr_v4.disc_port.try_into().map_err(|_| {
|
||||
"boot node enr-udp-port not set and listening port is zero"
|
||||
})?,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(listening_addr_v6) = network_config.listen_addrs().v6() {
|
||||
network_config.enr_udp6_port = Some(
|
||||
network_config
|
||||
.enr_udp6_port
|
||||
.unwrap_or(listening_addr_v6.disc_port),
|
||||
)
|
||||
if network_config.enr_udp6_port.is_none() {
|
||||
network_config.enr_udp6_port =
|
||||
Some(network_config.enr_udp6_port.unwrap_or(
|
||||
listening_addr_v6.disc_port.try_into().map_err(|_| {
|
||||
"boot node enr-udp-port not set and listening port is zero"
|
||||
})?,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
// By default this is enabled. If it is not set, revert to false.
|
||||
|
@ -1,5 +1,4 @@
|
||||
status = [
|
||||
"cargo-fmt",
|
||||
"release-tests-ubuntu",
|
||||
"release-tests-windows",
|
||||
"debug-tests-ubuntu",
|
||||
@ -9,20 +8,16 @@ status = [
|
||||
"eth1-simulator-ubuntu",
|
||||
"merge-transition-ubuntu",
|
||||
"no-eth1-simulator-ubuntu",
|
||||
"check-benchmarks",
|
||||
"clippy",
|
||||
"arbitrary-check",
|
||||
"cargo-audit",
|
||||
"check-code",
|
||||
"cargo-udeps",
|
||||
"beacon-chain-tests",
|
||||
"op-pool-tests",
|
||||
"doppelganger-protection-test",
|
||||
"execution-engine-integration-ubuntu",
|
||||
"cargo-vendor",
|
||||
"check-msrv",
|
||||
"slasher-tests",
|
||||
"syncing-simulator-ubuntu",
|
||||
"compile-with-beta-compiler"
|
||||
"compile-with-beta-compiler",
|
||||
]
|
||||
use_squash_merge = true
|
||||
timeout_sec = 10800
|
||||
|
@ -9,8 +9,6 @@
|
||||
- enr:-Ku4QPn5eVhcoF1opaFEvg1b6JNFD2rqVkHQ8HApOKK61OIcIXD127bKWgAtbwI7pnxx6cDyk_nI88TrZKQaGMZj0q0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDayLMaJc2VjcDI1NmsxoQK2sBOLGcUb4AwuYzFuAVCaNHA-dy24UuEKkeFNgCVCsIN1ZHCCIyg
|
||||
- enr:-Ku4QEWzdnVtXc2Q0ZVigfCGggOVB2Vc1ZCPEc6j21NIFLODSJbvNaef1g4PxhPwl_3kax86YPheFUSLXPRs98vvYsoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDZBrP2Jc2VjcDI1NmsxoQM6jr8Rb1ktLEsVcKAPa08wCsKUmvoQ8khiOl_SLozf9IN1ZHCCIyg
|
||||
# Teku team (Consensys)
|
||||
- enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2Gxb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNlY3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QL-eqFoHy0cI31THvtZjpYUu_Jdw_MO7skQRJxY1g5HTN1A0epPCU6vi0gLGUgrzpU-ygeMSS8ewVxDpKfYmxMMGhGV0aDKQtTA_KgAAAAD__________4JpZIJ2NIJpcIQ2_DUbiXNlY3AyNTZrMaED8GJ2vzUqgL6-KD1xalo1CsmY4X1HaDnyl6Y_WayCo9GDdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QMOEswP62yzDjSwWS4YEjtTZ5PO6r65CPqYBkgTTkrpaedQ8uEUo1uMALtJIvb2w_WWEVmg5yt1UAuK1ftxUU7QDhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQEnfA2iXNlY3AyNTZrMaEDfol8oLr6XJ7FsdAYE7lpJhKMls4G_v6qQOGKJUWGb_uDdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QF4B5WrlFcRhUU6dZETwY5ZzAXnA0vGC__L1Kdw602nDZwXSTs5RFXFIFUnbQJmhNGVU6OIX7KVrCSTODsz1tK4DhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQExNYEiXNlY3AyNTZrMaECQmM9vp7KhaXhI-nqL_R0ovULLCFSFTa9CPPSdb1zPX6DdGNwgiMog3VkcIIjKA
|
||||
# Prysm team (Prysmatic Labs)
|
||||
|
@ -6,3 +6,6 @@ edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
fnv = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
mock_instant = "0.3"
|
||||
|
@ -1,7 +1,13 @@
|
||||
//! This implements a time-based LRU cache for fast checking of duplicates
|
||||
use fnv::FnvHashSet;
|
||||
#[cfg(test)]
|
||||
use mock_instant::Instant;
|
||||
use std::collections::VecDeque;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[cfg(not(test))]
|
||||
use std::time::Instant;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
struct Element<Key> {
|
||||
/// The key being inserted.
|
||||
@ -222,16 +228,16 @@ mod test {
|
||||
cache.insert("a");
|
||||
cache.insert("b");
|
||||
|
||||
std::thread::sleep(Duration::from_millis(20));
|
||||
mock_instant::MockClock::advance(Duration::from_millis(20));
|
||||
cache.insert("a");
|
||||
// a is newer now
|
||||
|
||||
std::thread::sleep(Duration::from_millis(85));
|
||||
mock_instant::MockClock::advance(Duration::from_millis(85));
|
||||
assert!(cache.contains(&"a"),);
|
||||
// b was inserted first but was not as recent it should have been removed
|
||||
assert!(!cache.contains(&"b"));
|
||||
|
||||
std::thread::sleep(Duration::from_millis(16));
|
||||
mock_instant::MockClock::advance(Duration::from_millis(16));
|
||||
assert!(!cache.contains(&"a"));
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ use crate::{
|
||||
BlockProcessingError, BlockSignatureStrategy, ConsensusContext, SlotProcessingError,
|
||||
VerifyBlockRoot,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use std::iter::Peekable;
|
||||
use std::marker::PhantomData;
|
||||
use types::{BeaconState, BlindedPayload, ChainSpec, EthSpec, Hash256, SignedBeaconBlock, Slot};
|
||||
|
||||
@ -25,7 +27,7 @@ pub struct BlockReplayer<
|
||||
'a,
|
||||
Spec: EthSpec,
|
||||
Error = BlockReplayError,
|
||||
StateRootIter = StateRootIterDefault<Error>,
|
||||
StateRootIter: Iterator<Item = Result<(Hash256, Slot), Error>> = StateRootIterDefault<Error>,
|
||||
> {
|
||||
state: BeaconState<Spec>,
|
||||
spec: &'a ChainSpec,
|
||||
@ -36,7 +38,7 @@ pub struct BlockReplayer<
|
||||
post_block_hook: Option<PostBlockHook<'a, Spec, Error>>,
|
||||
pre_slot_hook: Option<PreSlotHook<'a, Spec, Error>>,
|
||||
post_slot_hook: Option<PostSlotHook<'a, Spec, Error>>,
|
||||
state_root_iter: Option<StateRootIter>,
|
||||
pub(crate) state_root_iter: Option<Peekable<StateRootIter>>,
|
||||
state_root_miss: bool,
|
||||
_phantom: PhantomData<Error>,
|
||||
}
|
||||
@ -138,7 +140,7 @@ where
|
||||
/// `self.state.slot` to the `target_slot` supplied to `apply_blocks` (inclusive of both
|
||||
/// endpoints).
|
||||
pub fn state_root_iter(mut self, iter: StateRootIter) -> Self {
|
||||
self.state_root_iter = Some(iter);
|
||||
self.state_root_iter = Some(iter.peekable());
|
||||
self
|
||||
}
|
||||
|
||||
@ -192,7 +194,7 @@ where
|
||||
// If a state root iterator is configured, use it to find the root.
|
||||
if let Some(ref mut state_root_iter) = self.state_root_iter {
|
||||
let opt_root = state_root_iter
|
||||
.take_while(|res| res.as_ref().map_or(true, |(_, s)| *s <= slot))
|
||||
.peeking_take_while(|res| res.as_ref().map_or(true, |(_, s)| *s <= slot))
|
||||
.find(|res| res.as_ref().map_or(true, |(_, s)| *s == slot))
|
||||
.transpose()?;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
#![cfg(all(test, not(feature = "fake_crypto")))]
|
||||
#![cfg(all(test, not(feature = "fake_crypto"), not(debug_assertions)))]
|
||||
|
||||
use crate::per_block_processing::errors::{
|
||||
AttestationInvalid, AttesterSlashingInvalid, BlockOperationError, BlockProcessingError,
|
||||
DepositInvalid, HeaderInvalid, IndexedAttestationInvalid, IntoWithIndex,
|
||||
ProposerSlashingInvalid,
|
||||
};
|
||||
use crate::{per_block_processing, StateProcessingStrategy};
|
||||
use crate::{per_block_processing, BlockReplayError, BlockReplayer, StateProcessingStrategy};
|
||||
use crate::{
|
||||
per_block_processing::{process_operations, verify_exit::verify_exit},
|
||||
BlockSignatureStrategy, ConsensusContext, VerifyBlockRoot, VerifySignatures,
|
||||
@ -1035,3 +1035,51 @@ async fn fork_spanning_exit() {
|
||||
)
|
||||
.expect_err("phase0 exit does not verify against bellatrix state");
|
||||
}
|
||||
|
||||
/// Check that the block replayer does not consume state roots unnecessarily.
|
||||
#[tokio::test]
|
||||
async fn block_replayer_peeking_state_roots() {
|
||||
let harness = get_harness::<MainnetEthSpec>(EPOCH_OFFSET, VALIDATOR_COUNT).await;
|
||||
|
||||
let target_state = harness.get_current_state();
|
||||
let target_block_root = harness.head_block_root();
|
||||
let target_block = harness
|
||||
.chain
|
||||
.get_blinded_block(&target_block_root)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let parent_block_root = target_block.parent_root();
|
||||
let parent_block = harness
|
||||
.chain
|
||||
.get_blinded_block(&parent_block_root)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let parent_state = harness
|
||||
.chain
|
||||
.get_state(&parent_block.state_root(), Some(parent_block.slot()))
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
// Omit the state root for `target_state` but provide a dummy state root at the *next* slot.
|
||||
// If the block replayer is peeking at the state roots rather than consuming them, then the
|
||||
// dummy state should still be there after block replay completes.
|
||||
let dummy_state_root = Hash256::repeat_byte(0xff);
|
||||
let dummy_slot = target_state.slot() + 1;
|
||||
let state_root_iter = vec![Ok::<_, BlockReplayError>((dummy_state_root, dummy_slot))];
|
||||
let block_replayer = BlockReplayer::new(parent_state, &harness.chain.spec)
|
||||
.state_root_iter(state_root_iter.into_iter())
|
||||
.no_signature_verification()
|
||||
.apply_blocks(vec![target_block], None)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
block_replayer
|
||||
.state_root_iter
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
(dummy_state_root, dummy_slot)
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::beacon_block_body::KzgCommitments;
|
||||
use crate::{
|
||||
BlobRootsList, ChainSpec, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb,
|
||||
ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ForkName, ForkVersionDeserialize,
|
||||
KzgProofs, SignedRoot, Uint256,
|
||||
ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, ForkName,
|
||||
ForkVersionDeserialize, KzgProofs, SignedRoot, Uint256,
|
||||
};
|
||||
use bls::PublicKeyBytes;
|
||||
use bls::Signature;
|
||||
@ -26,7 +26,8 @@ pub struct BlindedBlobsBundle<E: EthSpec> {
|
||||
derive(PartialEq, Debug, Serialize, Deserialize, TreeHash, Clone),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields)
|
||||
),
|
||||
map_ref_into(ExecutionPayloadHeaderRef)
|
||||
map_ref_into(ExecutionPayloadHeaderRef),
|
||||
map_ref_mut_into(ExecutionPayloadHeaderRefMut)
|
||||
)]
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, TreeHash, Clone)]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields, untagged)]
|
||||
@ -59,6 +60,14 @@ impl<'a, E: EthSpec> BuilderBidRef<'a, E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> BuilderBidRefMut<'a, E> {
|
||||
pub fn header_mut(self) -> ExecutionPayloadHeaderRefMut<'a, E> {
|
||||
map_builder_bid_ref_mut_into_execution_payload_header_ref_mut!(&'a _, self, |bid, cons| {
|
||||
cons(&mut bid.header)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedRoot for BuilderBid<E> {}
|
||||
|
||||
/// Validator registration, for use in interacting with servers implementing the builder API.
|
||||
|
@ -21,3 +21,17 @@ pub struct ValidatorRegistrationData {
|
||||
}
|
||||
|
||||
impl SignedRoot for ValidatorRegistrationData {}
|
||||
|
||||
impl SignedValidatorRegistrationData {
|
||||
pub fn verify_signature(&self, spec: &ChainSpec) -> bool {
|
||||
self.message
|
||||
.pubkey
|
||||
.decompress()
|
||||
.map(|pubkey| {
|
||||
let domain = spec.get_builder_domain();
|
||||
let message = self.message.signing_root(domain);
|
||||
self.signature.verify(&pubkey, message)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,16 @@ use lighthouse_network::{
|
||||
libp2p::identity::secp256k1,
|
||||
NetworkConfig, NETWORK_KEY_FILENAME,
|
||||
};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{fs, net::Ipv4Addr};
|
||||
use std::{fs::File, num::NonZeroU16};
|
||||
use types::{ChainSpec, EnrForkId, Epoch, EthSpec, Hash256};
|
||||
|
||||
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
|
||||
let ip: Ipv4Addr = clap_utils::parse_required(matches, "ip")?;
|
||||
let udp_port: u16 = clap_utils::parse_required(matches, "udp-port")?;
|
||||
let tcp_port: u16 = clap_utils::parse_required(matches, "tcp-port")?;
|
||||
let udp_port: NonZeroU16 = clap_utils::parse_required(matches, "udp-port")?;
|
||||
let tcp_port: NonZeroU16 = clap_utils::parse_required(matches, "tcp-port")?;
|
||||
let output_dir: PathBuf = clap_utils::parse_required(matches, "output-dir")?;
|
||||
let genesis_fork_version: [u8; 4] =
|
||||
clap_utils::parse_ssz_required(matches, "genesis-fork-version")?;
|
||||
|
@ -22,9 +22,14 @@ use types::{
|
||||
Address, Checkpoint, Epoch, ExecutionBlockHash, ForkName, Hash256, MainnetEthSpec,
|
||||
ProgressiveBalancesMode,
|
||||
};
|
||||
use unused_port::{unused_tcp4_port, unused_tcp6_port, unused_udp4_port, unused_udp6_port};
|
||||
|
||||
const DEFAULT_ETH1_ENDPOINT: &str = "http://localhost:8545/";
|
||||
const DUMMY_ENR_TCP_PORT: u16 = 7777;
|
||||
const DUMMY_ENR_UDP_PORT: u16 = 8888;
|
||||
const DUMMY_ENR_QUIC_PORT: u16 = 9999;
|
||||
|
||||
const _: () =
|
||||
assert!(DUMMY_ENR_QUIC_PORT != 0 && DUMMY_ENR_TCP_PORT != 0 && DUMMY_ENR_UDP_PORT != 0);
|
||||
|
||||
/// Returns the `lighthouse beacon_node` command.
|
||||
fn base_cmd() -> Command {
|
||||
@ -1036,7 +1041,7 @@ fn network_listen_address_flag_wrong_double_v6_value_config() {
|
||||
}
|
||||
#[test]
|
||||
fn network_port_flag_over_ipv4() {
|
||||
let port = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let port = 0;
|
||||
CommandLineTest::new()
|
||||
.flag("port", Some(port.to_string().as_str()))
|
||||
.run()
|
||||
@ -1053,7 +1058,7 @@ fn network_port_flag_over_ipv4() {
|
||||
}
|
||||
#[test]
|
||||
fn network_port_flag_over_ipv6() {
|
||||
let port = unused_tcp6_port().expect("Unable to find unused port.");
|
||||
let port = 0;
|
||||
CommandLineTest::new()
|
||||
.flag("listen-address", Some("::1"))
|
||||
.flag("port", Some(port.to_string().as_str()))
|
||||
@ -1071,8 +1076,8 @@ fn network_port_flag_over_ipv6() {
|
||||
}
|
||||
#[test]
|
||||
fn network_port_and_discovery_port_flags_over_ipv4() {
|
||||
let tcp4_port = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let disc4_port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let tcp4_port = 0;
|
||||
let disc4_port = 0;
|
||||
CommandLineTest::new()
|
||||
.flag("port", Some(tcp4_port.to_string().as_str()))
|
||||
.flag("discovery-port", Some(disc4_port.to_string().as_str()))
|
||||
@ -1090,8 +1095,8 @@ fn network_port_and_discovery_port_flags_over_ipv4() {
|
||||
}
|
||||
#[test]
|
||||
fn network_port_and_discovery_port_flags_over_ipv6() {
|
||||
let tcp6_port = unused_tcp6_port().expect("Unable to find unused port.");
|
||||
let disc6_port = unused_udp6_port().expect("Unable to find unused port.");
|
||||
let tcp6_port = 0;
|
||||
let disc6_port = 0;
|
||||
CommandLineTest::new()
|
||||
.flag("listen-address", Some("::1"))
|
||||
.flag("port", Some(tcp6_port.to_string().as_str()))
|
||||
@ -1110,10 +1115,10 @@ fn network_port_and_discovery_port_flags_over_ipv6() {
|
||||
}
|
||||
#[test]
|
||||
fn network_port_and_discovery_port_flags_over_ipv4_and_ipv6() {
|
||||
let tcp4_port = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let disc4_port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let tcp6_port = unused_tcp6_port().expect("Unable to find unused port.");
|
||||
let disc6_port = unused_udp6_port().expect("Unable to find unused port.");
|
||||
let tcp4_port = 0;
|
||||
let disc4_port = 0;
|
||||
let tcp6_port = 0;
|
||||
let disc6_port = 0;
|
||||
CommandLineTest::new()
|
||||
.flag("listen-address", Some("::1"))
|
||||
.flag("listen-address", Some("127.0.0.1"))
|
||||
@ -1145,12 +1150,12 @@ fn network_port_and_discovery_port_flags_over_ipv4_and_ipv6() {
|
||||
|
||||
#[test]
|
||||
fn network_port_discovery_quic_port_flags_over_ipv4_and_ipv6() {
|
||||
let tcp4_port = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let disc4_port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let quic4_port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let tcp6_port = unused_tcp6_port().expect("Unable to find unused port.");
|
||||
let disc6_port = unused_udp6_port().expect("Unable to find unused port.");
|
||||
let quic6_port = unused_udp6_port().expect("Unable to find unused port.");
|
||||
let tcp4_port = 0;
|
||||
let disc4_port = 0;
|
||||
let quic4_port = 0;
|
||||
let tcp6_port = 0;
|
||||
let disc6_port = 0;
|
||||
let quic6_port = 0;
|
||||
CommandLineTest::new()
|
||||
.flag("listen-address", Some("::1"))
|
||||
.flag("listen-address", Some("127.0.0.1"))
|
||||
@ -1226,7 +1231,7 @@ fn default_backfill_rate_limiting_flag() {
|
||||
}
|
||||
#[test]
|
||||
fn default_boot_nodes() {
|
||||
let number_of_boot_nodes = 17;
|
||||
let number_of_boot_nodes = 15;
|
||||
|
||||
CommandLineTest::new()
|
||||
.run_with_zero_port()
|
||||
@ -1296,57 +1301,91 @@ fn network_load_flag() {
|
||||
// Tests for ENR flags.
|
||||
#[test]
|
||||
fn enr_udp_port_flag() {
|
||||
let port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_UDP_PORT;
|
||||
assert!(port != 0);
|
||||
CommandLineTest::new()
|
||||
.flag("enr-udp-port", Some(port.to_string().as_str()))
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| assert_eq!(config.network.enr_udp4_port, Some(port)));
|
||||
.with_config(|config| {
|
||||
assert_eq!(
|
||||
config.network.enr_udp4_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
)
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_quic_port_flag() {
|
||||
let port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_QUIC_PORT;
|
||||
CommandLineTest::new()
|
||||
.flag("enr-quic-port", Some(port.to_string().as_str()))
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| assert_eq!(config.network.enr_quic4_port, Some(port)));
|
||||
.with_config(|config| {
|
||||
assert_eq!(
|
||||
config.network.enr_quic4_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
)
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_tcp_port_flag() {
|
||||
let port = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_TCP_PORT;
|
||||
CommandLineTest::new()
|
||||
.flag("enr-tcp-port", Some(port.to_string().as_str()))
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| assert_eq!(config.network.enr_tcp4_port, Some(port)));
|
||||
.with_config(|config| {
|
||||
assert_eq!(
|
||||
config.network.enr_tcp4_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
)
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_udp6_port_flag() {
|
||||
let port = unused_udp6_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_UDP_PORT;
|
||||
CommandLineTest::new()
|
||||
.flag("enr-udp6-port", Some(port.to_string().as_str()))
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| assert_eq!(config.network.enr_udp6_port, Some(port)));
|
||||
.with_config(|config| {
|
||||
assert_eq!(
|
||||
config.network.enr_udp6_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
)
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_quic6_port_flag() {
|
||||
let port = unused_udp6_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_QUIC_PORT;
|
||||
CommandLineTest::new()
|
||||
.flag("enr-quic6-port", Some(port.to_string().as_str()))
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| assert_eq!(config.network.enr_quic6_port, Some(port)));
|
||||
.with_config(|config| {
|
||||
assert_eq!(
|
||||
config.network.enr_quic6_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
)
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_tcp6_port_flag() {
|
||||
let port = unused_tcp6_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_TCP_PORT;
|
||||
CommandLineTest::new()
|
||||
.flag("enr-tcp6-port", Some(port.to_string().as_str()))
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| assert_eq!(config.network.enr_tcp6_port, Some(port)));
|
||||
.with_config(|config| {
|
||||
assert_eq!(
|
||||
config.network.enr_tcp6_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
)
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_match_flag_over_ipv4() {
|
||||
let addr = "127.0.0.2".parse::<Ipv4Addr>().unwrap();
|
||||
let udp4_port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let tcp4_port = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
|
||||
// the reason we use the ENR dummy values is because, due to the nature of the `--enr-match` flag, these will eventually become ENR ports (as well as listening ports).
|
||||
let udp4_port = DUMMY_ENR_UDP_PORT;
|
||||
let tcp4_port = DUMMY_ENR_TCP_PORT;
|
||||
|
||||
CommandLineTest::new()
|
||||
.flag("enr-match", None)
|
||||
.flag("listen-address", Some("127.0.0.2"))
|
||||
@ -1363,15 +1402,21 @@ fn enr_match_flag_over_ipv4() {
|
||||
Some((addr, udp4_port, tcp4_port))
|
||||
);
|
||||
assert_eq!(config.network.enr_address, (Some(addr), None));
|
||||
assert_eq!(config.network.enr_udp4_port, Some(udp4_port));
|
||||
assert_eq!(
|
||||
config.network.enr_udp4_port.map(|port| port.get()),
|
||||
Some(udp4_port)
|
||||
);
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_match_flag_over_ipv6() {
|
||||
const ADDR: &str = "::1";
|
||||
let addr = ADDR.parse::<Ipv6Addr>().unwrap();
|
||||
let udp6_port = unused_udp6_port().expect("Unable to find unused port.");
|
||||
let tcp6_port = unused_tcp6_port().expect("Unable to find unused port.");
|
||||
|
||||
// the reason we use the ENR dummy values is because, due to the nature of the `--enr-match` flag, these will eventually become ENR ports (as well as listening ports).
|
||||
let udp6_port = DUMMY_ENR_UDP_PORT;
|
||||
let tcp6_port = DUMMY_ENR_TCP_PORT;
|
||||
|
||||
CommandLineTest::new()
|
||||
.flag("enr-match", None)
|
||||
.flag("listen-address", Some(ADDR))
|
||||
@ -1388,19 +1433,27 @@ fn enr_match_flag_over_ipv6() {
|
||||
Some((addr, udp6_port, tcp6_port))
|
||||
);
|
||||
assert_eq!(config.network.enr_address, (None, Some(addr)));
|
||||
assert_eq!(config.network.enr_udp6_port, Some(udp6_port));
|
||||
assert_eq!(
|
||||
config.network.enr_udp6_port.map(|port| port.get()),
|
||||
Some(udp6_port)
|
||||
);
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_match_flag_over_ipv4_and_ipv6() {
|
||||
const IPV6_ADDR: &str = "::1";
|
||||
|
||||
// the reason we use the ENR dummy values is because, due to the nature of the `--enr-match` flag, these will eventually become ENR ports (as well as listening ports).
|
||||
let udp6_port = DUMMY_ENR_UDP_PORT;
|
||||
let tcp6_port = DUMMY_ENR_TCP_PORT;
|
||||
let ipv6_addr = IPV6_ADDR.parse::<Ipv6Addr>().unwrap();
|
||||
let udp6_port = unused_udp6_port().expect("Unable to find unused port.");
|
||||
let tcp6_port = unused_tcp6_port().expect("Unable to find unused port.");
|
||||
|
||||
const IPV4_ADDR: &str = "127.0.0.1";
|
||||
// the reason we use the ENR dummy values is because, due to the nature of the `--enr-match` flag, these will eventually become ENR ports (as well as listening ports).
|
||||
let udp4_port = DUMMY_ENR_UDP_PORT;
|
||||
let tcp4_port = DUMMY_ENR_TCP_PORT;
|
||||
let ipv4_addr = IPV4_ADDR.parse::<Ipv4Addr>().unwrap();
|
||||
let udp4_port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let tcp4_port = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
|
||||
CommandLineTest::new()
|
||||
.flag("enr-match", None)
|
||||
.flag("listen-address", Some(IPV4_ADDR))
|
||||
@ -1431,41 +1484,53 @@ fn enr_match_flag_over_ipv4_and_ipv6() {
|
||||
config.network.enr_address,
|
||||
(Some(ipv4_addr), Some(ipv6_addr))
|
||||
);
|
||||
assert_eq!(config.network.enr_udp6_port, Some(udp6_port));
|
||||
assert_eq!(config.network.enr_udp4_port, Some(udp4_port));
|
||||
assert_eq!(
|
||||
config.network.enr_udp6_port.map(|port| port.get()),
|
||||
Some(udp6_port)
|
||||
);
|
||||
assert_eq!(
|
||||
config.network.enr_udp4_port.map(|port| port.get()),
|
||||
Some(udp4_port)
|
||||
);
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_address_flag_with_ipv4() {
|
||||
let addr = "192.167.1.1".parse::<Ipv4Addr>().unwrap();
|
||||
let port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_UDP_PORT;
|
||||
CommandLineTest::new()
|
||||
.flag("enr-address", Some("192.167.1.1"))
|
||||
.flag("enr-udp-port", Some(port.to_string().as_str()))
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| {
|
||||
assert_eq!(config.network.enr_address, (Some(addr), None));
|
||||
assert_eq!(config.network.enr_udp4_port, Some(port));
|
||||
assert_eq!(
|
||||
config.network.enr_udp4_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
);
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_address_flag_with_ipv6() {
|
||||
let addr = "192.167.1.1".parse::<Ipv4Addr>().unwrap();
|
||||
let port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_UDP_PORT;
|
||||
CommandLineTest::new()
|
||||
.flag("enr-address", Some("192.167.1.1"))
|
||||
.flag("enr-udp-port", Some(port.to_string().as_str()))
|
||||
.run_with_zero_port()
|
||||
.with_config(|config| {
|
||||
assert_eq!(config.network.enr_address, (Some(addr), None));
|
||||
assert_eq!(config.network.enr_udp4_port, Some(port));
|
||||
assert_eq!(
|
||||
config.network.enr_udp4_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
);
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn enr_address_dns_flag() {
|
||||
let addr = Ipv4Addr::LOCALHOST;
|
||||
let ipv6addr = Ipv6Addr::LOCALHOST;
|
||||
let port = unused_udp4_port().expect("Unable to find unused port.");
|
||||
let port = DUMMY_ENR_UDP_PORT;
|
||||
CommandLineTest::new()
|
||||
.flag("enr-address", Some("localhost"))
|
||||
.flag("enr-udp-port", Some(port.to_string().as_str()))
|
||||
@ -1475,7 +1540,10 @@ fn enr_address_dns_flag() {
|
||||
config.network.enr_address.0 == Some(addr)
|
||||
|| config.network.enr_address.1 == Some(ipv6addr)
|
||||
);
|
||||
assert_eq!(config.network.enr_udp4_port, Some(port));
|
||||
assert_eq!(
|
||||
config.network.enr_udp4_port.map(|port| port.get()),
|
||||
Some(port)
|
||||
);
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
@ -1514,8 +1582,8 @@ fn http_address_ipv6_flag() {
|
||||
}
|
||||
#[test]
|
||||
fn http_port_flag() {
|
||||
let port1 = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let port2 = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let port1 = 0;
|
||||
let port2 = 0;
|
||||
CommandLineTest::new()
|
||||
.flag("http", None)
|
||||
.flag("http-port", Some(port1.to_string().as_str()))
|
||||
@ -1671,8 +1739,8 @@ fn metrics_address_ipv6_flag() {
|
||||
}
|
||||
#[test]
|
||||
fn metrics_port_flag() {
|
||||
let port1 = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let port2 = unused_tcp4_port().expect("Unable to find unused port.");
|
||||
let port1 = 0;
|
||||
let port2 = 0;
|
||||
CommandLineTest::new()
|
||||
.flag("metrics", None)
|
||||
.flag("metrics-port", Some(port1.to_string().as_str()))
|
||||
|
@ -66,8 +66,8 @@ impl<E: EthSpec> LocalNetwork<E> {
|
||||
BOOTNODE_PORT,
|
||||
QUIC_PORT,
|
||||
);
|
||||
beacon_config.network.enr_udp4_port = Some(BOOTNODE_PORT);
|
||||
beacon_config.network.enr_tcp4_port = Some(BOOTNODE_PORT);
|
||||
beacon_config.network.enr_udp4_port = Some(BOOTNODE_PORT.try_into().expect("non zero"));
|
||||
beacon_config.network.enr_tcp4_port = Some(BOOTNODE_PORT.try_into().expect("non zero"));
|
||||
beacon_config.network.discv5_config.table_filter = |_| true;
|
||||
|
||||
let execution_node = if let Some(el_config) = &mut beacon_config.execution_layer {
|
||||
@ -152,14 +152,16 @@ impl<E: EthSpec> LocalNetwork<E> {
|
||||
.expect("bootnode must have a network"),
|
||||
);
|
||||
let count = (self.beacon_node_count() + self.proposer_node_count()) as u16;
|
||||
let libp2p_tcp_port = BOOTNODE_PORT + count;
|
||||
let discv5_port = BOOTNODE_PORT + count;
|
||||
beacon_config.network.set_ipv4_listening_address(
|
||||
std::net::Ipv4Addr::UNSPECIFIED,
|
||||
BOOTNODE_PORT + count,
|
||||
BOOTNODE_PORT + count,
|
||||
libp2p_tcp_port,
|
||||
discv5_port,
|
||||
QUIC_PORT + count,
|
||||
);
|
||||
beacon_config.network.enr_udp4_port = Some(BOOTNODE_PORT + count);
|
||||
beacon_config.network.enr_tcp4_port = Some(BOOTNODE_PORT + count);
|
||||
beacon_config.network.enr_udp4_port = Some(discv5_port.try_into().unwrap());
|
||||
beacon_config.network.enr_tcp4_port = Some(libp2p_tcp_port.try_into().unwrap());
|
||||
beacon_config.network.discv5_config.table_filter = |_| true;
|
||||
beacon_config.network.proposer_only = is_proposer;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
openssl req -x509 -sha256 -nodes -days 36500 -newkey rsa:4096 -keyout web3signer/key.key -out web3signer/cert.pem -config web3signer/config &&
|
||||
openssl pkcs12 -export -out web3signer/key.p12 -inkey web3signer/key.key -in web3signer/cert.pem -password pass:$(cat web3signer/password.txt) &&
|
||||
openssl pkcs12 -export -aes256 -out web3signer/key.p12 -inkey web3signer/key.key -in web3signer/cert.pem -password pass:$(cat web3signer/password.txt) &&
|
||||
cp web3signer/cert.pem lighthouse/web3signer.pem &&
|
||||
openssl req -x509 -sha256 -nodes -days 36500 -newkey rsa:4096 -keyout lighthouse/key.key -out lighthouse/cert.pem -config lighthouse/config &&
|
||||
openssl pkcs12 -export -out lighthouse/key.p12 -inkey lighthouse/key.key -in lighthouse/cert.pem -password pass:$(cat lighthouse/password.txt) &&
|
||||
openssl pkcs12 -export -aes256 -out lighthouse/key.p12 -inkey lighthouse/key.key -in lighthouse/cert.pem -password pass:$(cat lighthouse/password.txt) &&
|
||||
openssl x509 -noout -fingerprint -sha256 -inform pem -in lighthouse/cert.pem | cut -b 20-| sed "s/^/lighthouse /" > web3signer/known_clients.txt
|
||||
|
@ -1,33 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFujCCA6KgAwIBAgIUELASgYwStCn/u/8tPByRADyCwLEwDQYJKoZIhvcNAQEL
|
||||
MIIFujCCA6KgAwIBAgIUXZijYo8W4/9dAq58ocFEbZDxohwwDQYJKoZIhvcNAQEL
|
||||
BQAwazELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZBMREwDwYDVQQHDAhTb21lQ2l0
|
||||
eTESMBAGA1UECgwJTXlDb21wYW55MRMwEQYDVQQLDApNeURpdmlzaW9uMRMwEQYD
|
||||
VQQDDApsaWdodGhvdXNlMCAXDTIzMDkyMjAzMDA1N1oYDzIxMjMwODI5MDMwMDU3
|
||||
VQQDDApsaWdodGhvdXNlMCAXDTIzMDkyMDAyNTYzNloYDzIxMjMwODI3MDI1NjM2
|
||||
WjBrMQswCQYDVQQGEwJVUzELMAkGA1UECAwCVkExETAPBgNVBAcMCFNvbWVDaXR5
|
||||
MRIwEAYDVQQKDAlNeUNvbXBhbnkxEzARBgNVBAsMCk15RGl2aXNpb24xEzARBgNV
|
||||
BAMMCmxpZ2h0aG91c2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCc
|
||||
i30cib5B/B5QNd8grzi4LxmlyfZFi3VfpukwdwOD1Xk3ODk1OtjAzhK46YhDclvc
|
||||
u98m1Dnib1Z+eTjRuEEoekIxz2+BbOle7G52LNvuDZpD+HKucqIU3TnEKPPuTYPp
|
||||
lZ1n/9EyxXUwD5uTkn7xXzK8UFXUt73j6I6VFMdHlNcwLcx8KSwBDzvnGT4ew/UL
|
||||
+ThON3j5rIT+nFHDcC2zoM+6ANdVkL6GHid4/cOcYW6GxB9TRZtEasqze41bC+kX
|
||||
ZtPlV5V2nilAzVj8z9ynwBpHkLH+E6sMUhSEwA++QfI1gGf0FmSBgSIZ3RdPo/dp
|
||||
hkLG8fZXKMkMzKkRm5hcstDP6DnTIYl+CfuVez5gZ0/yelAqXNvTqMKuDhHTTRRY
|
||||
aOXZX4BAiQO2Q6a6WYLe87E2ka5AF2T2y/BPeXjUwDS/1mFIB3FUGlMLVJt8/RLz
|
||||
nXVGoSsYapttiiPucQbMPEysCJ4/LZ9zxe3EDWWjpurLHGi/Y/dVziEvg1Eoycix
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -1,52 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
GlPvUaKC1KX0CX1qT1anVZq9bSMTG+M=
|
||||
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
|
||||
vc3Za4ClKSLmb3ZA9giTswYMev+3BQ==
|
||||
-----END PRIVATE KEY-----
|
||||
|
Binary file not shown.
@ -1,33 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -1,33 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -1,52 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
CXDusRSlsQNpzHc6QKq8IDZLut9g
|
||||
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
|
||||
oJ/aHbXf6PdOO9MYiI/es/dfKK8ywA==
|
||||
-----END PRIVATE KEY-----
|
||||
|
Binary file not shown.
@ -1 +1 @@
|
||||
lighthouse FF:4C:84:A6:37:28:EC:7E:A7:D8:C6:49:0D:C6:F9:5D:C1:06:BA:6D:69:49:0A:AA:38:32:01:2B:ED:D9:F2:FA
|
||||
lighthouse 02:D0:A8:C0:6A:59:90:40:54:67:D4:BD:AE:5A:D4:F5:14:A9:79:38:98:E0:62:93:C1:77:13:FC:B4:60:65:CE
|
||||
|
@ -56,7 +56,7 @@ itertools = { workspace = true }
|
||||
monitoring_api = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["native-tls"] }
|
||||
url = { workspace = true }
|
||||
malloc_utils = { workspace = true }
|
||||
sysinfo = { workspace = true }
|
||||
|
@ -6,20 +6,23 @@ ARCHIVE_URL := https://github.com/eth-clients/slashing-protection-interchange-te
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
ifeq (, $(shell where rm))
|
||||
rmfile = if exist $(1) (del /F /Q $(1))
|
||||
rmdir = if exist $(1) (rmdir /Q /S $(1))
|
||||
rmfile = if exist $(1) (del /F /Q $(1))
|
||||
rmdir = if exist $(1) (rmdir /Q /S $(1))
|
||||
makedir = if not exist $(1) (mkdir $(1))
|
||||
else
|
||||
rmfile = rm -f $(1)
|
||||
rmdir = rm -rf $(1)
|
||||
rmfile = rm -f $(1)
|
||||
rmdir = rm -rf $(1)
|
||||
makedir = mkdir -p $(1)
|
||||
endif
|
||||
else
|
||||
rmfile = rm -f $(1)
|
||||
rmdir = rm -rf $(1)
|
||||
rmfile = rm -f $(1)
|
||||
rmdir = rm -rf $(1)
|
||||
makedir = mkdir -p $(1)
|
||||
endif
|
||||
|
||||
$(OUTPUT_DIR): $(TARBALL)
|
||||
$(call rmdir,$@)
|
||||
mkdir $@
|
||||
$(call makedir,$@)
|
||||
tar --strip-components=1 -xzf $^ -C $@
|
||||
|
||||
$(TARBALL):
|
||||
|
@ -25,8 +25,10 @@ fn test_root_dir() -> PathBuf {
|
||||
.join("tests")
|
||||
}
|
||||
|
||||
// NOTE: I've combined two tests together to avoid a race-condition which occurs when fighting over
|
||||
// which test builds the TEST_ROOT_DIR lazy static.
|
||||
#[test]
|
||||
fn generated() {
|
||||
fn generated_and_with_minification() {
|
||||
for entry in TEST_ROOT_DIR
|
||||
.join("generated")
|
||||
.read_dir()
|
||||
@ -37,10 +39,7 @@ fn generated() {
|
||||
let test_case: MultiTestCase = serde_json::from_reader(&file).unwrap();
|
||||
test_case.run(false);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generated_with_minification() {
|
||||
for entry in TEST_ROOT_DIR
|
||||
.join("generated")
|
||||
.read_dir()
|
||||
|
@ -491,6 +491,14 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
|
||||
) -> Result<(), String> {
|
||||
let log = self.context.log();
|
||||
|
||||
if !validator_duties
|
||||
.iter()
|
||||
.any(|duty_and_proof| duty_and_proof.selection_proof.is_some())
|
||||
{
|
||||
// Exit early if no validator is aggregator
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let aggregated_attestation = &self
|
||||
.beacon_nodes
|
||||
.first_success(
|
||||
|
@ -1176,7 +1176,8 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
.or(get_fee_recipient)
|
||||
.or(get_gas_limit)
|
||||
.or(get_std_keystores)
|
||||
.or(get_std_remotekeys),
|
||||
.or(get_std_remotekeys)
|
||||
.recover(warp_utils::reject::handle_rejection),
|
||||
)
|
||||
.or(warp::post().and(
|
||||
post_validators
|
||||
@ -1187,15 +1188,18 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
.or(post_fee_recipient)
|
||||
.or(post_gas_limit)
|
||||
.or(post_std_keystores)
|
||||
.or(post_std_remotekeys),
|
||||
.or(post_std_remotekeys)
|
||||
.recover(warp_utils::reject::handle_rejection),
|
||||
))
|
||||
.or(warp::patch().and(patch_validators))
|
||||
.or(warp::patch()
|
||||
.and(patch_validators.recover(warp_utils::reject::handle_rejection)))
|
||||
.or(warp::delete().and(
|
||||
delete_lighthouse_keystores
|
||||
.or(delete_fee_recipient)
|
||||
.or(delete_gas_limit)
|
||||
.or(delete_std_keystores)
|
||||
.or(delete_std_remotekeys),
|
||||
.or(delete_std_remotekeys)
|
||||
.recover(warp_utils::reject::handle_rejection),
|
||||
)),
|
||||
)
|
||||
// The auth route and logs are the only routes that are allowed to be accessed without the API token.
|
||||
|
@ -2146,7 +2146,7 @@ async fn import_remotekey_web3signer_enabled() {
|
||||
assert_eq!(tester.vals_total(), 1);
|
||||
assert_eq!(tester.vals_enabled(), 1);
|
||||
let vals = tester.initialized_validators.read();
|
||||
let web3_vals = vals.validator_definitions().clone();
|
||||
let web3_vals = vals.validator_definitions();
|
||||
|
||||
// Import remotekeys.
|
||||
let import_res = tester
|
||||
@ -2164,7 +2164,7 @@ async fn import_remotekey_web3signer_enabled() {
|
||||
assert_eq!(tester.vals_total(), 1);
|
||||
assert_eq!(tester.vals_enabled(), 1);
|
||||
let vals = tester.initialized_validators.read();
|
||||
let remote_vals = vals.validator_definitions().clone();
|
||||
let remote_vals = vals.validator_definitions();
|
||||
|
||||
// Web3signer should not be overwritten since it is enabled.
|
||||
assert!(web3_vals == remote_vals);
|
||||
|
Loading…
Reference in New Issue
Block a user