mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
Compare commits
91 Commits
yk/worker-
...
feat/check
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85f061d77d | ||
|
|
988ae03dd0 | ||
|
|
e739505b34 | ||
|
|
3380eb69c8 | ||
|
|
0366497ada | ||
|
|
cd71f3d5a4 | ||
|
|
64909d33e6 | ||
|
|
3c9ad31344 | ||
|
|
f3e14fd061 | ||
|
|
daf6b88dc6 | ||
|
|
d2d58f9a0e | ||
|
|
ace4e515b5 | ||
|
|
134164954b | ||
|
|
2775dd1f23 | ||
|
|
ac0f9687bd | ||
|
|
a9c21a395d | ||
|
|
df7ad9ae45 | ||
|
|
5903e42a98 | ||
|
|
3c41b99599 | ||
|
|
d70d80fff1 | ||
|
|
ed3a8a03d5 | ||
|
|
bfcd46d01d | ||
|
|
194d545fae | ||
|
|
97243ec1f4 | ||
|
|
93c1b0f52f | ||
|
|
474c09095f | ||
|
|
24c298133f | ||
|
|
da27336a1e | ||
|
|
2e567d6658 | ||
|
|
28e7c8a7cb | ||
|
|
a2a5e03cb8 | ||
|
|
6073aa5b4a | ||
|
|
e90cfedf3d | ||
|
|
8b27ca6fa2 | ||
|
|
1752d6fb99 | ||
|
|
ac891a780b | ||
|
|
036626b8a7 | ||
|
|
68f0c9812f | ||
|
|
c9920c9690 | ||
|
|
af82606ff4 | ||
|
|
38331a362e | ||
|
|
e8dae2ae7d | ||
|
|
ce5f90175b | ||
|
|
8c361c87c2 | ||
|
|
4fbbb1fe54 | ||
|
|
b7d8815104 | ||
|
|
b91cd8f451 | ||
|
|
09aee4e35a | ||
|
|
505a384b10 | ||
|
|
6e00b99b67 | ||
|
|
1d389cfe7a | ||
|
|
2e62387469 | ||
|
|
31133255fe | ||
|
|
a6b9472d1c | ||
|
|
6636d2a2ad | ||
|
|
ab6854d159 | ||
|
|
5a274fc939 | ||
|
|
c9431b224b | ||
|
|
8cbfd91db0 | ||
|
|
43f9942ba7 | ||
|
|
06adc3ee0c | ||
|
|
fbf6be4cf2 | ||
|
|
21d61d40d1 | ||
|
|
cf7d709358 | ||
|
|
e9355caba5 | ||
|
|
fdd9d5bb40 | ||
|
|
9eeba7e6b3 | ||
|
|
0085acc868 | ||
|
|
c697147f90 | ||
|
|
7388d6636d | ||
|
|
0b859c0735 | ||
|
|
a8e0606fa7 | ||
|
|
969689d9b6 | ||
|
|
ad2081493a | ||
|
|
abfb6d3965 | ||
|
|
0f0eb7a531 | ||
|
|
4f1e486b4f | ||
|
|
05307d088c | ||
|
|
245cca7ce2 | ||
|
|
28d6996fc4 | ||
|
|
0eaffdf489 | ||
|
|
9c141cac4b | ||
|
|
fc6ab35c5c | ||
|
|
f88bf4e427 | ||
|
|
3d330caf36 | ||
|
|
5a43e77771 | ||
|
|
5b3c479ed5 | ||
|
|
dc06b47abe | ||
|
|
e9cd7cc003 | ||
|
|
f633efc969 | ||
|
|
2f55b1c30f |
7
.github/actionlint.yaml
vendored
Normal file
7
.github/actionlint.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
self-hosted-runner:
|
||||
labels:
|
||||
- depot-ubuntu-latest
|
||||
- depot-ubuntu-latest-2
|
||||
- depot-ubuntu-latest-4
|
||||
- depot-ubuntu-latest-8
|
||||
- depot-ubuntu-latest-16
|
||||
2
.github/assets/hive/run_simulator.sh
vendored
2
.github/assets/hive/run_simulator.sh
vendored
@@ -7,7 +7,7 @@ sim="${1}"
|
||||
limit="${2}"
|
||||
|
||||
run_hive() {
|
||||
hive --sim "${sim}" --sim.limit "${limit}" --sim.parallelism 8 --client reth 2>&1 | tee /tmp/log || true
|
||||
hive --sim "${sim}" --sim.limit "${limit}" --sim.parallelism 16 --client reth 2>&1 | tee /tmp/log || true
|
||||
}
|
||||
|
||||
check_log() {
|
||||
|
||||
5
.github/workflows/bench.yml
vendored
5
.github/workflows/bench.yml
vendored
@@ -11,18 +11,19 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
BASELINE: base
|
||||
SEED: reth
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
name: bench
|
||||
jobs:
|
||||
codspeed:
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
7
.github/workflows/book.yml
vendored
7
.github/workflows/book.yml
vendored
@@ -10,9 +10,12 @@ on:
|
||||
types: [opened, reopened, synchronize, closed]
|
||||
merge_group:
|
||||
|
||||
env:
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest-8
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -33,6 +36,8 @@ jobs:
|
||||
- name: Install Rust nightly
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
|
||||
- name: Build docs
|
||||
run: cd docs/vocs && bash scripts/build-cargo-docs.sh
|
||||
|
||||
|
||||
5
.github/workflows/compact.yml
vendored
5
.github/workflows/compact.yml
vendored
@@ -13,12 +13,12 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
name: compact-codec
|
||||
jobs:
|
||||
compact-codec:
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
bin:
|
||||
@@ -27,6 +27,7 @@ jobs:
|
||||
steps:
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
6
.github/workflows/e2e.yml
vendored
6
.github/workflows/e2e.yml
vendored
@@ -11,6 +11,7 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
SEED: rustethereumethereumrust
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -19,14 +20,14 @@ concurrency:
|
||||
jobs:
|
||||
test:
|
||||
name: e2e-testsuite
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: taiki-e/install-action@nextest
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
@@ -43,4 +44,3 @@ jobs:
|
||||
--exclude 'op-reth' \
|
||||
--exclude 'reth' \
|
||||
-E 'binary(e2e_testsuite)'
|
||||
|
||||
|
||||
9
.github/workflows/hive.yml
vendored
9
.github/workflows/hive.yml
vendored
@@ -24,8 +24,7 @@ jobs:
|
||||
prepare-hive:
|
||||
if: github.repository == 'paradigmxyz/reth'
|
||||
timeout-minutes: 45
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Checkout hive tests
|
||||
@@ -179,8 +178,7 @@ jobs:
|
||||
- prepare-reth
|
||||
- prepare-hive
|
||||
name: run ${{ matrix.scenario.sim }}${{ matrix.scenario.limit && format(' - {0}', matrix.scenario.limit) }}
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
@@ -247,8 +245,7 @@ jobs:
|
||||
notify-on-error:
|
||||
needs: test
|
||||
if: failure()
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Slack Webhook Action
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
|
||||
6
.github/workflows/integration.yml
vendored
6
.github/workflows/integration.yml
vendored
@@ -14,6 +14,7 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
SEED: rustethereumethereumrust
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -23,8 +24,7 @@ jobs:
|
||||
test:
|
||||
name: test / ${{ matrix.network }}
|
||||
if: github.event_name != 'schedule'
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
strategy:
|
||||
@@ -38,6 +38,7 @@ jobs:
|
||||
- name: Install Geth
|
||||
run: .github/assets/install_geth.sh
|
||||
- uses: taiki-e/install-action@nextest
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -75,6 +76,7 @@ jobs:
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: taiki-e/install-action@nextest
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
9
.github/workflows/kurtosis-op.yml
vendored
9
.github/workflows/kurtosis-op.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
- "*"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -32,8 +32,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
name: run kurtosis
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
needs:
|
||||
- prepare-reth
|
||||
steps:
|
||||
@@ -83,12 +82,10 @@ jobs:
|
||||
kurtosis service logs -a op-devnet op-cl-2151908-2-op-node-op-reth-op-kurtosis
|
||||
exit 1
|
||||
|
||||
|
||||
notify-on-error:
|
||||
needs: test
|
||||
if: failure()
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Slack Webhook Action
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
|
||||
10
.github/workflows/kurtosis.yml
vendored
10
.github/workflows/kurtosis.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
- "*"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -30,8 +30,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
name: run kurtosis
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
needs:
|
||||
- prepare-reth
|
||||
steps:
|
||||
@@ -54,13 +53,12 @@ jobs:
|
||||
- name: Run kurtosis
|
||||
uses: ethpandaops/kurtosis-assertoor-github-action@v1
|
||||
with:
|
||||
ethereum_package_args: '.github/assets/kurtosis_network_params.yaml'
|
||||
ethereum_package_args: ".github/assets/kurtosis_network_params.yaml"
|
||||
|
||||
notify-on-error:
|
||||
needs: test
|
||||
if: failure()
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Slack Webhook Action
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
|
||||
57
.github/workflows/lint.yml
vendored
57
.github/workflows/lint.yml
vendored
@@ -8,11 +8,12 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
jobs:
|
||||
clippy-binaries:
|
||||
name: clippy binaries / ${{ matrix.type }}
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -26,6 +27,7 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@clippy
|
||||
with:
|
||||
components: clippy
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -40,7 +42,7 @@ jobs:
|
||||
|
||||
clippy:
|
||||
name: clippy
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -48,6 +50,7 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: clippy
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -56,7 +59,7 @@ jobs:
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
wasm:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -65,6 +68,7 @@ jobs:
|
||||
with:
|
||||
target: wasm32-wasip1
|
||||
- uses: taiki-e/install-action@cargo-hack
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -75,7 +79,7 @@ jobs:
|
||||
.github/assets/check_wasm.sh
|
||||
|
||||
riscv:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -84,6 +88,7 @@ jobs:
|
||||
with:
|
||||
target: riscv32imac-unknown-none-elf
|
||||
- uses: taiki-e/install-action@cargo-hack
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -93,17 +98,18 @@ jobs:
|
||||
|
||||
crate-checks:
|
||||
name: crate-checks (${{ matrix.partition }}/${{ matrix.total_partitions }})
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
strategy:
|
||||
matrix:
|
||||
partition: [1, 2]
|
||||
total_partitions: [2]
|
||||
partition: [1, 2, 3]
|
||||
total_partitions: [3]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: taiki-e/install-action@cargo-hack
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -111,7 +117,7 @@ jobs:
|
||||
|
||||
msrv:
|
||||
name: MSRV
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -124,6 +130,7 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: "1.88" # MSRV
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -133,12 +140,13 @@ jobs:
|
||||
|
||||
docs:
|
||||
name: docs
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -150,7 +158,7 @@ jobs:
|
||||
|
||||
fmt:
|
||||
name: fmt
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -158,17 +166,19 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: rustfmt
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- name: Run fmt
|
||||
run: cargo fmt --all --check
|
||||
|
||||
udeps:
|
||||
name: udeps
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -177,12 +187,13 @@ jobs:
|
||||
|
||||
book:
|
||||
name: book
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -232,31 +243,43 @@ jobs:
|
||||
- name: Ensure no arbitrary or proptest dependency on default build
|
||||
run: cargo tree --package reth -e=features,no-dev | grep -Eq "arbitrary|proptest" && exit 1 || exit 0
|
||||
|
||||
# Checks that selected rates can compile with power set of features
|
||||
# Checks that selected crates can compile with power set of features
|
||||
features:
|
||||
name: features
|
||||
runs-on: ubuntu-latest
|
||||
name: features (${{ matrix.partition }}/${{ matrix.total_partitions }})
|
||||
runs-on: depot-ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
partition: [1, 2]
|
||||
total_partitions: [2]
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@clippy
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
- name: cargo install cargo-hack
|
||||
uses: taiki-e/install-action@cargo-hack
|
||||
- run: make check-features
|
||||
- run: |
|
||||
cargo hack check \
|
||||
--package reth-codecs \
|
||||
--package reth-primitives-traits \
|
||||
--package reth-primitives \
|
||||
--feature-powerset \
|
||||
--partition ${{ matrix.partition }}/${{ matrix.total_partitions }}
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
# Check crates correctly propagate features
|
||||
feature-propagation:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: taiki-e/cache-cargo-install-action@v2
|
||||
with:
|
||||
|
||||
3
.github/workflows/prepare-reth.yml
vendored
3
.github/workflows/prepare-reth.yml
vendored
@@ -26,8 +26,7 @@ jobs:
|
||||
prepare-reth:
|
||||
if: github.repository == 'paradigmxyz/reth'
|
||||
timeout-minutes: 45
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- run: mkdir artifacts
|
||||
|
||||
2
.github/workflows/release-dist.yml
vendored
2
.github/workflows/release-dist.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Update Homebrew formula
|
||||
uses: dawidd6/action-homebrew-bump-formula@v6
|
||||
uses: dawidd6/action-homebrew-bump-formula@v7
|
||||
with:
|
||||
token: ${{ secrets.HOMEBREW }}
|
||||
no_fork: true
|
||||
|
||||
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -22,6 +22,7 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
DOCKER_IMAGE_NAME_URL: https://ghcr.io/${{ github.repository_owner }}/reth
|
||||
DOCKER_OP_IMAGE_NAME_URL: https://ghcr.io/${{ github.repository_owner }}/op-reth
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
jobs:
|
||||
dry-run:
|
||||
@@ -51,6 +52,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- name: Verify crate version matches tag
|
||||
# Check that the Cargo version starts with the tag,
|
||||
# so that Cargo version 1.4.8 can be matched against both v1.4.8 and v1.4.8-rc.1
|
||||
@@ -104,6 +106,7 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
target: ${{ matrix.configs.target }}
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- name: Install cross main
|
||||
id: cross_main
|
||||
run: |
|
||||
|
||||
5
.github/workflows/stage.yml
vendored
5
.github/workflows/stage.yml
vendored
@@ -12,6 +12,7 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
FROM_BLOCK: 0
|
||||
TO_BLOCK: 50000
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -22,8 +23,7 @@ jobs:
|
||||
name: stage-run-test
|
||||
# Only run stage commands test in merge groups
|
||||
if: github.event_name == 'merge_group'
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
env:
|
||||
RUST_LOG: info,sync=error
|
||||
RUST_BACKTRACE: 1
|
||||
@@ -32,6 +32,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
7
.github/workflows/sync-era.yml
vendored
7
.github/workflows/sync-era.yml
vendored
@@ -9,6 +9,7 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -17,8 +18,7 @@ concurrency:
|
||||
jobs:
|
||||
sync:
|
||||
name: sync (${{ matrix.chain.bin }})
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
env:
|
||||
RUST_LOG: info,sync=error
|
||||
RUST_BACKTRACE: 1
|
||||
@@ -42,6 +42,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -64,4 +65,4 @@ jobs:
|
||||
${{ matrix.chain.bin }} stage unwind num-blocks 100 --chain ${{ matrix.chain.chain }}
|
||||
- name: Run stage unwind to block hash
|
||||
run: |
|
||||
${{ matrix.chain.bin }} stage unwind to-block ${{ matrix.chain.unwind-target }} --chain ${{ matrix.chain.chain }}
|
||||
${{ matrix.chain.bin }} stage unwind to-block ${{ matrix.chain.unwind-target }} --chain ${{ matrix.chain.chain }}
|
||||
|
||||
7
.github/workflows/sync.yml
vendored
7
.github/workflows/sync.yml
vendored
@@ -9,6 +9,7 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -17,8 +18,7 @@ concurrency:
|
||||
jobs:
|
||||
sync:
|
||||
name: sync (${{ matrix.chain.bin }})
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
env:
|
||||
RUST_LOG: info,sync=error
|
||||
RUST_BACKTRACE: 1
|
||||
@@ -42,6 +42,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -63,4 +64,4 @@ jobs:
|
||||
${{ matrix.chain.bin }} stage unwind num-blocks 100 --chain ${{ matrix.chain.chain }}
|
||||
- name: Run stage unwind to block hash
|
||||
run: |
|
||||
${{ matrix.chain.bin }} stage unwind to-block ${{ matrix.chain.unwind-target }} --chain ${{ matrix.chain.chain }}
|
||||
${{ matrix.chain.bin }} stage unwind to-block ${{ matrix.chain.unwind-target }} --chain ${{ matrix.chain.chain }}
|
||||
|
||||
13
.github/workflows/unit.yml
vendored
13
.github/workflows/unit.yml
vendored
@@ -11,6 +11,7 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
SEED: rustethereumethereumrust
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -19,8 +20,7 @@ concurrency:
|
||||
jobs:
|
||||
test:
|
||||
name: test / ${{ matrix.type }} (${{ matrix.partition }}/${{ matrix.total_partitions }})
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
strategy:
|
||||
@@ -47,6 +47,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -65,8 +66,7 @@ jobs:
|
||||
|
||||
state:
|
||||
name: Ethereum state tests
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
env:
|
||||
RUST_LOG: info,sync=error
|
||||
RUST_BACKTRACE: 1
|
||||
@@ -93,6 +93,7 @@ jobs:
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: taiki-e/install-action@nextest
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -100,8 +101,7 @@ jobs:
|
||||
|
||||
doc:
|
||||
name: doc tests
|
||||
runs-on:
|
||||
group: Reth
|
||||
runs-on: depot-ubuntu-latest
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
timeout-minutes: 30
|
||||
@@ -109,6 +109,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
9
.github/workflows/windows.yml
vendored
9
.github/workflows/windows.yml
vendored
@@ -9,9 +9,12 @@ on:
|
||||
branches: [main]
|
||||
merge_group:
|
||||
|
||||
env:
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
jobs:
|
||||
check-reth:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
@@ -21,6 +24,7 @@ jobs:
|
||||
with:
|
||||
target: x86_64-pc-windows-gnu
|
||||
- uses: taiki-e/install-action@cross
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
@@ -30,7 +34,7 @@ jobs:
|
||||
run: cargo check --target x86_64-pc-windows-gnu
|
||||
|
||||
check-op-reth:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
@@ -40,6 +44,7 @@ jobs:
|
||||
with:
|
||||
target: x86_64-pc-windows-gnu
|
||||
- uses: taiki-e/install-action@cross
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
269
Cargo.lock
generated
269
Cargo.lock
generated
@@ -97,9 +97,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "alloy-chains"
|
||||
version = "0.2.20"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bc32535569185cbcb6ad5fa64d989a47bccb9a08e27284b1f2a3ccf16e6d010"
|
||||
checksum = "1b9ebac8ff9c2f07667e1803dc777304337e160ce5153335beb45e8ec0751808"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rlp",
|
||||
@@ -112,9 +112,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-consensus"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b6440213a22df93a87ed512d2f668e7dc1d62a05642d107f82d61edc9e12370"
|
||||
checksum = "2e318e25fb719e747a7e8db1654170fc185024f3ed5b10f86c08d448a912f6e2"
|
||||
dependencies = [
|
||||
"alloy-eips",
|
||||
"alloy-primitives",
|
||||
@@ -140,9 +140,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-consensus-any"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15d0bea09287942405c4f9d2a4f22d1e07611c2dbd9d5bf94b75366340f9e6e0"
|
||||
checksum = "364380a845193a317bcb7a5398fc86cdb66c47ebe010771dde05f6869bf9e64a"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -155,9 +155,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-contract"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d69af404f1d00ddb42f2419788fa87746a4cd13bab271916d7726fda6c792d94"
|
||||
checksum = "08d39c80ffc806f27a76ed42f3351a455f3dc4f81d6ff92c8aad2cf36b7d3a34"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-dyn-abi",
|
||||
@@ -239,10 +239,22 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloy-eips"
|
||||
version = "1.1.2"
|
||||
name = "alloy-eip7928"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bd2c7ae05abcab4483ce821f12f285e01c0b33804e6883dd9ca1569a87ee2be"
|
||||
checksum = "926b2c0d34e641cf8b17bf54ce50fda16715b9f68ad878fa6128bae410c6f890"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rlp",
|
||||
"borsh",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloy-eips"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c4d7c5839d9f3a467900c625416b24328450c65702eb3d8caff8813e4d1d33"
|
||||
dependencies = [
|
||||
"alloy-eip2124",
|
||||
"alloy-eip2930",
|
||||
@@ -266,9 +278,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-evm"
|
||||
version = "0.24.2"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01be36ba6f5e6e62563b369e03ca529eac46aea50677f84655084b4750816574"
|
||||
checksum = "3e7b4fb2418490bca9978e74208215ed5fcb21a10aba7eea487abaa60fd588db"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -288,9 +300,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-genesis"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc47eaae86488b07ea8e20236184944072a78784a1f4993f8ec17b3aa5d08c21"
|
||||
checksum = "1ba4b1be0988c11f0095a2380aa596e35533276b8fa6c9e06961bbfe0aebcac5"
|
||||
dependencies = [
|
||||
"alloy-eips",
|
||||
"alloy-primitives",
|
||||
@@ -329,9 +341,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-json-rpc"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "003f46c54f22854a32b9cc7972660a476968008ad505427eabab49225309ec40"
|
||||
checksum = "f72cf87cda808e593381fb9f005ffa4d2475552b7a6c5ac33d087bf77d82abd0"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-sol-types",
|
||||
@@ -344,9 +356,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-network"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f4029954d9406a40979f3a3b46950928a0fdcfe3ea8a9b0c17490d57e8aa0e3"
|
||||
checksum = "12aeb37b6f2e61b93b1c3d34d01ee720207c76fe447e2a2c217e433ac75b17f5"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-consensus-any",
|
||||
@@ -370,9 +382,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-network-primitives"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7805124ad69e57bbae7731c9c344571700b2a18d351bda9e0eba521c991d1bcb"
|
||||
checksum = "abd29ace62872083e30929cd9b282d82723196d196db589f3ceda67edcc05552"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -383,9 +395,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-op-evm"
|
||||
version = "0.24.2"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "231262d7e06000f3fb642d32d38ca75e09e78e04977c10be0a07a5ee2c869cfd"
|
||||
checksum = "56afbe3c3b66435c7c3846fe639a60e4cdbc31b9263596eb2f382408b1b160c4"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -401,9 +413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-op-hardforks"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ac97adaba4c26e17192d81f49186ac20c1e844e35a00e169c8d3d58bc84e6b"
|
||||
checksum = "f96fb2fce4024ada5b2c11d4076acf778a0d3e4f011c6dfd2ffce6d0fcf84ee9"
|
||||
dependencies = [
|
||||
"alloy-chains",
|
||||
"alloy-hardforks",
|
||||
@@ -444,9 +456,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-provider"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d369e12c92870d069e0c9dc5350377067af8a056e29e3badf8446099d7e00889"
|
||||
checksum = "9b710636d7126e08003b8217e24c09f0cca0b46d62f650a841736891b1ed1fc1"
|
||||
dependencies = [
|
||||
"alloy-chains",
|
||||
"alloy-consensus",
|
||||
@@ -489,9 +501,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-pubsub"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f77d20cdbb68a614c7a86b3ffef607b37d087bb47a03c58f4c3f8f99bc3ace3b"
|
||||
checksum = "cdd4c64eb250a18101d22ae622357c6b505e158e9165d4c7974d59082a600c5e"
|
||||
dependencies = [
|
||||
"alloy-json-rpc",
|
||||
"alloy-primitives",
|
||||
@@ -533,9 +545,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-client"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31c89883fe6b7381744cbe80fef638ac488ead4f1956a4278956a1362c71cd2e"
|
||||
checksum = "d0882e72d2c1c0c79dcf4ab60a67472d3f009a949f774d4c17d0bdb669cfde05"
|
||||
dependencies = [
|
||||
"alloy-json-rpc",
|
||||
"alloy-primitives",
|
||||
@@ -559,9 +571,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e279e6d40ee40fe8f76753b678d8d5d260cb276dc6c8a8026099b16d2b43f4"
|
||||
checksum = "39cf1398cb33aacb139a960fa3d8cf8b1202079f320e77e952a0b95967bf7a9f"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rpc-types-engine",
|
||||
@@ -572,9 +584,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-admin"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bcf50ccb65d29b8599f8f5e23dcac685f1d79459654c830cba381345760e901"
|
||||
checksum = "65a583d2029b171301f5dcf122aa2ef443a65a373778ec76540d999691ae867d"
|
||||
dependencies = [
|
||||
"alloy-genesis",
|
||||
"alloy-primitives",
|
||||
@@ -584,9 +596,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-anvil"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e176c26fdd87893b6afeb5d92099d8f7e7a1fe11d6f4fe0883d6e33ac5f31ba"
|
||||
checksum = "c3ce4c24e416bd0f17fceeb2f26cd8668df08fe19e1dc02f9d41c3b8ed1e93e0"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rpc-types-eth",
|
||||
@@ -596,9 +608,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-any"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b43c1622aac2508d528743fd4cfdac1dea92d5a8fa894038488ff7edd0af0b32"
|
||||
checksum = "6a63fb40ed24e4c92505f488f9dd256e2afaed17faa1b7a221086ebba74f4122"
|
||||
dependencies = [
|
||||
"alloy-consensus-any",
|
||||
"alloy-rpc-types-eth",
|
||||
@@ -607,9 +619,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-beacon"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1786681640d4c60f22b6b8376b0f3fa200360bf1c3c2cb913e6c97f51928eb1b"
|
||||
checksum = "16633087e23d8d75161c3a59aa183203637b817a5a8d2f662f612ccb6d129af0"
|
||||
dependencies = [
|
||||
"alloy-eips",
|
||||
"alloy-primitives",
|
||||
@@ -627,9 +639,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-debug"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b2ca3a434a6d49910a7e8e51797eb25db42ef8a5578c52d877fcb26d0afe7bc"
|
||||
checksum = "4936f579d9d10eae01772b2ab3497f9d568684f05f26f8175e12f9a1a2babc33"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"derive_more",
|
||||
@@ -639,9 +651,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-engine"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4c53a8b0905d931e7921774a1830609713bd3e8222347963172b03a3ecc68"
|
||||
checksum = "4c60bdce3be295924122732b7ecd0b2495ce4790bedc5370ca7019c08ad3f26e"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -660,9 +672,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-eth"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5fafb741c19b3cca4cdd04fa215c89413491f9695a3e928dee2ae5657f607e"
|
||||
checksum = "9eae0c7c40da20684548cbc8577b6b7447f7bf4ddbac363df95e3da220e41e72"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-consensus-any",
|
||||
@@ -682,9 +694,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-mev"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49a97bfc6d9b411c85bb08e1174ddd3e5d61b10d3bd13f529d6609f733cb2f6f"
|
||||
checksum = "81c0dd81c24944cfbf45b5df7cd149d9cd3e354db81ccf08aa47e0e05be8ab97"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -697,9 +709,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-trace"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c55324323aa634b01bdecb2d47462a8dce05f5505b14a6e5db361eef16eda476"
|
||||
checksum = "ef206a4b8d436fbb7cf2e6a61c692d11df78f9382becc3c9a283bd58e64f0583"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rpc-types-eth",
|
||||
@@ -711,9 +723,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-rpc-types-txpool"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96b1aa28effb6854be356ce92ed64cea3b323acd04c3f8bfb5126e2839698043"
|
||||
checksum = "ecb5a795264a02222f9534435b8f40dcbd88de8e9d586647884aae24f389ebf2"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rpc-types-eth",
|
||||
@@ -723,9 +735,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-serde"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6f180c399ca7c1e2fe17ea58343910cad0090878a696ff5a50241aee12fc529"
|
||||
checksum = "c0df1987ed0ff2d0159d76b52e7ddfc4e4fbddacc54d2fbee765e0d14d7c01b5"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"arbitrary",
|
||||
@@ -735,9 +747,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-signer"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc39ad2c0a3d2da8891f4081565780703a593f090f768f884049aa3aa929cbc"
|
||||
checksum = "6ff69deedee7232d7ce5330259025b868c5e6a52fa8dffda2c861fb3a5889b24"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"async-trait",
|
||||
@@ -750,9 +762,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-signer-local"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "930e17cb1e46446a193a593a3bfff8d0ecee4e510b802575ebe300ae2e43ef75"
|
||||
checksum = "72cfe0be3ec5a8c1a46b2e5a7047ed41121d360d97f4405bb7c1c784880c86cb"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-network",
|
||||
@@ -839,9 +851,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-transport"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cae82426d98f8bc18f53c5223862907cac30ab8fc5e4cd2bb50808e6d3ab43d8"
|
||||
checksum = "be98b07210d24acf5b793c99b759e9a696e4a2e67593aec0487ae3b3e1a2478c"
|
||||
dependencies = [
|
||||
"alloy-json-rpc",
|
||||
"auto_impl",
|
||||
@@ -862,9 +874,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-transport-http"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90aa6825760905898c106aba9c804b131816a15041523e80b6d4fe7af6380ada"
|
||||
checksum = "4198a1ee82e562cab85e7f3d5921aab725d9bd154b6ad5017f82df1695877c97"
|
||||
dependencies = [
|
||||
"alloy-json-rpc",
|
||||
"alloy-transport",
|
||||
@@ -877,9 +889,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-transport-ipc"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ace83a4a6bb896e5894c3479042e6ba78aa5271dde599aa8c36a021d49cc8cc"
|
||||
checksum = "d8db249779ebc20dc265920c7e706ed0d31dbde8627818d1cbde60919b875bb0"
|
||||
dependencies = [
|
||||
"alloy-json-rpc",
|
||||
"alloy-pubsub",
|
||||
@@ -897,9 +909,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-transport-ws"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86c9ab4c199e3a8f3520b60ba81aa67bb21fed9ed0d8304e0569094d0758a56f"
|
||||
checksum = "5ad2344a12398d7105e3722c9b7a7044ea837128e11d453604dec6e3731a86e2"
|
||||
dependencies = [
|
||||
"alloy-pubsub",
|
||||
"alloy-transport",
|
||||
@@ -935,9 +947,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-tx-macros"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae109e33814b49fc0a62f2528993aa8a2dd346c26959b151f05441dc0b9da292"
|
||||
checksum = "333544408503f42d7d3792bfc0f7218b643d968a03d2c0ed383ae558fb4a76d0"
|
||||
dependencies = [
|
||||
"darling 0.21.3",
|
||||
"proc-macro2",
|
||||
@@ -1627,15 +1639,15 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin-io"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf"
|
||||
checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953"
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin_hashes"
|
||||
version = "0.14.0"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
|
||||
checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b"
|
||||
dependencies = [
|
||||
"bitcoin-io",
|
||||
"hex-conservative",
|
||||
@@ -2471,9 +2483,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.7.1"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7"
|
||||
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
@@ -2978,22 +2990,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "2.0.1"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
|
||||
checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "2.0.1"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
|
||||
checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version 0.4.1",
|
||||
"syn 2.0.111",
|
||||
"unicode-xid",
|
||||
]
|
||||
@@ -3670,6 +3683,17 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "example-custom-rpc-middleware"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"jsonrpsee",
|
||||
"reth-ethereum",
|
||||
"tower",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "example-db-access"
|
||||
version = "0.0.0"
|
||||
@@ -3981,9 +4005,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.5"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
|
||||
checksum = "a2152dbcb980c05735e2a651d96011320a949eb31a0c8b38b72645ce97dec676"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -4277,9 +4301,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.20.2"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
|
||||
checksum = "3e2b37e2f62729cdada11f0e6b3b6fe383c69c29fc619e391223e12856af308c"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"libc",
|
||||
@@ -4704,9 +4728,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.18"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
|
||||
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
@@ -5416,15 +5440,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
version = "0.2.178"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.18.2+1.9.1"
|
||||
version = "0.18.3+1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222"
|
||||
checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -5569,9 +5593,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.28"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
@@ -5839,9 +5863,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
|
||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
@@ -6187,9 +6211,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
|
||||
|
||||
[[package]]
|
||||
name = "op-alloy"
|
||||
version = "0.22.4"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3b13412d297c1f9341f678b763750b120a73ffe998fa54a94d6eda98449e7ca"
|
||||
checksum = "5f8cef53b364f406ed2be3a447b2d8f2f18b07a6ff1255c287debb4cda68095b"
|
||||
dependencies = [
|
||||
"op-alloy-consensus",
|
||||
"op-alloy-network",
|
||||
@@ -6200,9 +6224,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "op-alloy-consensus"
|
||||
version = "0.22.4"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "726da827358a547be9f1e37c2a756b9e3729cb0350f43408164794b370cad8ae"
|
||||
checksum = "736381a95471d23e267263cfcee9e1d96d30b9754a94a2819148f83379de8a86"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -6226,9 +6250,9 @@ checksum = "a79f352fc3893dcd670172e615afef993a41798a1d3fc0db88a3e60ef2e70ecc"
|
||||
|
||||
[[package]]
|
||||
name = "op-alloy-network"
|
||||
version = "0.22.4"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f63f27e65be273ec8fcb0b6af0fd850b550979465ab93423705ceb3dfddbd2ab"
|
||||
checksum = "4034183dca6bff6632e7c24c92e75ff5f0eabb58144edb4d8241814851334d47"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-network",
|
||||
@@ -6242,9 +6266,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "op-alloy-provider"
|
||||
version = "0.22.4"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a71456699aa256dc20119736422ad9a44da8b9585036117afb936778122093b9"
|
||||
checksum = "9f1c952895ad45087d35d323e3fb73c0b5de7c6852494d81ebe997030366196a"
|
||||
dependencies = [
|
||||
"alloy-network",
|
||||
"alloy-primitives",
|
||||
@@ -6257,9 +6281,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "op-alloy-rpc-jsonrpsee"
|
||||
version = "0.22.4"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ef9114426b16172254555aad34a8ea96c01895e40da92f5d12ea680a1baeaa7"
|
||||
checksum = "c1c820ef9c802ebc732281a940bfb6ac2345af4d9fff041cbb64b4b546676686"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"jsonrpsee",
|
||||
@@ -6267,9 +6291,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "op-alloy-rpc-types"
|
||||
version = "0.22.4"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562dd4462562c41f9fdc4d860858c40e14a25df7f983ae82047f15f08fce4d19"
|
||||
checksum = "ddd87c6b9e5b6eee8d6b76f41b04368dca0e9f38d83338e5b00e730c282098a4"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -6287,9 +6311,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "op-alloy-rpc-types-engine"
|
||||
version = "0.22.4"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8f24b8cb66e4b33e6c9e508bf46b8ecafc92eadd0b93fedd306c0accb477657"
|
||||
checksum = "77727699310a18cdeed32da3928c709e2704043b6584ed416397d5da65694efc"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -6303,6 +6327,7 @@ dependencies = [
|
||||
"ethereum_ssz_derive",
|
||||
"op-alloy-consensus",
|
||||
"serde",
|
||||
"sha2",
|
||||
"snap",
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
@@ -6792,7 +6817,7 @@ version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
|
||||
dependencies = [
|
||||
"toml_edit 0.23.7",
|
||||
"toml_edit 0.23.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8195,6 +8220,7 @@ name = "reth-engine-tree"
|
||||
version = "1.9.3"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eip7928",
|
||||
"alloy-eips",
|
||||
"alloy-evm",
|
||||
"alloy-primitives",
|
||||
@@ -9219,6 +9245,7 @@ dependencies = [
|
||||
"alloy-sol-types",
|
||||
"eyre",
|
||||
"futures",
|
||||
"jsonrpsee-core",
|
||||
"rand 0.9.2",
|
||||
"reth-chainspec",
|
||||
"reth-db",
|
||||
@@ -9254,6 +9281,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"similar-asserts",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@@ -10144,6 +10172,7 @@ dependencies = [
|
||||
"reth-db-api",
|
||||
"reth-engine-primitives",
|
||||
"reth-errors",
|
||||
"reth-ethereum-engine-primitives",
|
||||
"reth-ethereum-primitives",
|
||||
"reth-evm",
|
||||
"reth-evm-ethereum",
|
||||
@@ -10206,6 +10235,9 @@ dependencies = [
|
||||
"reth-network-peers",
|
||||
"reth-rpc-eth-api",
|
||||
"reth-trie-common",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10270,6 +10302,7 @@ dependencies = [
|
||||
"reth-rpc-server-types",
|
||||
"reth-storage-api",
|
||||
"reth-tasks",
|
||||
"reth-tokio-util",
|
||||
"reth-tracing",
|
||||
"reth-transaction-pool",
|
||||
"serde",
|
||||
@@ -11163,9 +11196,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revm-inspectors"
|
||||
version = "0.33.1"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c93974333e7acc4b2dc024b10def99707f7375a4d53db7a7f8351722d25673f"
|
||||
checksum = "01def7351cd9af844150b8e88980bcd11304f33ce23c3d7c25f2a8dab87c1345"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rpc-types-eth",
|
||||
@@ -12787,9 +12820,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.23.7"
|
||||
version = "0.23.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
|
||||
checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832"
|
||||
dependencies = [
|
||||
"indexmap 2.12.1",
|
||||
"toml_datetime 0.7.3",
|
||||
@@ -13303,9 +13336,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.18.1"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
|
||||
checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"js-sys",
|
||||
@@ -14282,18 +14315,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.30"
|
||||
version = "0.8.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c"
|
||||
checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.30"
|
||||
version = "0.8.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5"
|
||||
checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
74
Cargo.toml
74
Cargo.toml
@@ -153,6 +153,7 @@ members = [
|
||||
"examples/custom-node-components/",
|
||||
"examples/custom-payload-builder/",
|
||||
"examples/custom-rlpx-subprotocol",
|
||||
"examples/custom-rpc-middleware",
|
||||
"examples/custom-node",
|
||||
"examples/db-access",
|
||||
"examples/engine-api-access",
|
||||
@@ -375,11 +376,11 @@ reth-era-utils = { path = "crates/era-utils" }
|
||||
reth-errors = { path = "crates/errors" }
|
||||
reth-eth-wire = { path = "crates/net/eth-wire" }
|
||||
reth-eth-wire-types = { path = "crates/net/eth-wire-types" }
|
||||
reth-ethereum-payload-builder = { path = "crates/ethereum/payload" }
|
||||
reth-ethereum-cli = { path = "crates/ethereum/cli", default-features = false }
|
||||
reth-ethereum-consensus = { path = "crates/ethereum/consensus", default-features = false }
|
||||
reth-ethereum-engine-primitives = { path = "crates/ethereum/engine-primitives", default-features = false }
|
||||
reth-ethereum-forks = { path = "crates/ethereum/hardforks", default-features = false }
|
||||
reth-ethereum-payload-builder = { path = "crates/ethereum/payload" }
|
||||
reth-ethereum-primitives = { path = "crates/ethereum/primitives", default-features = false }
|
||||
reth-ethereum = { path = "crates/ethereum/reth" }
|
||||
reth-etl = { path = "crates/etl" }
|
||||
@@ -480,13 +481,14 @@ revm-primitives = { version = "21.0.2", default-features = false }
|
||||
revm-interpreter = { version = "31.1.0", default-features = false }
|
||||
revm-database-interface = { version = "8.0.5", default-features = false }
|
||||
op-revm = { version = "14.1.0", default-features = false }
|
||||
revm-inspectors = "0.33.1"
|
||||
revm-inspectors = "0.33.2"
|
||||
|
||||
# eth
|
||||
alloy-chains = { version = "0.2.5", default-features = false }
|
||||
alloy-dyn-abi = "1.4.1"
|
||||
alloy-eip2124 = { version = "0.2.0", default-features = false }
|
||||
alloy-evm = { version = "0.24.1", default-features = false }
|
||||
alloy-eip7928 = { version = "0.1.0" }
|
||||
alloy-evm = { version = "0.25.1", default-features = false }
|
||||
alloy-primitives = { version = "1.4.1", default-features = false, features = ["map-foldhash"] }
|
||||
alloy-rlp = { version = "0.3.10", default-features = false, features = ["core-net"] }
|
||||
alloy-sol-macro = "1.4.1"
|
||||
@@ -495,42 +497,42 @@ alloy-trie = { version = "0.9.1", default-features = false }
|
||||
|
||||
alloy-hardforks = "0.4.5"
|
||||
|
||||
alloy-consensus = { version = "1.1.2", default-features = false }
|
||||
alloy-contract = { version = "1.1.2", default-features = false }
|
||||
alloy-eips = { version = "1.1.2", default-features = false }
|
||||
alloy-genesis = { version = "1.1.2", default-features = false }
|
||||
alloy-json-rpc = { version = "1.1.2", default-features = false }
|
||||
alloy-network = { version = "1.1.2", default-features = false }
|
||||
alloy-network-primitives = { version = "1.1.2", default-features = false }
|
||||
alloy-provider = { version = "1.1.2", features = ["reqwest", "debug-api"], default-features = false }
|
||||
alloy-pubsub = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-client = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types = { version = "1.1.2", features = ["eth"], default-features = false }
|
||||
alloy-rpc-types-admin = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types-anvil = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types-beacon = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types-debug = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types-engine = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types-eth = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types-mev = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types-trace = { version = "1.1.2", default-features = false }
|
||||
alloy-rpc-types-txpool = { version = "1.1.2", default-features = false }
|
||||
alloy-serde = { version = "1.1.2", default-features = false }
|
||||
alloy-signer = { version = "1.1.2", default-features = false }
|
||||
alloy-signer-local = { version = "1.1.2", default-features = false }
|
||||
alloy-transport = { version = "1.1.2" }
|
||||
alloy-transport-http = { version = "1.1.2", features = ["reqwest-rustls-tls"], default-features = false }
|
||||
alloy-transport-ipc = { version = "1.1.2", default-features = false }
|
||||
alloy-transport-ws = { version = "1.1.2", default-features = false }
|
||||
alloy-consensus = { version = "1.1.3", default-features = false }
|
||||
alloy-contract = { version = "1.1.3", default-features = false }
|
||||
alloy-eips = { version = "1.1.3", default-features = false }
|
||||
alloy-genesis = { version = "1.1.3", default-features = false }
|
||||
alloy-json-rpc = { version = "1.1.3", default-features = false }
|
||||
alloy-network = { version = "1.1.3", default-features = false }
|
||||
alloy-network-primitives = { version = "1.1.3", default-features = false }
|
||||
alloy-provider = { version = "1.1.3", features = ["reqwest", "debug-api"], default-features = false }
|
||||
alloy-pubsub = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-client = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types = { version = "1.1.3", features = ["eth"], default-features = false }
|
||||
alloy-rpc-types-admin = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types-anvil = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types-beacon = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types-debug = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types-engine = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types-eth = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types-mev = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types-trace = { version = "1.1.3", default-features = false }
|
||||
alloy-rpc-types-txpool = { version = "1.1.3", default-features = false }
|
||||
alloy-serde = { version = "1.1.3", default-features = false }
|
||||
alloy-signer = { version = "1.1.3", default-features = false }
|
||||
alloy-signer-local = { version = "1.1.3", default-features = false }
|
||||
alloy-transport = { version = "1.1.3" }
|
||||
alloy-transport-http = { version = "1.1.3", features = ["reqwest-rustls-tls"], default-features = false }
|
||||
alloy-transport-ipc = { version = "1.1.3", default-features = false }
|
||||
alloy-transport-ws = { version = "1.1.3", default-features = false }
|
||||
|
||||
# op
|
||||
alloy-op-evm = { version = "0.24.1", default-features = false }
|
||||
alloy-op-evm = { version = "0.25.0", default-features = false }
|
||||
alloy-op-hardforks = "0.4.4"
|
||||
op-alloy-rpc-types = { version = "0.22.4", default-features = false }
|
||||
op-alloy-rpc-types-engine = { version = "0.22.4", default-features = false }
|
||||
op-alloy-network = { version = "0.22.4", default-features = false }
|
||||
op-alloy-consensus = { version = "0.22.4", default-features = false }
|
||||
op-alloy-rpc-jsonrpsee = { version = "0.22.4", default-features = false }
|
||||
op-alloy-rpc-types = { version = "0.23.1", default-features = false }
|
||||
op-alloy-rpc-types-engine = { version = "0.23.1", default-features = false }
|
||||
op-alloy-network = { version = "0.23.1", default-features = false }
|
||||
op-alloy-consensus = { version = "0.23.1", default-features = false }
|
||||
op-alloy-rpc-jsonrpsee = { version = "0.23.1", default-features = false }
|
||||
op-alloy-flz = { version = "0.13.1", default-features = false }
|
||||
|
||||
# misc
|
||||
|
||||
5
Makefile
5
Makefile
@@ -523,8 +523,3 @@ pr:
|
||||
make test
|
||||
|
||||
check-features:
|
||||
cargo hack check \
|
||||
--package reth-codecs \
|
||||
--package reth-primitives-traits \
|
||||
--package reth-primitives \
|
||||
--feature-powerset
|
||||
|
||||
@@ -506,8 +506,8 @@ async fn run_warmup_phase(
|
||||
// Build additional args with conditional --debug.startup-sync-state-idle flag
|
||||
let additional_args = args.build_additional_args("warmup", args.baseline_args.as_ref());
|
||||
|
||||
// Start reth node for warmup
|
||||
let mut node_process =
|
||||
// Start reth node for warmup (command is not stored for warmup phase)
|
||||
let (mut node_process, _warmup_command) =
|
||||
node_manager.start_node(&binary_path, warmup_ref, "warmup", &additional_args).await?;
|
||||
|
||||
// Wait for node to be ready and get its current tip
|
||||
@@ -607,8 +607,8 @@ async fn run_benchmark_workflow(
|
||||
// Build additional args with conditional --debug.startup-sync-state-idle flag
|
||||
let additional_args = args.build_additional_args(ref_type, base_args_str);
|
||||
|
||||
// Start reth node
|
||||
let mut node_process =
|
||||
// Start reth node and capture the command for reporting
|
||||
let (mut node_process, reth_command) =
|
||||
node_manager.start_node(&binary_path, git_ref, ref_type, &additional_args).await?;
|
||||
|
||||
// Wait for node to be ready and get its current tip (wherever it is)
|
||||
@@ -645,8 +645,9 @@ async fn run_benchmark_workflow(
|
||||
// Store results for comparison
|
||||
comparison_generator.add_ref_results(ref_type, &output_dir)?;
|
||||
|
||||
// Set the benchmark run timestamps
|
||||
// Set the benchmark run timestamps and reth command
|
||||
comparison_generator.set_ref_timestamps(ref_type, benchmark_start, benchmark_end)?;
|
||||
comparison_generator.set_ref_command(ref_type, reth_command)?;
|
||||
|
||||
info!("Completed {} reference benchmark", ref_type);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ pub(crate) struct ComparisonGenerator {
|
||||
feature_ref_name: String,
|
||||
baseline_results: Option<BenchmarkResults>,
|
||||
feature_results: Option<BenchmarkResults>,
|
||||
baseline_command: Option<String>,
|
||||
feature_command: Option<String>,
|
||||
}
|
||||
|
||||
/// Represents the results from a single benchmark run
|
||||
@@ -89,6 +91,7 @@ pub(crate) struct RefInfo {
|
||||
pub summary: BenchmarkSummary,
|
||||
pub start_timestamp: Option<DateTime<Utc>>,
|
||||
pub end_timestamp: Option<DateTime<Utc>>,
|
||||
pub reth_command: Option<String>,
|
||||
}
|
||||
|
||||
/// Summary of the comparison between references.
|
||||
@@ -142,6 +145,8 @@ impl ComparisonGenerator {
|
||||
feature_ref_name: args.feature_ref.clone(),
|
||||
baseline_results: None,
|
||||
feature_results: None,
|
||||
baseline_command: None,
|
||||
feature_command: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,6 +211,21 @@ impl ComparisonGenerator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the reth command for a reference
|
||||
pub(crate) fn set_ref_command(&mut self, ref_type: &str, command: String) -> Result<()> {
|
||||
match ref_type {
|
||||
"baseline" => {
|
||||
self.baseline_command = Some(command);
|
||||
}
|
||||
"feature" => {
|
||||
self.feature_command = Some(command);
|
||||
}
|
||||
_ => return Err(eyre!("Unknown reference type: {}", ref_type)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generate the final comparison report
|
||||
pub(crate) async fn generate_comparison_report(&self) -> Result<()> {
|
||||
info!("Generating comparison report...");
|
||||
@@ -230,12 +250,14 @@ impl ComparisonGenerator {
|
||||
summary: baseline.summary.clone(),
|
||||
start_timestamp: baseline.start_timestamp,
|
||||
end_timestamp: baseline.end_timestamp,
|
||||
reth_command: self.baseline_command.clone(),
|
||||
},
|
||||
feature: RefInfo {
|
||||
ref_name: feature.ref_name.clone(),
|
||||
summary: feature.summary.clone(),
|
||||
start_timestamp: feature.start_timestamp,
|
||||
end_timestamp: feature.end_timestamp,
|
||||
reth_command: self.feature_command.clone(),
|
||||
},
|
||||
comparison_summary,
|
||||
per_block_comparisons,
|
||||
@@ -599,6 +621,9 @@ impl ComparisonGenerator {
|
||||
end.format("%Y-%m-%d %H:%M:%S UTC")
|
||||
);
|
||||
}
|
||||
if let Some(ref cmd) = report.baseline.reth_command {
|
||||
println!(" Command: {}", cmd);
|
||||
}
|
||||
println!();
|
||||
|
||||
println!("Feature Summary:");
|
||||
@@ -628,6 +653,9 @@ impl ComparisonGenerator {
|
||||
end.format("%Y-%m-%d %H:%M:%S UTC")
|
||||
);
|
||||
}
|
||||
if let Some(ref cmd) = report.feature.reth_command {
|
||||
println!(" Command: {}", cmd);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,19 +240,24 @@ impl NodeManager {
|
||||
}
|
||||
|
||||
/// Start a reth node using the specified binary path and return the process handle
|
||||
/// along with the formatted reth command string for reporting.
|
||||
pub(crate) async fn start_node(
|
||||
&mut self,
|
||||
binary_path: &std::path::Path,
|
||||
_git_ref: &str,
|
||||
ref_type: &str,
|
||||
additional_args: &[String],
|
||||
) -> Result<tokio::process::Child> {
|
||||
) -> Result<(tokio::process::Child, String)> {
|
||||
// Store the binary path for later use (e.g., in unwind_to_block)
|
||||
self.binary_path = Some(binary_path.to_path_buf());
|
||||
|
||||
let binary_path_str = binary_path.to_string_lossy();
|
||||
let (reth_args, _) = self.build_reth_args(&binary_path_str, additional_args, ref_type);
|
||||
|
||||
// Format the reth command string for reporting
|
||||
let reth_command = shlex::try_join(reth_args.iter().map(|s| s.as_str()))
|
||||
.wrap_err("Failed to format reth command string")?;
|
||||
|
||||
// Log additional arguments if any
|
||||
if !self.additional_reth_args.is_empty() {
|
||||
info!("Using common additional reth arguments: {:?}", self.additional_reth_args);
|
||||
@@ -346,7 +351,7 @@ impl NodeManager {
|
||||
// Give the node a moment to start up
|
||||
sleep(Duration::from_secs(5)).await;
|
||||
|
||||
Ok(child)
|
||||
Ok((child, reth_command))
|
||||
}
|
||||
|
||||
/// Wait for the node to be ready and return its current tip
|
||||
|
||||
@@ -80,7 +80,7 @@ RUSTFLAGS="-C target-cpu=native" cargo build --profile profiling --no-default-fe
|
||||
### Run the Benchmark:
|
||||
First, start the reth node. Here is an example that runs `reth` compiled with the `profiling` profile, runs `samply`, and configures `reth` to run with metrics enabled:
|
||||
```bash
|
||||
samply record -p 3001 target/profiling/reth node --metrics localhost:9001 --authrpc.jwt-secret <jwt_file_path>
|
||||
samply record -p 3001 target/profiling/reth node --metrics localhost:9001 --authrpc.jwtsecret <jwt_file_path>
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -143,5 +143,5 @@ To reproduce the benchmark, first re-set the node to the block that the benchmar
|
||||
- **RPC Configuration**: The RPC endpoints should be accessible and configured correctly, specifically the RPC endpoint must support `eth_getBlockByNumber` and support fetching full transactions. The benchmark will make one RPC query per block as fast as possible, so ensure the RPC endpoint does not rate limit or block requests after a certain volume.
|
||||
- **Reproducibility**: Ensure that the node is at the same state before attempting to retry a benchmark. The `new-payload-fcu` command specifically will commit to the database, so the node must be rolled back using `reth stage unwind` to reproducibly retry benchmarks.
|
||||
- **Profiling tools**: If you are collecting CPU profiles, tools like [`samply`](https://github.com/mstange/samply) and [`perf`](https://perf.wiki.kernel.org/index.php/Main_Page) can be useful for analyzing node performance.
|
||||
- **Benchmark Data**: `reth-bench` additionally contains a `--benchmark.output` flag, which will output gas used benchmarks across the benchmark range in CSV format. This may be useful for further data analysis.
|
||||
- **Benchmark Data**: `reth-bench` additionally contains a `--output` flag, which will output gas used benchmarks across the benchmark range in CSV format. This may be useful for further data analysis.
|
||||
- **Platform Information**: To ensure accurate and reproducible benchmarking, document the platform details, including hardware specifications, OS version, and any other relevant information before publishing any benchmarks.
|
||||
|
||||
@@ -18,7 +18,7 @@ use reth_primitives_traits::{
|
||||
};
|
||||
use reth_storage_api::StateProviderBox;
|
||||
use reth_trie::{updates::TrieUpdatesSorted, HashedPostStateSorted, TrieInputSorted};
|
||||
use std::{collections::BTreeMap, sync::Arc, time::Instant};
|
||||
use std::{collections::BTreeMap, ops::Deref, sync::Arc, time::Instant};
|
||||
use tokio::sync::{broadcast, watch};
|
||||
|
||||
/// Size of the broadcast channel used to notify canonical state events.
|
||||
@@ -634,6 +634,8 @@ impl<N: NodePrimitives> BlockState<N> {
|
||||
/// We assume that the `Receipts` in the executed block `ExecutionOutcome`
|
||||
/// has only one element corresponding to the executed block associated to
|
||||
/// the state.
|
||||
///
|
||||
/// This clones the vector of receipts. To avoid it, use [`Self::executed_block_receipts_ref`].
|
||||
pub fn executed_block_receipts(&self) -> Vec<N::Receipt> {
|
||||
let receipts = self.receipts();
|
||||
|
||||
@@ -646,6 +648,22 @@ impl<N: NodePrimitives> BlockState<N> {
|
||||
receipts.first().cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns a slice of `Receipt` of executed block that determines the state.
|
||||
/// We assume that the `Receipts` in the executed block `ExecutionOutcome`
|
||||
/// has only one element corresponding to the executed block associated to
|
||||
/// the state.
|
||||
pub fn executed_block_receipts_ref(&self) -> &[N::Receipt] {
|
||||
let receipts = self.receipts();
|
||||
|
||||
debug_assert!(
|
||||
receipts.len() <= 1,
|
||||
"Expected at most one block's worth of receipts, found {}",
|
||||
receipts.len()
|
||||
);
|
||||
|
||||
receipts.first().map(|receipts| receipts.deref()).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns a vector of __parent__ `BlockStates`.
|
||||
///
|
||||
/// The block state order in the output vector is newest to oldest (highest to lowest):
|
||||
|
||||
@@ -8,12 +8,17 @@ use reth_db::{
|
||||
RawDupSort,
|
||||
};
|
||||
use reth_db_api::{
|
||||
table::{Decompress, DupSort, Table},
|
||||
tables, RawKey, RawTable, Receipts, TableViewer, Transactions,
|
||||
cursor::{DbCursorRO, DbDupCursorRO},
|
||||
database::Database,
|
||||
table::{Compress, Decompress, DupSort, Table},
|
||||
tables,
|
||||
transaction::DbTx,
|
||||
RawKey, RawTable, Receipts, TableViewer, Transactions,
|
||||
};
|
||||
use reth_db_common::DbTool;
|
||||
use reth_node_api::{HeaderTy, ReceiptTy, TxTy};
|
||||
use reth_node_builder::NodeTypesWithDB;
|
||||
use reth_primitives_traits::ValueWithSubKey;
|
||||
use reth_provider::{providers::ProviderNodeTypes, StaticFileProviderFactory};
|
||||
use reth_static_file_types::StaticFileSegment;
|
||||
use tracing::error;
|
||||
@@ -39,6 +44,14 @@ enum Subcommand {
|
||||
#[arg(value_parser = maybe_json_value_parser)]
|
||||
subkey: Option<String>,
|
||||
|
||||
/// Optional end key for range query (exclusive upper bound)
|
||||
#[arg(value_parser = maybe_json_value_parser)]
|
||||
end_key: Option<String>,
|
||||
|
||||
/// Optional end subkey for range query (exclusive upper bound)
|
||||
#[arg(value_parser = maybe_json_value_parser)]
|
||||
end_subkey: Option<String>,
|
||||
|
||||
/// Output bytes instead of human-readable decoded value
|
||||
#[arg(long)]
|
||||
raw: bool,
|
||||
@@ -61,8 +74,8 @@ impl Command {
|
||||
/// Execute `db get` command
|
||||
pub fn execute<N: ProviderNodeTypes>(self, tool: &DbTool<N>) -> eyre::Result<()> {
|
||||
match self.subcommand {
|
||||
Subcommand::Mdbx { table, key, subkey, raw } => {
|
||||
table.view(&GetValueViewer { tool, key, subkey, raw })?
|
||||
Subcommand::Mdbx { table, key, subkey, end_key, end_subkey, raw } => {
|
||||
table.view(&GetValueViewer { tool, key, subkey, end_key, end_subkey, raw })?
|
||||
}
|
||||
Subcommand::StaticFile { segment, key, raw } => {
|
||||
let (key, mask): (u64, _) = match segment {
|
||||
@@ -154,6 +167,8 @@ struct GetValueViewer<'a, N: NodeTypesWithDB> {
|
||||
tool: &'a DbTool<N>,
|
||||
key: String,
|
||||
subkey: Option<String>,
|
||||
end_key: Option<String>,
|
||||
end_subkey: Option<String>,
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
@@ -163,53 +178,158 @@ impl<N: ProviderNodeTypes> TableViewer<()> for GetValueViewer<'_, N> {
|
||||
fn view<T: Table>(&self) -> Result<(), Self::Error> {
|
||||
let key = table_key::<T>(&self.key)?;
|
||||
|
||||
let content = if self.raw {
|
||||
self.tool
|
||||
.get::<RawTable<T>>(RawKey::from(key))?
|
||||
.map(|content| hex::encode_prefixed(content.raw_value()))
|
||||
} else {
|
||||
self.tool.get::<T>(key)?.as_ref().map(serde_json::to_string_pretty).transpose()?
|
||||
};
|
||||
// A non-dupsort table cannot have subkeys. The `subkey` arg becomes the `end_key`. First we
|
||||
// check that `end_key` and `end_subkey` weren't previously given, as that wouldn't be
|
||||
// valid.
|
||||
if self.end_key.is_some() || self.end_subkey.is_some() {
|
||||
return Err(eyre::eyre!("Only END_KEY can be given for non-DUPSORT tables"));
|
||||
}
|
||||
|
||||
match content {
|
||||
Some(content) => {
|
||||
println!("{content}");
|
||||
}
|
||||
None => {
|
||||
error!(target: "reth::cli", "No content for the given table key.");
|
||||
}
|
||||
};
|
||||
let end_key = self.subkey.clone();
|
||||
|
||||
// Check if we're doing a range query
|
||||
if let Some(ref end_key_str) = end_key {
|
||||
let end_key = table_key::<T>(end_key_str)?;
|
||||
|
||||
// Use walk_range to iterate over the range
|
||||
self.tool.provider_factory.db_ref().view(|tx| {
|
||||
let mut cursor = tx.cursor_read::<T>()?;
|
||||
let walker = cursor.walk_range(key..end_key)?;
|
||||
|
||||
for result in walker {
|
||||
let (k, v) = result?;
|
||||
let json_val = if self.raw {
|
||||
let raw_key = RawKey::from(k);
|
||||
serde_json::json!({
|
||||
"key": hex::encode_prefixed(raw_key.raw_key()),
|
||||
"val": hex::encode_prefixed(v.compress().as_ref()),
|
||||
})
|
||||
} else {
|
||||
serde_json::json!({
|
||||
"key": &k,
|
||||
"val": &v,
|
||||
})
|
||||
};
|
||||
|
||||
println!("{}", serde_json::to_string_pretty(&json_val)?);
|
||||
}
|
||||
|
||||
Ok::<_, eyre::Report>(())
|
||||
})??;
|
||||
} else {
|
||||
// Single key lookup
|
||||
let content = if self.raw {
|
||||
self.tool
|
||||
.get::<RawTable<T>>(RawKey::from(key))?
|
||||
.map(|content| hex::encode_prefixed(content.raw_value()))
|
||||
} else {
|
||||
self.tool.get::<T>(key)?.as_ref().map(serde_json::to_string_pretty).transpose()?
|
||||
};
|
||||
|
||||
match content {
|
||||
Some(content) => {
|
||||
println!("{content}");
|
||||
}
|
||||
None => {
|
||||
error!(target: "reth::cli", "No content for the given table key.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn view_dupsort<T: DupSort>(&self) -> Result<(), Self::Error> {
|
||||
fn view_dupsort<T: DupSort>(&self) -> Result<(), Self::Error>
|
||||
where
|
||||
T::Value: reth_primitives_traits::ValueWithSubKey<SubKey = T::SubKey>,
|
||||
{
|
||||
// get a key for given table
|
||||
let key = table_key::<T>(&self.key)?;
|
||||
|
||||
// process dupsort table
|
||||
let subkey = table_subkey::<T>(self.subkey.as_deref())?;
|
||||
|
||||
let content = if self.raw {
|
||||
self.tool
|
||||
.get_dup::<RawDupSort<T>>(RawKey::from(key), RawKey::from(subkey))?
|
||||
.map(|content| hex::encode_prefixed(content.raw_value()))
|
||||
} else {
|
||||
self.tool
|
||||
.get_dup::<T>(key, subkey)?
|
||||
// Check if we're doing a range query
|
||||
if let Some(ref end_key_str) = self.end_key {
|
||||
let end_key = table_key::<T>(end_key_str)?;
|
||||
let start_subkey = table_subkey::<T>(Some(
|
||||
self.subkey.as_ref().expect("must have been given if end_key is given").as_str(),
|
||||
))?;
|
||||
let end_subkey_parsed = self
|
||||
.end_subkey
|
||||
.as_ref()
|
||||
.map(serde_json::to_string_pretty)
|
||||
.transpose()?
|
||||
};
|
||||
.map(|s| table_subkey::<T>(Some(s.as_str())))
|
||||
.transpose()?;
|
||||
|
||||
match content {
|
||||
Some(content) => {
|
||||
println!("{content}");
|
||||
}
|
||||
None => {
|
||||
error!(target: "reth::cli", "No content for the given table subkey.");
|
||||
}
|
||||
};
|
||||
self.tool.provider_factory.db_ref().view(|tx| {
|
||||
let mut cursor = tx.cursor_dup_read::<T>()?;
|
||||
|
||||
// Seek to the starting key. If there is actually a key at the starting key then
|
||||
// seek to the subkey within it.
|
||||
if let Some((decoded_key, _)) = cursor.seek(key.clone())? &&
|
||||
decoded_key == key
|
||||
{
|
||||
cursor.seek_by_key_subkey(key.clone(), start_subkey.clone())?;
|
||||
}
|
||||
|
||||
// Get the current position to start iteration
|
||||
let mut current = cursor.current()?;
|
||||
|
||||
while let Some((decoded_key, decoded_value)) = current {
|
||||
// Extract the subkey using the ValueWithSubKey trait
|
||||
let decoded_subkey = decoded_value.get_subkey();
|
||||
|
||||
// Check if we've reached the end (exclusive)
|
||||
if (&decoded_key, Some(&decoded_subkey)) >=
|
||||
(&end_key, end_subkey_parsed.as_ref())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Output the entry with both key and subkey
|
||||
let json_val = if self.raw {
|
||||
let raw_key = RawKey::from(decoded_key.clone());
|
||||
serde_json::json!({
|
||||
"key": hex::encode_prefixed(raw_key.raw_key()),
|
||||
"val": hex::encode_prefixed(decoded_value.compress().as_ref()),
|
||||
})
|
||||
} else {
|
||||
serde_json::json!({
|
||||
"key": &decoded_key,
|
||||
"val": &decoded_value,
|
||||
})
|
||||
};
|
||||
|
||||
println!("{}", serde_json::to_string_pretty(&json_val)?);
|
||||
|
||||
// Move to next entry
|
||||
current = cursor.next()?;
|
||||
}
|
||||
|
||||
Ok::<_, eyre::Report>(())
|
||||
})??;
|
||||
} else {
|
||||
// Single key/subkey lookup
|
||||
let subkey = table_subkey::<T>(self.subkey.as_deref())?;
|
||||
|
||||
let content = if self.raw {
|
||||
self.tool
|
||||
.get_dup::<RawDupSort<T>>(RawKey::from(key), RawKey::from(subkey))?
|
||||
.map(|content| hex::encode_prefixed(content.raw_value()))
|
||||
} else {
|
||||
self.tool
|
||||
.get_dup::<T>(key, subkey)?
|
||||
.as_ref()
|
||||
.map(serde_json::to_string_pretty)
|
||||
.transpose()?
|
||||
};
|
||||
|
||||
match content {
|
||||
Some(content) => {
|
||||
println!("{content}");
|
||||
}
|
||||
None => {
|
||||
error!(target: "reth::cli", "No content for the given table subkey.");
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,9 @@ impl Command {
|
||||
let mut settings @ StorageSettings {
|
||||
receipts_in_static_files: _,
|
||||
transaction_senders_in_static_files: _,
|
||||
storages_history_in_rocksdb: _,
|
||||
transaction_hash_numbers_in_rocksdb: _,
|
||||
account_history_in_rocksdb: _,
|
||||
} = settings.unwrap_or_else(StorageSettings::legacy);
|
||||
|
||||
// Update the setting based on the key
|
||||
|
||||
@@ -110,7 +110,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateC
|
||||
static_file_provider.commit()?;
|
||||
} else if last_block_number > 0 && last_block_number < header.number() {
|
||||
return Err(eyre::eyre!(
|
||||
"Data directory should be empty when calling init-state with --without-evm-history."
|
||||
"Data directory should be empty when calling init-state with --without-evm."
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,8 +531,12 @@ impl PruneConfig {
|
||||
self.segments.receipts.is_some() || !self.segments.receipts_log_filter.is_empty()
|
||||
}
|
||||
|
||||
/// Merges another `PruneConfig` into this one, taking values from the other config if and only
|
||||
/// if the corresponding value in this config is not set.
|
||||
/// Merges values from `other` into `self`.
|
||||
/// - `Option<PruneMode>` fields: set from `other` only if `self` is `None`.
|
||||
/// - `block_interval`: set from `other` only if `self.block_interval ==
|
||||
/// DEFAULT_BLOCK_INTERVAL`.
|
||||
/// - `merkle_changesets`: always set from `other`.
|
||||
/// - `receipts_log_filter`: set from `other` only if `self` is empty and `other` is non-empty.
|
||||
pub fn merge(&mut self, other: Self) {
|
||||
let Self {
|
||||
block_interval,
|
||||
@@ -561,7 +565,7 @@ impl PruneConfig {
|
||||
self.segments.account_history = self.segments.account_history.or(account_history);
|
||||
self.segments.storage_history = self.segments.storage_history.or(storage_history);
|
||||
self.segments.bodies_history = self.segments.bodies_history.or(bodies_history);
|
||||
// Merkle changesets is not optional, so we just replace it if provided
|
||||
// Merkle changesets is not optional; always take the value from `other`
|
||||
self.segments.merkle_changesets = merkle_changesets;
|
||||
|
||||
if self.segments.receipts_log_filter.0.is_empty() && !receipts_log_filter.0.is_empty() {
|
||||
|
||||
@@ -327,7 +327,7 @@ pub fn validate_against_parent_eip1559_base_fee<ChainSpec: EthChainSpec + Ethere
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates the timestamp against the parent to make sure it is in the past.
|
||||
/// Validates that the block timestamp is greater than the parent block timestamp.
|
||||
#[inline]
|
||||
pub fn validate_against_parent_timestamp<H: BlockHeader>(
|
||||
header: &H,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::BlockProvider;
|
||||
use alloy_provider::{Network, Provider, ProviderBuilder};
|
||||
use alloy_provider::{ConnectionConfig, Network, Provider, ProviderBuilder, WebSocketConfig};
|
||||
use alloy_transport::TransportResult;
|
||||
use futures::{Stream, StreamExt};
|
||||
use reth_node_api::Block;
|
||||
@@ -25,7 +25,19 @@ impl<N: Network, PrimitiveBlock> RpcBlockProvider<N, PrimitiveBlock> {
|
||||
convert: impl Fn(N::BlockResponse) -> PrimitiveBlock + Send + Sync + 'static,
|
||||
) -> eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
provider: Arc::new(ProviderBuilder::default().connect(rpc_url).await?),
|
||||
provider: Arc::new(
|
||||
ProviderBuilder::default()
|
||||
.connect_with_config(
|
||||
rpc_url,
|
||||
ConnectionConfig::default().with_max_retries(u32::MAX).with_ws_config(
|
||||
WebSocketConfig::default()
|
||||
// allow larger messages/frames for big blocks
|
||||
.max_frame_size(Some(128 * 1024 * 1024))
|
||||
.max_message_size(Some(128 * 1024 * 1024)),
|
||||
),
|
||||
)
|
||||
.await?,
|
||||
),
|
||||
url: rpc_url.to_string(),
|
||||
convert: Arc::new(convert),
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
//! Engine tree configuration.
|
||||
|
||||
use alloy_eips::merge::EPOCH_SLOTS;
|
||||
|
||||
/// Triggers persistence when the number of canonical blocks in memory exceeds this threshold.
|
||||
pub const DEFAULT_PERSISTENCE_THRESHOLD: u64 = 2;
|
||||
|
||||
@@ -40,7 +42,7 @@ pub const DEFAULT_RESERVED_CPU_CORES: usize = 1;
|
||||
/// Default maximum concurrency for prewarm task.
|
||||
pub const DEFAULT_PREWARM_MAX_CONCURRENCY: usize = 16;
|
||||
|
||||
const DEFAULT_BLOCK_BUFFER_LIMIT: u32 = 256;
|
||||
const DEFAULT_BLOCK_BUFFER_LIMIT: u32 = EPOCH_SLOTS as u32 * 2;
|
||||
const DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH: u32 = 256;
|
||||
const DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE: usize = 4;
|
||||
const DEFAULT_CROSS_BLOCK_CACHE_SIZE: u64 = 4 * 1024 * 1024 * 1024;
|
||||
@@ -89,6 +91,8 @@ pub struct TreeConfig {
|
||||
/// Whether to always compare trie updates from the state root task to the trie updates from
|
||||
/// the regular state root calculation.
|
||||
always_compare_trie_updates: bool,
|
||||
/// Whether to disable state cache.
|
||||
disable_state_cache: bool,
|
||||
/// Whether to disable parallel prewarming.
|
||||
disable_prewarming: bool,
|
||||
/// Whether to disable the parallel sparse trie state root algorithm.
|
||||
@@ -143,6 +147,7 @@ impl Default for TreeConfig {
|
||||
max_execute_block_batch_size: DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE,
|
||||
legacy_state_root: false,
|
||||
always_compare_trie_updates: false,
|
||||
disable_state_cache: false,
|
||||
disable_prewarming: false,
|
||||
disable_parallel_sparse_trie: false,
|
||||
state_provider_metrics: false,
|
||||
@@ -173,6 +178,7 @@ impl TreeConfig {
|
||||
max_execute_block_batch_size: usize,
|
||||
legacy_state_root: bool,
|
||||
always_compare_trie_updates: bool,
|
||||
disable_state_cache: bool,
|
||||
disable_prewarming: bool,
|
||||
disable_parallel_sparse_trie: bool,
|
||||
state_provider_metrics: bool,
|
||||
@@ -197,6 +203,7 @@ impl TreeConfig {
|
||||
max_execute_block_batch_size,
|
||||
legacy_state_root,
|
||||
always_compare_trie_updates,
|
||||
disable_state_cache,
|
||||
disable_prewarming,
|
||||
disable_parallel_sparse_trie,
|
||||
state_provider_metrics,
|
||||
@@ -271,7 +278,12 @@ impl TreeConfig {
|
||||
self.disable_parallel_sparse_trie
|
||||
}
|
||||
|
||||
/// Returns whether or not parallel prewarming should be used.
|
||||
/// Returns whether or not state cache is disabled.
|
||||
pub const fn disable_state_cache(&self) -> bool {
|
||||
self.disable_state_cache
|
||||
}
|
||||
|
||||
/// Returns whether or not parallel prewarming is disabled.
|
||||
pub const fn disable_prewarming(&self) -> bool {
|
||||
self.disable_prewarming
|
||||
}
|
||||
@@ -363,6 +375,12 @@ impl TreeConfig {
|
||||
self
|
||||
}
|
||||
|
||||
/// Setter for whether to disable state cache.
|
||||
pub const fn without_state_cache(mut self, disable_state_cache: bool) -> Self {
|
||||
self.disable_state_cache = disable_state_cache;
|
||||
self
|
||||
}
|
||||
|
||||
/// Setter for whether to disable parallel prewarming.
|
||||
pub const fn without_prewarming(mut self, disable_prewarming: bool) -> Self {
|
||||
self.disable_prewarming = disable_prewarming;
|
||||
|
||||
@@ -39,6 +39,7 @@ reth-trie.workspace = true
|
||||
alloy-evm.workspace = true
|
||||
alloy-consensus.workspace = true
|
||||
alloy-eips.workspace = true
|
||||
alloy-eip7928.workspace = true
|
||||
alloy-primitives.workspace = true
|
||||
alloy-rlp.workspace = true
|
||||
alloy-rpc-types-engine.workspace = true
|
||||
|
||||
@@ -229,9 +229,15 @@ fn bench_state_root(c: &mut Criterion) {
|
||||
black_box({
|
||||
let mut handle = payload_processor.spawn(
|
||||
Default::default(),
|
||||
core::iter::empty::<
|
||||
Result<Recovered<TransactionSigned>, core::convert::Infallible>,
|
||||
>(),
|
||||
(
|
||||
core::iter::empty::<
|
||||
Result<
|
||||
Recovered<TransactionSigned>,
|
||||
core::convert::Infallible,
|
||||
>,
|
||||
>(),
|
||||
std::convert::identity,
|
||||
),
|
||||
StateProviderBuilder::new(provider.clone(), genesis_hash, None),
|
||||
OverlayStateProviderFactory::new(provider),
|
||||
&TreeConfig::default(),
|
||||
|
||||
@@ -146,17 +146,26 @@ impl<S: StateProvider> StateProvider for CachedStateProvider<S> {
|
||||
storage_key: StorageKey,
|
||||
) -> ProviderResult<Option<StorageValue>> {
|
||||
match self.caches.get_storage(&account, &storage_key) {
|
||||
SlotStatus::NotCached => {
|
||||
self.metrics.storage_cache_misses.increment(1);
|
||||
(SlotStatus::NotCached, maybe_cache) => {
|
||||
let final_res = self.state_provider.storage(account, storage_key)?;
|
||||
self.caches.insert_storage(account, storage_key, final_res);
|
||||
let account_cache = maybe_cache.unwrap_or_default();
|
||||
account_cache.insert_storage(storage_key, final_res);
|
||||
// we always need to insert the value to update the weights.
|
||||
// Note: there exists a race when the storage cache did not exist yet and two
|
||||
// consumers looking up the a storage value for this account for the first time,
|
||||
// however we can assume that this will only happen for the very first (mostlikely
|
||||
// the same) value, and don't expect that this will accidentally
|
||||
// replace an account storage cache with additional values.
|
||||
self.caches.insert_storage_cache(account, account_cache);
|
||||
|
||||
self.metrics.storage_cache_misses.increment(1);
|
||||
Ok(final_res)
|
||||
}
|
||||
SlotStatus::Empty => {
|
||||
(SlotStatus::Empty, _) => {
|
||||
self.metrics.storage_cache_hits.increment(1);
|
||||
Ok(None)
|
||||
}
|
||||
SlotStatus::Value(value) => {
|
||||
(SlotStatus::Value(value), _) => {
|
||||
self.metrics.storage_cache_hits.increment(1);
|
||||
Ok(Some(value))
|
||||
}
|
||||
@@ -311,18 +320,28 @@ pub(crate) struct ExecutionCache {
|
||||
impl ExecutionCache {
|
||||
/// Get storage value from hierarchical cache.
|
||||
///
|
||||
/// Returns a `SlotStatus` indicating whether:
|
||||
/// - `NotCached`: The account's storage cache doesn't exist
|
||||
/// - `Empty`: The slot exists in the account's cache but is empty
|
||||
/// - `Value`: The slot exists and has a specific value
|
||||
pub(crate) fn get_storage(&self, address: &Address, key: &StorageKey) -> SlotStatus {
|
||||
/// Returns a tuple of:
|
||||
/// - `SlotStatus` indicating whether:
|
||||
/// - `NotCached`: The account's storage cache doesn't exist
|
||||
/// - `Empty`: The slot exists in the account's cache but is empty
|
||||
/// - `Value`: The slot exists and has a specific value
|
||||
/// - `Option<Arc<AccountStorageCache>>`: The account's storage cache if it exists
|
||||
pub(crate) fn get_storage(
|
||||
&self,
|
||||
address: &Address,
|
||||
key: &StorageKey,
|
||||
) -> (SlotStatus, Option<Arc<AccountStorageCache>>) {
|
||||
match self.storage_cache.get(address) {
|
||||
None => SlotStatus::NotCached,
|
||||
Some(account_cache) => account_cache.get_storage(key),
|
||||
None => (SlotStatus::NotCached, None),
|
||||
Some(account_cache) => {
|
||||
let status = account_cache.get_storage(key);
|
||||
(status, Some(account_cache))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert storage value into hierarchical cache
|
||||
#[cfg(test)]
|
||||
pub(crate) fn insert_storage(
|
||||
&self,
|
||||
address: Address,
|
||||
@@ -351,6 +370,15 @@ impl ExecutionCache {
|
||||
self.storage_cache.insert(address, account_cache);
|
||||
}
|
||||
|
||||
/// Inserts the [`AccountStorageCache`].
|
||||
pub(crate) fn insert_storage_cache(
|
||||
&self,
|
||||
address: Address,
|
||||
storage_cache: Arc<AccountStorageCache>,
|
||||
) {
|
||||
self.storage_cache.insert(address, storage_cache);
|
||||
}
|
||||
|
||||
/// Invalidate storage for specific account
|
||||
pub(crate) fn invalidate_account_storage(&self, address: &Address) {
|
||||
self.storage_cache.invalidate(address);
|
||||
@@ -800,7 +828,7 @@ mod tests {
|
||||
caches.insert_storage(address, storage_key, Some(storage_value));
|
||||
|
||||
// check that the storage returns the cached value
|
||||
let slot_status = caches.get_storage(&address, &storage_key);
|
||||
let (slot_status, _) = caches.get_storage(&address, &storage_key);
|
||||
assert_eq!(slot_status, SlotStatus::Value(storage_value));
|
||||
}
|
||||
|
||||
@@ -814,7 +842,7 @@ mod tests {
|
||||
let caches = ExecutionCacheBuilder::default().build_caches(1000);
|
||||
|
||||
// check that the storage is not cached
|
||||
let slot_status = caches.get_storage(&address, &storage_key);
|
||||
let (slot_status, _) = caches.get_storage(&address, &storage_key);
|
||||
assert_eq!(slot_status, SlotStatus::NotCached);
|
||||
}
|
||||
|
||||
@@ -830,7 +858,7 @@ mod tests {
|
||||
caches.insert_storage(address, storage_key, None);
|
||||
|
||||
// check that the storage is empty
|
||||
let slot_status = caches.get_storage(&address, &storage_key);
|
||||
let (slot_status, _) = caches.get_storage(&address, &storage_key);
|
||||
assert_eq!(slot_status, SlotStatus::Empty);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ const NANOS_PER_SEC: u32 = 1_000_000_000;
|
||||
|
||||
/// An atomic version of [`Duration`], using an [`AtomicU64`] to store the total nanoseconds in the
|
||||
/// duration.
|
||||
#[derive(Default)]
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct AtomicDuration {
|
||||
/// The nanoseconds part of the duration
|
||||
///
|
||||
@@ -59,7 +59,8 @@ impl AtomicDuration {
|
||||
}
|
||||
|
||||
/// A wrapper of a state provider and latency metrics.
|
||||
pub(crate) struct InstrumentedStateProvider<S> {
|
||||
#[derive(Debug)]
|
||||
pub struct InstrumentedStateProvider<S> {
|
||||
/// The state provider
|
||||
state_provider: S,
|
||||
|
||||
@@ -80,11 +81,12 @@ impl<S> InstrumentedStateProvider<S>
|
||||
where
|
||||
S: StateProvider,
|
||||
{
|
||||
/// Creates a new [`InstrumentedStateProvider`] from a state provider
|
||||
pub(crate) fn from_state_provider(state_provider: S) -> Self {
|
||||
/// Creates a new [`InstrumentedStateProvider`] from a state provider with the provided label
|
||||
/// for metrics.
|
||||
pub fn from_state_provider(state_provider: S, source: &'static str) -> Self {
|
||||
Self {
|
||||
state_provider,
|
||||
metrics: StateProviderMetrics::default(),
|
||||
metrics: StateProviderMetrics::new_with_labels(&[("source", source)]),
|
||||
total_storage_fetch_latency: AtomicDuration::zero(),
|
||||
total_code_fetch_latency: AtomicDuration::zero(),
|
||||
total_account_fetch_latency: AtomicDuration::zero(),
|
||||
@@ -134,6 +136,12 @@ impl<S> InstrumentedStateProvider<S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Drop for InstrumentedStateProvider<S> {
|
||||
fn drop(&mut self) {
|
||||
self.record_total_latency();
|
||||
}
|
||||
}
|
||||
|
||||
/// Metrics for the instrumented state provider
|
||||
#[derive(Metrics, Clone)]
|
||||
#[metrics(scope = "sync.state_provider")]
|
||||
|
||||
@@ -63,7 +63,7 @@ impl EngineApiMetrics {
|
||||
pub(crate) fn execute_metered<E, DB>(
|
||||
&self,
|
||||
executor: E,
|
||||
transactions: impl Iterator<Item = Result<impl ExecutableTx<E>, BlockExecutionError>>,
|
||||
mut transactions: impl Iterator<Item = Result<impl ExecutableTx<E>, BlockExecutionError>>,
|
||||
state_hook: Box<dyn OnStateHook>,
|
||||
) -> Result<(BlockExecutionOutput<E::Receipt>, Vec<Address>), BlockExecutionError>
|
||||
where
|
||||
@@ -79,27 +79,42 @@ impl EngineApiMetrics {
|
||||
let mut executor = executor.with_state_hook(Some(Box::new(wrapper)));
|
||||
|
||||
let f = || {
|
||||
let start = Instant::now();
|
||||
debug_span!(target: "engine::tree", "pre execution")
|
||||
.entered()
|
||||
.in_scope(|| executor.apply_pre_execution_changes())?;
|
||||
self.executor.pre_execution_histogram.record(start.elapsed());
|
||||
|
||||
let exec_span = debug_span!(target: "engine::tree", "execution").entered();
|
||||
for tx in transactions {
|
||||
loop {
|
||||
let start = Instant::now();
|
||||
let Some(tx) = transactions.next() else { break };
|
||||
self.executor.transaction_wait_histogram.record(start.elapsed());
|
||||
|
||||
let tx = tx?;
|
||||
senders.push(*tx.signer());
|
||||
|
||||
let span =
|
||||
debug_span!(target: "engine::tree", "execute tx", tx_hash=?tx.tx().tx_hash());
|
||||
let enter = span.entered();
|
||||
trace!(target: "engine::tree", "Executing transaction");
|
||||
senders.push(*tx.signer());
|
||||
let start = Instant::now();
|
||||
let gas_used = executor.execute_transaction(tx)?;
|
||||
self.executor.transaction_execution_histogram.record(start.elapsed());
|
||||
|
||||
// record the tx gas used
|
||||
enter.record("gas_used", gas_used);
|
||||
}
|
||||
drop(exec_span);
|
||||
debug_span!(target: "engine::tree", "finish")
|
||||
|
||||
let start = Instant::now();
|
||||
let result = debug_span!(target: "engine::tree", "finish")
|
||||
.entered()
|
||||
.in_scope(|| executor.finish())
|
||||
.map(|(evm, result)| (evm.into_db(), result))
|
||||
.map(|(evm, result)| (evm.into_db(), result));
|
||||
self.executor.post_execution_histogram.record(start.elapsed());
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
// Use metered to execute and track timing/gas metrics
|
||||
|
||||
@@ -54,7 +54,7 @@ use tracing::*;
|
||||
mod block_buffer;
|
||||
mod cached_state;
|
||||
pub mod error;
|
||||
mod instrumented_state;
|
||||
pub mod instrumented_state;
|
||||
mod invalid_headers;
|
||||
mod metrics;
|
||||
mod payload_processor;
|
||||
@@ -1901,6 +1901,16 @@ where
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns true if the given hash is part of the last received sync target fork choice update.
|
||||
///
|
||||
/// See [`ForkchoiceStateTracker::sync_target_state`]
|
||||
fn is_any_sync_target(&self, block_hash: B256) -> bool {
|
||||
if let Some(target) = self.state.forkchoice_state_tracker.sync_target_state() {
|
||||
return target.contains(block_hash)
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks if the given `check` hash points to an invalid header, inserting the given `head`
|
||||
/// block into the invalid header cache if the `check` hash has a known invalid ancestor.
|
||||
///
|
||||
@@ -2040,9 +2050,12 @@ where
|
||||
match self.insert_block(child) {
|
||||
Ok(res) => {
|
||||
debug!(target: "engine::tree", child =?child_num_hash, ?res, "connected buffered block");
|
||||
if self.is_sync_target_head(child_num_hash.hash) &&
|
||||
if self.is_any_sync_target(child_num_hash.hash) &&
|
||||
matches!(res, InsertPayloadOk::Inserted(BlockStatus::Valid))
|
||||
{
|
||||
debug!(target: "engine::tree", child =?child_num_hash, "connected sync target block");
|
||||
// we just inserted a block that we know is part of the canonical chain, so
|
||||
// we can make it canonical
|
||||
self.make_canonical(child_num_hash.hash)?;
|
||||
}
|
||||
}
|
||||
@@ -2348,11 +2361,15 @@ where
|
||||
// try to append the block
|
||||
match self.insert_block(block) {
|
||||
Ok(InsertPayloadOk::Inserted(BlockStatus::Valid)) => {
|
||||
if self.is_sync_target_head(block_num_hash.hash) {
|
||||
trace!(target: "engine::tree", "appended downloaded sync target block");
|
||||
// check if we just inserted a block that's part of sync targets,
|
||||
// i.e. head, safe, or finalized
|
||||
if let Some(sync_target) = self.state.forkchoice_state_tracker.sync_target_state() &&
|
||||
sync_target.contains(block_num_hash.hash)
|
||||
{
|
||||
debug!(target: "engine::tree", ?sync_target, "appended downloaded sync target block");
|
||||
|
||||
// we just inserted the current sync target block, we can try to make it
|
||||
// canonical
|
||||
// we just inserted a block that we know is part of the canonical chain, so we
|
||||
// can make it canonical
|
||||
return Ok(Some(TreeEvent::TreeAction(TreeAction::MakeCanonical {
|
||||
sync_target_head: block_num_hash.hash,
|
||||
})))
|
||||
|
||||
@@ -21,6 +21,7 @@ use executor::WorkloadExecutor;
|
||||
use multiproof::{SparseTrieUpdate, *};
|
||||
use parking_lot::RwLock;
|
||||
use prewarm::PrewarmMetrics;
|
||||
use rayon::iter::{ParallelBridge, ParallelIterator};
|
||||
use reth_engine_primitives::ExecutableTxIterator;
|
||||
use reth_evm::{
|
||||
execute::{ExecutableTxFor, WithTxEnv},
|
||||
@@ -40,6 +41,7 @@ use reth_trie_sparse::{
|
||||
};
|
||||
use reth_trie_sparse_parallel::{ParallelSparseTrie, ParallelismThresholds};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
sync::{
|
||||
atomic::AtomicBool,
|
||||
mpsc::{self, channel},
|
||||
@@ -104,6 +106,8 @@ where
|
||||
cross_block_cache_size: u64,
|
||||
/// Whether transactions should not be executed on prewarming task.
|
||||
disable_transaction_prewarming: bool,
|
||||
/// Whether state cache should be disable
|
||||
disable_state_cache: bool,
|
||||
/// Determines how to configure the evm for execution.
|
||||
evm_config: Evm,
|
||||
/// Whether precompile cache should be disabled.
|
||||
@@ -147,6 +151,7 @@ where
|
||||
cross_block_cache_size: config.cross_block_cache_size(),
|
||||
disable_transaction_prewarming: config.disable_prewarming(),
|
||||
evm_config,
|
||||
disable_state_cache: config.disable_state_cache(),
|
||||
precompile_cache_disabled: config.precompile_cache_disabled(),
|
||||
precompile_cache_map,
|
||||
sparse_state_trie: Arc::default(),
|
||||
@@ -312,21 +317,50 @@ where
|
||||
mpsc::Receiver<Result<WithTxEnv<TxEnvFor<Evm>, I::Tx>, I::Error>>,
|
||||
usize,
|
||||
) {
|
||||
let (transactions, convert) = transactions.into();
|
||||
let transactions = transactions.into_iter();
|
||||
// Get the transaction count for prewarming task
|
||||
// Use upper bound if available (more accurate), otherwise use lower bound
|
||||
let (lower, upper) = transactions.size_hint();
|
||||
let transaction_count_hint = upper.unwrap_or(lower);
|
||||
|
||||
// Spawn a task that iterates through all transactions in parallel and sends them to the
|
||||
// main task.
|
||||
let (tx, rx) = mpsc::channel();
|
||||
self.executor.spawn_blocking(move || {
|
||||
transactions.enumerate().par_bridge().for_each_with(tx, |sender, (idx, tx)| {
|
||||
let tx = convert(tx);
|
||||
let tx = tx.map(|tx| WithTxEnv { tx_env: tx.to_tx_env(), tx: Arc::new(tx) });
|
||||
let _ = sender.send((idx, tx));
|
||||
});
|
||||
});
|
||||
|
||||
// Spawn a task that processes out-of-order transactions from the task above and sends them
|
||||
// to prewarming and execution tasks.
|
||||
let (prewarm_tx, prewarm_rx) = mpsc::channel();
|
||||
let (execute_tx, execute_rx) = mpsc::channel();
|
||||
self.executor.spawn_blocking(move || {
|
||||
for tx in transactions {
|
||||
let tx = tx.map(|tx| WithTxEnv { tx_env: tx.to_tx_env(), tx: Arc::new(tx) });
|
||||
let mut next_for_execution = 0;
|
||||
let mut queue = BTreeMap::new();
|
||||
while let Ok((idx, tx)) = rx.recv() {
|
||||
// only send Ok(_) variants to prewarming task
|
||||
if let Ok(tx) = &tx {
|
||||
let _ = prewarm_tx.send(tx.clone());
|
||||
}
|
||||
let _ = execute_tx.send(tx);
|
||||
|
||||
if next_for_execution == idx {
|
||||
let _ = execute_tx.send(tx);
|
||||
next_for_execution += 1;
|
||||
|
||||
while let Some(entry) = queue.first_entry() &&
|
||||
*entry.key() == next_for_execution
|
||||
{
|
||||
let _ = execute_tx.send(entry.remove());
|
||||
next_for_execution += 1;
|
||||
}
|
||||
} else {
|
||||
queue.insert(idx, tx);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -351,9 +385,15 @@ where
|
||||
transactions = mpsc::channel().1;
|
||||
}
|
||||
|
||||
let saved_cache = self.cache_for(env.parent_hash);
|
||||
let cache = saved_cache.cache().clone();
|
||||
let cache_metrics = saved_cache.metrics().clone();
|
||||
let (saved_cache, cache, cache_metrics) = if self.disable_state_cache {
|
||||
(None, None, None)
|
||||
} else {
|
||||
let saved_cache = self.cache_for(env.parent_hash);
|
||||
let cache = saved_cache.cache().clone();
|
||||
let cache_metrics = saved_cache.metrics().clone();
|
||||
(Some(saved_cache), Some(cache), Some(cache_metrics))
|
||||
};
|
||||
|
||||
// configure prewarming
|
||||
let prewarm_ctx = PrewarmContext {
|
||||
env,
|
||||
@@ -565,12 +605,12 @@ impl<Tx, Err> PayloadHandle<Tx, Err> {
|
||||
}
|
||||
|
||||
/// Returns a clone of the caches used by prewarming
|
||||
pub(super) fn caches(&self) -> StateExecutionCache {
|
||||
pub(super) fn caches(&self) -> Option<StateExecutionCache> {
|
||||
self.prewarm_handle.cache.clone()
|
||||
}
|
||||
|
||||
/// Returns a clone of the cache metrics used by prewarming
|
||||
pub(super) fn cache_metrics(&self) -> CachedStateMetrics {
|
||||
pub(super) fn cache_metrics(&self) -> Option<CachedStateMetrics> {
|
||||
self.prewarm_handle.cache_metrics.clone()
|
||||
}
|
||||
|
||||
@@ -600,9 +640,9 @@ impl<Tx, Err> PayloadHandle<Tx, Err> {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CacheTaskHandle {
|
||||
/// The shared cache the task operates with.
|
||||
cache: StateExecutionCache,
|
||||
cache: Option<StateExecutionCache>,
|
||||
/// Metrics for the caches
|
||||
cache_metrics: CachedStateMetrics,
|
||||
cache_metrics: Option<CachedStateMetrics>,
|
||||
/// Channel to the spawned prewarm task if any
|
||||
to_prewarm_task: Option<std::sync::mpsc::Sender<PrewarmTaskEvent>>,
|
||||
}
|
||||
@@ -1017,13 +1057,19 @@ mod tests {
|
||||
|
||||
let provider_factory = BlockchainProvider::new(factory).unwrap();
|
||||
|
||||
let mut handle = payload_processor.spawn(
|
||||
Default::default(),
|
||||
core::iter::empty::<Result<Recovered<TransactionSigned>, core::convert::Infallible>>(),
|
||||
StateProviderBuilder::new(provider_factory.clone(), genesis_hash, None),
|
||||
OverlayStateProviderFactory::new(provider_factory),
|
||||
&TreeConfig::default(),
|
||||
);
|
||||
let mut handle =
|
||||
payload_processor.spawn(
|
||||
Default::default(),
|
||||
(
|
||||
core::iter::empty::<
|
||||
Result<Recovered<TransactionSigned>, core::convert::Infallible>,
|
||||
>(),
|
||||
std::convert::identity,
|
||||
),
|
||||
StateProviderBuilder::new(provider_factory.clone(), genesis_hash, None),
|
||||
OverlayStateProviderFactory::new(provider_factory),
|
||||
&TreeConfig::default(),
|
||||
);
|
||||
|
||||
let mut state_hook = handle.state_hook();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@ use metrics::{Counter, Gauge, Histogram};
|
||||
use reth_evm::{execute::ExecutableTxFor, ConfigureEvm, Evm, EvmFor, SpecFor};
|
||||
use reth_metrics::Metrics;
|
||||
use reth_primitives_traits::NodePrimitives;
|
||||
use reth_provider::{BlockReader, StateProviderFactory, StateReader};
|
||||
use reth_provider::{BlockReader, StateProviderBox, StateProviderFactory, StateReader};
|
||||
use reth_revm::{database::StateProviderDatabase, db::BundleState, state::EvmState};
|
||||
use reth_trie::MultiProofTargets;
|
||||
use std::{
|
||||
@@ -255,31 +255,35 @@ where
|
||||
self;
|
||||
let hash = env.hash;
|
||||
|
||||
debug!(target: "engine::caching", parent_hash=?hash, "Updating execution cache");
|
||||
// Perform all cache operations atomically under the lock
|
||||
execution_cache.update_with_guard(|cached| {
|
||||
// consumes the `SavedCache` held by the prewarming task, which releases its usage guard
|
||||
let (caches, cache_metrics) = saved_cache.split();
|
||||
let new_cache = SavedCache::new(hash, caches, cache_metrics);
|
||||
if let Some(saved_cache) = saved_cache {
|
||||
debug!(target: "engine::caching", parent_hash=?hash, "Updating execution cache");
|
||||
// Perform all cache operations atomically under the lock
|
||||
execution_cache.update_with_guard(|cached| {
|
||||
// consumes the `SavedCache` held by the prewarming task, which releases its usage
|
||||
// guard
|
||||
let (caches, cache_metrics) = saved_cache.split();
|
||||
let new_cache = SavedCache::new(hash, caches, cache_metrics);
|
||||
|
||||
// Insert state into cache while holding the lock
|
||||
if new_cache.cache().insert_state(&state).is_err() {
|
||||
// Clear the cache on error to prevent having a polluted cache
|
||||
*cached = None;
|
||||
debug!(target: "engine::caching", "cleared execution cache on update error");
|
||||
return;
|
||||
}
|
||||
// Insert state into cache while holding the lock
|
||||
if new_cache.cache().insert_state(&state).is_err() {
|
||||
// Clear the cache on error to prevent having a polluted cache
|
||||
*cached = None;
|
||||
debug!(target: "engine::caching", "cleared execution cache on update error");
|
||||
return;
|
||||
}
|
||||
|
||||
new_cache.update_metrics();
|
||||
new_cache.update_metrics();
|
||||
|
||||
// Replace the shared cache with the new one; the previous cache (if any) is dropped.
|
||||
*cached = Some(new_cache);
|
||||
});
|
||||
// Replace the shared cache with the new one; the previous cache (if any) is
|
||||
// dropped.
|
||||
*cached = Some(new_cache);
|
||||
});
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
debug!(target: "engine::caching", parent_hash=?hash, elapsed=?elapsed, "Updated execution cache");
|
||||
let elapsed = start.elapsed();
|
||||
debug!(target: "engine::caching", parent_hash=?hash, elapsed=?elapsed, "Updated execution cache");
|
||||
|
||||
metrics.cache_saving_duration.set(elapsed.as_secs_f64());
|
||||
metrics.cache_saving_duration.set(elapsed.as_secs_f64());
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes the task.
|
||||
@@ -356,7 +360,7 @@ where
|
||||
{
|
||||
pub(super) env: ExecutionEnv<Evm>,
|
||||
pub(super) evm_config: Evm,
|
||||
pub(super) saved_cache: SavedCache,
|
||||
pub(super) saved_cache: Option<SavedCache>,
|
||||
/// Provider to obtain the state
|
||||
pub(super) provider: StateProviderBuilder<N, P>,
|
||||
pub(super) metrics: PrewarmMetrics,
|
||||
@@ -400,10 +404,13 @@ where
|
||||
};
|
||||
|
||||
// Use the caches to create a new provider with caching
|
||||
let caches = saved_cache.cache().clone();
|
||||
let cache_metrics = saved_cache.metrics().clone();
|
||||
let state_provider =
|
||||
CachedStateProvider::new_with_caches(state_provider, caches, cache_metrics);
|
||||
let state_provider: StateProviderBox = if let Some(saved_cache) = saved_cache {
|
||||
let caches = saved_cache.cache().clone();
|
||||
let cache_metrics = saved_cache.metrics().clone();
|
||||
Box::new(CachedStateProvider::new_with_caches(state_provider, caches, cache_metrics))
|
||||
} else {
|
||||
state_provider
|
||||
};
|
||||
|
||||
let state_provider = StateProviderDatabase::new(state_provider);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::tree::{
|
||||
StateProviderDatabase, TreeConfig,
|
||||
};
|
||||
use alloy_consensus::transaction::Either;
|
||||
use alloy_eip7928::BlockAccessList;
|
||||
use alloy_eips::{eip1898::BlockWithParent, NumHash};
|
||||
use alloy_evm::Evm;
|
||||
use alloy_primitives::B256;
|
||||
@@ -213,16 +214,31 @@ where
|
||||
Evm: ConfigureEngineEvm<T::ExecutionData, Primitives = N>,
|
||||
{
|
||||
match input {
|
||||
BlockOrPayload::Payload(payload) => Ok(Either::Left(
|
||||
self.evm_config
|
||||
BlockOrPayload::Payload(payload) => {
|
||||
let (iter, convert) = self
|
||||
.evm_config
|
||||
.tx_iterator_for_payload(payload)
|
||||
.map_err(NewPayloadError::other)?
|
||||
.map(|res| res.map(Either::Left).map_err(NewPayloadError::other)),
|
||||
)),
|
||||
.into();
|
||||
|
||||
let iter = Either::Left(iter.into_iter().map(Either::Left));
|
||||
let convert = move |tx| {
|
||||
let Either::Left(tx) = tx else { unreachable!() };
|
||||
convert(tx).map(Either::Left).map_err(Either::Left)
|
||||
};
|
||||
|
||||
// Box the closure to satisfy the `Fn` bound both here and in the branch below
|
||||
Ok((iter, Box::new(convert) as Box<dyn Fn(_) -> _ + Send + Sync + 'static>))
|
||||
}
|
||||
BlockOrPayload::Block(block) => {
|
||||
Ok(Either::Right(block.body().clone_transactions().into_iter().map(|tx| {
|
||||
Ok(Either::Right(tx.try_into_recovered().map_err(NewPayloadError::other)?))
|
||||
})))
|
||||
let iter =
|
||||
Either::Right(block.body().clone_transactions().into_iter().map(Either::Right));
|
||||
let convert = move |tx: Either<_, N::SignedTx>| {
|
||||
let Either::Right(tx) = tx else { unreachable!() };
|
||||
tx.try_into_recovered().map(Either::Right).map_err(Either::Right)
|
||||
};
|
||||
|
||||
Ok((iter, Box::new(convert)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -353,7 +369,7 @@ where
|
||||
)
|
||||
.into())
|
||||
};
|
||||
let state_provider = ensure_ok!(provider_builder.build());
|
||||
let mut state_provider = ensure_ok!(provider_builder.build());
|
||||
drop(_enter);
|
||||
|
||||
// fetch parent block
|
||||
@@ -396,18 +412,19 @@ where
|
||||
|
||||
// Use cached state provider before executing, used in execution after prewarming threads
|
||||
// complete
|
||||
let state_provider = CachedStateProvider::new_with_caches(
|
||||
state_provider,
|
||||
handle.caches(),
|
||||
handle.cache_metrics(),
|
||||
);
|
||||
if let Some((caches, cache_metrics)) = handle.caches().zip(handle.cache_metrics()) {
|
||||
state_provider = Box::new(CachedStateProvider::new_with_caches(
|
||||
state_provider,
|
||||
caches,
|
||||
cache_metrics,
|
||||
));
|
||||
};
|
||||
|
||||
// Execute the block and handle any execution errors
|
||||
let (output, senders) = match if self.config.state_provider_metrics() {
|
||||
let state_provider = InstrumentedStateProvider::from_state_provider(&state_provider);
|
||||
let result = self.execute_block(&state_provider, env, &input, &mut handle);
|
||||
state_provider.record_total_latency();
|
||||
result
|
||||
let state_provider =
|
||||
InstrumentedStateProvider::from_state_provider(&state_provider, "engine");
|
||||
self.execute_block(&state_provider, env, &input, &mut handle)
|
||||
} else {
|
||||
self.execute_block(&state_provider, env, &input, &mut handle)
|
||||
} {
|
||||
@@ -1228,4 +1245,10 @@ impl<T: PayloadTypes> BlockOrPayload<T> {
|
||||
Self::Block(_) => "block",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the block access list if available.
|
||||
pub const fn block_access_list(&self) -> Option<Result<BlockAccessList, alloy_rlp::Error>> {
|
||||
// TODO decode and return `BlockAccessList`
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ where
|
||||
|
||||
/// Extracts block headers and bodies from `iter` and appends them using `writer` and `provider`.
|
||||
///
|
||||
/// Adds on to `total_difficulty` and collects hash to height using `hash_collector`.
|
||||
/// Collects hash to height using `hash_collector`.
|
||||
///
|
||||
/// Skips all blocks below the [`start_bound`] of `block_numbers` and stops when reaching past the
|
||||
/// [`end_bound`] or the end of the file.
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
//! Simple decoding and decompressing tests
|
||||
//! for mainnet era files
|
||||
|
||||
use reth_era::{
|
||||
common::file_ops::{StreamReader, StreamWriter},
|
||||
era::file::{EraReader, EraWriter},
|
||||
};
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::{EraTestDownloader, HOODI};
|
||||
|
||||
// Helper function to test decompression and decoding for a specific era file
|
||||
async fn test_era_file_decompression_and_decoding(
|
||||
downloader: &EraTestDownloader,
|
||||
filename: &str,
|
||||
network: &str,
|
||||
) -> eyre::Result<()> {
|
||||
println!("\nTesting file: {filename}");
|
||||
let file = downloader.open_era_file(filename, network).await?;
|
||||
|
||||
// Handle genesis era separately
|
||||
if file.group.is_genesis() {
|
||||
// Genesis has no blocks
|
||||
assert_eq!(file.group.blocks.len(), 0, "Genesis should have no blocks");
|
||||
assert!(file.group.slot_index.is_none(), "Genesis should not have block slot index");
|
||||
|
||||
// Test genesis state decompression
|
||||
let state_data = file.group.era_state.decompress()?;
|
||||
assert!(!state_data.is_empty(), "Genesis state should decompress to non-empty data");
|
||||
|
||||
// Verify state slot index
|
||||
assert_eq!(
|
||||
file.group.state_slot_index.slot_count(),
|
||||
1,
|
||||
"Genesis state index should have count of 1"
|
||||
);
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
{
|
||||
let mut writer = EraWriter::new(&mut buffer);
|
||||
writer.write_file(&file)?;
|
||||
}
|
||||
|
||||
let reader = EraReader::new(Cursor::new(&buffer));
|
||||
let read_back_file = reader.read(file.id.network_name.clone())?;
|
||||
|
||||
assert_eq!(
|
||||
file.group.era_state.decompress()?,
|
||||
read_back_file.group.era_state.decompress()?,
|
||||
"Genesis state data should be identical"
|
||||
);
|
||||
|
||||
println!("Genesis era verified successfully");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Non-genesis era - test beacon blocks
|
||||
println!(
|
||||
" Non-genesis era with {} beacon blocks, starting at slot {}",
|
||||
file.group.blocks.len(),
|
||||
file.group.starting_slot()
|
||||
);
|
||||
|
||||
// Test beacon block decompression across different positions
|
||||
let test_block_indices = [
|
||||
0, // First block
|
||||
file.group.blocks.len() / 2, // Middle block
|
||||
file.group.blocks.len() - 1, // Last block
|
||||
];
|
||||
|
||||
for &block_idx in &test_block_indices {
|
||||
let block = &file.group.blocks[block_idx];
|
||||
let slot = file.group.starting_slot() + block_idx as u64;
|
||||
|
||||
println!(
|
||||
"\n Testing beacon block at slot {}, compressed size: {} bytes",
|
||||
slot,
|
||||
block.data.len()
|
||||
);
|
||||
|
||||
// Test beacon block decompression
|
||||
let block_data = block.decompress()?;
|
||||
assert!(
|
||||
!block_data.is_empty(),
|
||||
"Beacon block at slot {slot} decompression should produce non-empty data"
|
||||
);
|
||||
}
|
||||
|
||||
// Test era state decompression
|
||||
let state_data = file.group.era_state.decompress()?;
|
||||
assert!(!state_data.is_empty(), "Era state decompression should produce non-empty data");
|
||||
println!(" Era state decompressed: {} bytes", state_data.len());
|
||||
|
||||
// Verify slot indices
|
||||
if let Some(ref block_slot_index) = file.group.slot_index {
|
||||
println!(
|
||||
" Block slot index: starting_slot={}, count={}",
|
||||
block_slot_index.starting_slot,
|
||||
block_slot_index.slot_count()
|
||||
);
|
||||
|
||||
// Check for empty slots
|
||||
let empty_slots: Vec<usize> = (0..block_slot_index.slot_count())
|
||||
.filter(|&i| !block_slot_index.has_data_at_slot(i))
|
||||
.collect();
|
||||
|
||||
if !empty_slots.is_empty() {
|
||||
println!(
|
||||
" Found {} empty slots (first few): {:?}",
|
||||
empty_slots.len(),
|
||||
&empty_slots[..empty_slots.len().min(5)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Test round-trip serialization
|
||||
let mut buffer = Vec::new();
|
||||
{
|
||||
let mut writer = EraWriter::new(&mut buffer);
|
||||
writer.write_file(&file)?;
|
||||
}
|
||||
|
||||
// Read back from buffer
|
||||
let reader = EraReader::new(Cursor::new(&buffer));
|
||||
let read_back_file = reader.read(file.id.network_name.clone())?;
|
||||
|
||||
// Verify basic properties are preserved
|
||||
assert_eq!(file.id.network_name, read_back_file.id.network_name);
|
||||
assert_eq!(file.id.start_slot, read_back_file.id.start_slot);
|
||||
assert_eq!(file.id.slot_count, read_back_file.id.slot_count);
|
||||
assert_eq!(file.group.blocks.len(), read_back_file.group.blocks.len());
|
||||
|
||||
// Test data preservation for beacon blocks
|
||||
for &idx in &test_block_indices {
|
||||
let original_block = &file.group.blocks[idx];
|
||||
let read_back_block = &read_back_file.group.blocks[idx];
|
||||
let slot = file.group.starting_slot() + idx as u64;
|
||||
|
||||
// Test that decompressed data is identical
|
||||
assert_eq!(
|
||||
original_block.decompress()?,
|
||||
read_back_block.decompress()?,
|
||||
"Beacon block data should be identical for slot {slot}"
|
||||
);
|
||||
}
|
||||
|
||||
// Test state data preservation
|
||||
assert_eq!(
|
||||
file.group.era_state.decompress()?,
|
||||
read_back_file.group.era_state.decompress()?,
|
||||
"Era state data should be identical"
|
||||
);
|
||||
|
||||
// Test slot indices preservation
|
||||
if let (Some(original_index), Some(read_index)) =
|
||||
(&file.group.slot_index, &read_back_file.group.slot_index)
|
||||
{
|
||||
assert_eq!(
|
||||
original_index.starting_slot, read_index.starting_slot,
|
||||
"Block slot index starting slot should match"
|
||||
);
|
||||
assert_eq!(
|
||||
original_index.offsets, read_index.offsets,
|
||||
"Block slot index offsets should match"
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
file.group.state_slot_index.starting_slot,
|
||||
read_back_file.group.state_slot_index.starting_slot,
|
||||
"State slot index starting slot should match"
|
||||
);
|
||||
assert_eq!(
|
||||
file.group.state_slot_index.offsets, read_back_file.group.state_slot_index.offsets,
|
||||
"State slot index offsets should match"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case::test_case("hoodi-00000-212f13fc.era"; "era_dd_hoodi_0")]
|
||||
#[test_case::test_case("hoodi-00021-857e418b.era"; "era_dd_hoodi_21")]
|
||||
#[test_case::test_case("hoodi-00175-202aaa6d.era"; "era_dd_hoodi_175")]
|
||||
#[test_case::test_case("hoodi-00201-0d521fc8.era"; "era_dd_hoodi_201")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore = "download intensive"]
|
||||
async fn test_hoodi_era1_file_decompression_and_decoding(filename: &str) -> eyre::Result<()> {
|
||||
let downloader = EraTestDownloader::new().await?;
|
||||
test_era_file_decompression_and_decoding(&downloader, filename, HOODI).await
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
mod dd;
|
||||
mod genesis;
|
||||
mod roundtrip;
|
||||
|
||||
228
crates/era/tests/it/era/roundtrip.rs
Normal file
228
crates/era/tests/it/era/roundtrip.rs
Normal file
@@ -0,0 +1,228 @@
|
||||
//! Roundtrip tests for `.era` files.
|
||||
//!
|
||||
//! These tests verify the full lifecycle of era files by:
|
||||
//! - Reading files from their original source
|
||||
//! - Decompressing their contents
|
||||
//! - Re-compressing the data
|
||||
//! - Writing the data back to a new file
|
||||
//! - Confirming that all original data is preserved throughout the process
|
||||
//!
|
||||
//!
|
||||
//! Only a couple of era files are downloaded from `https://mainnet.era.nimbus.team/` for mainnet
|
||||
//! and `https://hoodi.era.nimbus.team/` for hoodi to keep the tests efficient.
|
||||
|
||||
use reth_era::{
|
||||
common::file_ops::{EraFileFormat, StreamReader, StreamWriter},
|
||||
era::{
|
||||
file::{EraFile, EraReader, EraWriter},
|
||||
types::{
|
||||
consensus::{CompressedBeaconState, CompressedSignedBeaconBlock},
|
||||
group::{EraGroup, EraId},
|
||||
},
|
||||
},
|
||||
};
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::{EraTestDownloader, HOODI, MAINNET};
|
||||
|
||||
// Helper function to test roundtrip compression/encoding for a specific file
|
||||
async fn test_era_file_roundtrip(
|
||||
downloader: &EraTestDownloader,
|
||||
filename: &str,
|
||||
network: &str,
|
||||
) -> eyre::Result<()> {
|
||||
println!("\nTesting roundtrip for file: {filename}");
|
||||
|
||||
let original_file = downloader.open_era_file(filename, network).await?;
|
||||
|
||||
if original_file.group.is_genesis() {
|
||||
println!("Genesis era detected, using special handling");
|
||||
assert_eq!(original_file.group.blocks.len(), 0, "Genesis should have no blocks");
|
||||
assert!(
|
||||
original_file.group.slot_index.is_none(),
|
||||
"Genesis should not have block slot index"
|
||||
);
|
||||
|
||||
let state_data = original_file.group.era_state.decompress()?;
|
||||
println!(" Genesis state decompressed: {} bytes", state_data.len());
|
||||
|
||||
// File roundtrip test
|
||||
let mut buffer = Vec::new();
|
||||
{
|
||||
let mut writer = EraWriter::new(&mut buffer);
|
||||
writer.write_file(&original_file)?;
|
||||
}
|
||||
|
||||
let reader = EraReader::new(Cursor::new(&buffer));
|
||||
let roundtrip_file = reader.read(network.to_string())?;
|
||||
|
||||
assert_eq!(
|
||||
original_file.group.era_state.decompress()?,
|
||||
roundtrip_file.group.era_state.decompress()?,
|
||||
"Genesis state data should be identical after roundtrip"
|
||||
);
|
||||
|
||||
println!("Genesis era verified successfully");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// non genesis start
|
||||
let original_state_data = original_file.group.era_state.decompress()?;
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
{
|
||||
let mut writer = EraWriter::new(&mut buffer);
|
||||
writer.write_file(&original_file)?;
|
||||
}
|
||||
|
||||
// Read back from buffer
|
||||
let reader = EraReader::new(Cursor::new(&buffer));
|
||||
let roundtrip_file = reader.read(network.to_string())?;
|
||||
|
||||
assert_eq!(
|
||||
original_file.id.network_name, roundtrip_file.id.network_name,
|
||||
"Network name should match after roundtrip"
|
||||
);
|
||||
assert_eq!(
|
||||
original_file.id.start_slot, roundtrip_file.id.start_slot,
|
||||
"Start slot should match after roundtrip"
|
||||
);
|
||||
assert_eq!(
|
||||
original_file.group.blocks.len(),
|
||||
roundtrip_file.group.blocks.len(),
|
||||
"Block count should match after roundtrip"
|
||||
);
|
||||
|
||||
// Select a few blocks to test
|
||||
let test_block_indices = [
|
||||
0, // First block
|
||||
original_file.group.blocks.len() / 2, // Middle block
|
||||
original_file.group.blocks.len() - 1, // Last block
|
||||
];
|
||||
|
||||
// Test individual beacon blocks
|
||||
for &block_idx in &test_block_indices {
|
||||
let original_block = &original_file.group.blocks[block_idx];
|
||||
let roundtrip_block = &roundtrip_file.group.blocks[block_idx];
|
||||
|
||||
let original_block_data = original_block.decompress()?;
|
||||
let roundtrip_block_data = roundtrip_block.decompress()?;
|
||||
|
||||
// Verify file roundtrip preserves data
|
||||
assert_eq!(
|
||||
original_block_data, roundtrip_block_data,
|
||||
"Block {block_idx} data should be identical after file roundtrip"
|
||||
);
|
||||
|
||||
// Verify compression roundtrip
|
||||
let recompressed_block = CompressedSignedBeaconBlock::from_ssz(&original_block_data)?;
|
||||
let recompressed_block_data = recompressed_block.decompress()?;
|
||||
|
||||
assert_eq!(
|
||||
original_block_data, recompressed_block_data,
|
||||
"Block {block_idx} should be identical after re-compression cycle"
|
||||
);
|
||||
}
|
||||
|
||||
let roundtrip_state_data = roundtrip_file.group.era_state.decompress()?;
|
||||
|
||||
assert_eq!(
|
||||
original_state_data, roundtrip_state_data,
|
||||
"Era state data should be identical after roundtrip"
|
||||
);
|
||||
|
||||
let recompressed_state = CompressedBeaconState::from_ssz(&roundtrip_state_data)?;
|
||||
let recompressed_state_data = recompressed_state.decompress()?;
|
||||
|
||||
assert_eq!(
|
||||
original_state_data, recompressed_state_data,
|
||||
"Era state data should be identical after re-compression cycle"
|
||||
);
|
||||
|
||||
let recompressed_blocks: Vec<CompressedSignedBeaconBlock> = roundtrip_file
|
||||
.group
|
||||
.blocks
|
||||
.iter()
|
||||
.map(|block| {
|
||||
let data = block.decompress()?;
|
||||
CompressedSignedBeaconBlock::from_ssz(&data)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let new_group = if let Some(ref block_index) = roundtrip_file.group.slot_index {
|
||||
EraGroup::with_block_index(
|
||||
recompressed_blocks,
|
||||
recompressed_state,
|
||||
block_index.clone(),
|
||||
roundtrip_file.group.state_slot_index.clone(),
|
||||
)
|
||||
} else {
|
||||
EraGroup::new(
|
||||
recompressed_blocks,
|
||||
recompressed_state,
|
||||
roundtrip_file.group.state_slot_index,
|
||||
)
|
||||
};
|
||||
|
||||
let (start_slot, slot_count) = new_group.slot_range();
|
||||
let new_file = EraFile::new(new_group, EraId::new(network, start_slot, slot_count));
|
||||
|
||||
let mut reconstructed_buffer = Vec::new();
|
||||
{
|
||||
let mut writer = EraWriter::new(&mut reconstructed_buffer);
|
||||
writer.write_file(&new_file)?;
|
||||
}
|
||||
|
||||
let reader = EraReader::new(Cursor::new(&reconstructed_buffer));
|
||||
let reconstructed_file = reader.read(network.to_string())?;
|
||||
|
||||
assert_eq!(
|
||||
original_file.group.blocks.len(),
|
||||
reconstructed_file.group.blocks.len(),
|
||||
"Block count should match after full reconstruction"
|
||||
);
|
||||
|
||||
// Verify all reconstructed blocks match
|
||||
for (idx, (orig, recon)) in
|
||||
original_file.group.blocks.iter().zip(reconstructed_file.group.blocks.iter()).enumerate()
|
||||
{
|
||||
assert_eq!(
|
||||
orig.decompress()?,
|
||||
recon.decompress()?,
|
||||
"Block {idx} should match after full reconstruction"
|
||||
);
|
||||
}
|
||||
|
||||
// Verify reconstructed state matches
|
||||
assert_eq!(
|
||||
original_state_data,
|
||||
reconstructed_file.group.era_state.decompress()?,
|
||||
"State should match after full reconstruction"
|
||||
);
|
||||
|
||||
println!("File {filename} roundtrip successful");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case::test_case("mainnet-00000-4b363db9.era"; "era_roundtrip_mainnet_0")]
|
||||
#[test_case::test_case("mainnet-00178-0d0a5290.era"; "era_roundtrip_mainnet_178")]
|
||||
#[test_case::test_case("mainnet-01070-7616e3e2.era"; "era_roundtrip_mainnet_1070")]
|
||||
#[test_case::test_case("mainnet-01267-e3ddc749.era"; "era_roundtrip_mainnet_1267")]
|
||||
#[test_case::test_case("mainnet-01592-d4dc8b98.era"; "era_roundtrip_mainnet_1592")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore = "download intensive"]
|
||||
async fn test_roundtrip_compression_encoding_mainnet(filename: &str) -> eyre::Result<()> {
|
||||
let downloader = EraTestDownloader::new().await?;
|
||||
test_era_file_roundtrip(&downloader, filename, MAINNET).await
|
||||
}
|
||||
|
||||
#[test_case::test_case("hoodi-00000-212f13fc.era"; "era_roundtrip_hoodi_0")]
|
||||
#[test_case::test_case("hoodi-00021-857e418b.era"; "era_roundtrip_hoodi_21")]
|
||||
#[test_case::test_case("hoodi-00175-202aaa6d.era"; "era_roundtrip_hoodi_175")]
|
||||
#[test_case::test_case("hoodi-00201-0d521fc8.era"; "era_roundtrip_hoodi_201")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore = "download intensive"]
|
||||
async fn test_roundtrip_compression_encoding_hoodi(filename: &str) -> eyre::Result<()> {
|
||||
let downloader = EraTestDownloader::new().await?;
|
||||
test_era_file_roundtrip(&downloader, filename, HOODI).await
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
//! Simple decoding and decompressing tests
|
||||
//! for mainnet era1 files
|
||||
|
||||
use alloy_consensus::{BlockBody, Header};
|
||||
use alloy_primitives::U256;
|
||||
use reth_era::{
|
||||
common::file_ops::{StreamReader, StreamWriter},
|
||||
e2s::types::IndexEntry,
|
||||
era1::{
|
||||
file::{Era1Reader, Era1Writer},
|
||||
types::execution::CompressedBody,
|
||||
},
|
||||
};
|
||||
use reth_ethereum_primitives::TransactionSigned;
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::{EraTestDownloader, MAINNET};
|
||||
|
||||
// Helper function to test decompression and decoding for a specific era1 file
|
||||
async fn test_file_decompression(
|
||||
downloader: &EraTestDownloader,
|
||||
filename: &str,
|
||||
) -> eyre::Result<()> {
|
||||
println!("\nTesting file: {filename}");
|
||||
let file = downloader.open_era1_file(filename, MAINNET).await?;
|
||||
|
||||
// Test block decompression across different positions in the file
|
||||
let test_block_indices = [
|
||||
0, // First block
|
||||
file.group.blocks.len() / 2, // Middle block
|
||||
file.group.blocks.len() - 1, // Last block
|
||||
];
|
||||
|
||||
for &block_idx in &test_block_indices {
|
||||
let block = &file.group.blocks[block_idx];
|
||||
let block_number = file.group.block_index.starting_number() + block_idx as u64;
|
||||
|
||||
println!(
|
||||
"\n Testing block {}, compressed body size: {} bytes",
|
||||
block_number,
|
||||
block.body.data.len()
|
||||
);
|
||||
|
||||
// Test header decompression and decoding
|
||||
let header_data = block.header.decompress()?;
|
||||
assert!(
|
||||
!header_data.is_empty(),
|
||||
"Block {block_number} header decompression should produce non-empty data"
|
||||
);
|
||||
|
||||
let header = block.header.decode_header()?;
|
||||
assert_eq!(header.number, block_number, "Decoded header should have correct block number");
|
||||
println!("Header decompression and decoding successful");
|
||||
|
||||
// Test body decompression
|
||||
let body_data = block.body.decompress()?;
|
||||
assert!(
|
||||
!body_data.is_empty(),
|
||||
"Block {block_number} body decompression should produce non-empty data"
|
||||
);
|
||||
println!("Body decompression successful ({} bytes)", body_data.len());
|
||||
|
||||
let decoded_body: BlockBody<TransactionSigned> =
|
||||
CompressedBody::decode_body_from_decompressed::<TransactionSigned, Header>(&body_data)
|
||||
.expect("Failed to decode body");
|
||||
|
||||
println!(
|
||||
"Body decoding successful: {} transactions, {} ommers, withdrawals: {}",
|
||||
decoded_body.transactions.len(),
|
||||
decoded_body.ommers.len(),
|
||||
decoded_body.withdrawals.is_some()
|
||||
);
|
||||
|
||||
// Test receipts decompression
|
||||
let receipts_data = block.receipts.decompress()?;
|
||||
assert!(
|
||||
!receipts_data.is_empty(),
|
||||
"Block {block_number} receipts decompression should produce non-empty data"
|
||||
);
|
||||
println!("Receipts decompression successful ({} bytes)", receipts_data.len());
|
||||
|
||||
assert!(
|
||||
block.total_difficulty.value > U256::ZERO,
|
||||
"Block {block_number} should have non-zero difficulty"
|
||||
);
|
||||
println!("Total difficulty verified: {}", block.total_difficulty.value);
|
||||
}
|
||||
|
||||
// Test round-trip serialization
|
||||
println!("\n Testing data preservation roundtrip...");
|
||||
let mut buffer = Vec::new();
|
||||
{
|
||||
let mut writer = Era1Writer::new(&mut buffer);
|
||||
writer.write_file(&file)?;
|
||||
}
|
||||
|
||||
// Read back from buffer
|
||||
let reader = Era1Reader::new(Cursor::new(&buffer));
|
||||
let read_back_file = reader.read(file.id.network_name.clone())?;
|
||||
|
||||
// Verify basic properties are preserved
|
||||
assert_eq!(file.id.network_name, read_back_file.id.network_name);
|
||||
assert_eq!(file.id.start_block, read_back_file.id.start_block);
|
||||
assert_eq!(file.group.blocks.len(), read_back_file.group.blocks.len());
|
||||
assert_eq!(file.group.accumulator.root, read_back_file.group.accumulator.root);
|
||||
|
||||
// Test data preservation for some blocks
|
||||
for &idx in &test_block_indices {
|
||||
let original_block = &file.group.blocks[idx];
|
||||
let read_back_block = &read_back_file.group.blocks[idx];
|
||||
let block_number = file.group.block_index.starting_number() + idx as u64;
|
||||
|
||||
println!("Block {block_number} details:");
|
||||
println!(" Header size: {} bytes", original_block.header.data.len());
|
||||
println!(" Body size: {} bytes", original_block.body.data.len());
|
||||
println!(" Receipts size: {} bytes", original_block.receipts.data.len());
|
||||
|
||||
// Test that decompressed data is identical
|
||||
assert_eq!(
|
||||
original_block.header.decompress()?,
|
||||
read_back_block.header.decompress()?,
|
||||
"Header data should be identical for block {block_number}"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
original_block.body.decompress()?,
|
||||
read_back_block.body.decompress()?,
|
||||
"Body data should be identical for block {block_number}"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
original_block.receipts.decompress()?,
|
||||
read_back_block.receipts.decompress()?,
|
||||
"Receipts data should be identical for block {block_number}"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
original_block.total_difficulty.value, read_back_block.total_difficulty.value,
|
||||
"Total difficulty should be identical for block {block_number}"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case::test_case("mainnet-00000-5ec1ffb8.era1"; "era_dd_mainnet_0")]
|
||||
#[test_case::test_case("mainnet-00003-d8b8a40b.era1"; "era_dd_mainnet_3")]
|
||||
#[test_case::test_case("mainnet-00151-e322efe1.era1"; "era_dd_mainnet_151")]
|
||||
#[test_case::test_case("mainnet-00293-0d6c5812.era1"; "era_dd_mainnet_293")]
|
||||
#[test_case::test_case("mainnet-00443-ea71b6f9.era1"; "era_dd_mainnet_443")]
|
||||
#[test_case::test_case("mainnet-01367-d7efc68f.era1"; "era_dd_mainnet_1367")]
|
||||
#[test_case::test_case("mainnet-01610-99fdde4b.era1"; "era_dd_mainnet_1610")]
|
||||
#[test_case::test_case("mainnet-01895-3f81607c.era1"; "era_dd_mainnet_1895")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore = "download intensive"]
|
||||
async fn test_mainnet_era1_file_decompression_and_decoding(filename: &str) -> eyre::Result<()> {
|
||||
let downloader = EraTestDownloader::new().await?;
|
||||
test_file_decompression(&downloader, filename).await
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
mod dd;
|
||||
mod genesis;
|
||||
mod roundtrip;
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
//! - Re-encoding and recompressing the data
|
||||
//! - Writing the data back to a new file
|
||||
//! - Confirming that all original data is preserved throughout the process
|
||||
//!
|
||||
//! Only a couple of era1 files are downloaded from <https://era.ithaca.xyz/era1/> for mainnet
|
||||
//! and <https://era.ithaca.xyz/sepolia-era1/> for sepolia to keep the tests efficient.
|
||||
|
||||
use alloy_consensus::{BlockBody, BlockHeader, Header, ReceiptEnvelope};
|
||||
use reth_era::{
|
||||
@@ -27,7 +30,7 @@ use std::io::Cursor;
|
||||
use crate::{EraTestDownloader, MAINNET, SEPOLIA};
|
||||
|
||||
// Helper function to test roundtrip compression/encoding for a specific file
|
||||
async fn test_file_roundtrip(
|
||||
async fn test_era1_file_roundtrip(
|
||||
downloader: &EraTestDownloader,
|
||||
filename: &str,
|
||||
network: &str,
|
||||
@@ -252,27 +255,27 @@ async fn test_file_roundtrip(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case::test_case("mainnet-00000-5ec1ffb8.era1"; "era_mainnet_0")]
|
||||
#[test_case::test_case("mainnet-00151-e322efe1.era1"; "era_mainnet_151")]
|
||||
#[test_case::test_case("mainnet-01367-d7efc68f.era1"; "era_mainnet_1367")]
|
||||
#[test_case::test_case("mainnet-01895-3f81607c.era1"; "era_mainnet_1895")]
|
||||
#[test_case::test_case("mainnet-00000-5ec1ffb8.era1"; "era1_roundtrip_mainnet_0")]
|
||||
#[test_case::test_case("mainnet-00151-e322efe1.era1"; "era1_roundtrip_mainnet_151")]
|
||||
#[test_case::test_case("mainnet-01367-d7efc68f.era1"; "era1_roundtrip_mainnet_1367")]
|
||||
#[test_case::test_case("mainnet-01895-3f81607c.era1"; "era1_roundtrip_mainnet_1895")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore = "download intensive"]
|
||||
async fn test_roundtrip_compression_encoding_mainnet(filename: &str) -> eyre::Result<()> {
|
||||
let downloader = EraTestDownloader::new().await?;
|
||||
test_file_roundtrip(&downloader, filename, MAINNET).await
|
||||
test_era1_file_roundtrip(&downloader, filename, MAINNET).await
|
||||
}
|
||||
|
||||
#[test_case::test_case("sepolia-00000-643a00f7.era1"; "era_sepolia_0")]
|
||||
#[test_case::test_case("sepolia-00074-0e81003c.era1"; "era_sepolia_74")]
|
||||
#[test_case::test_case("sepolia-00173-b6924da5.era1"; "era_sepolia_173")]
|
||||
#[test_case::test_case("sepolia-00182-a4f0a8a1.era1"; "era_sepolia_182")]
|
||||
#[test_case::test_case("sepolia-00000-643a00f7.era1"; "era1_roundtrip_sepolia_0")]
|
||||
#[test_case::test_case("sepolia-00074-0e81003c.era1"; "era1_roundtrip_sepolia_74")]
|
||||
#[test_case::test_case("sepolia-00173-b6924da5.era1"; "era1_roundtrip_sepolia_173")]
|
||||
#[test_case::test_case("sepolia-00182-a4f0a8a1.era1"; "era1_roundtrip_sepolia_182")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore = "download intensive"]
|
||||
async fn test_roundtrip_compression_encoding_sepolia(filename: &str) -> eyre::Result<()> {
|
||||
let downloader = EraTestDownloader::new().await?;
|
||||
|
||||
test_file_roundtrip(&downloader, filename, SEPOLIA).await?;
|
||||
test_era1_file_roundtrip(&downloader, filename, SEPOLIA).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -91,16 +91,19 @@ const ERA_MAINNET_URL: &str = "https://mainnet.era.nimbus.team/";
|
||||
/// Succinct list of mainnet files we want to download
|
||||
/// from <https://mainnet.era.nimbus.team/> //TODO: to replace with internal era files hosting url
|
||||
/// for testing purposes
|
||||
const ERA_MAINNET_FILES_NAMES: [&str; 4] = [
|
||||
const ERA_MAINNET_FILES_NAMES: [&str; 8] = [
|
||||
"mainnet-00000-4b363db9.era",
|
||||
"mainnet-00178-0d0a5290.era",
|
||||
"mainnet-00518-4e267a3a.era",
|
||||
"mainnet-01140-f70d4869.era",
|
||||
"mainnet-00780-bb546fec.era",
|
||||
"mainnet-01070-7616e3e2.era",
|
||||
"mainnet-01267-e3ddc749.era",
|
||||
"mainnet-01581-82073d28.era",
|
||||
"mainnet-01592-d4dc8b98.era",
|
||||
];
|
||||
|
||||
/// Utility for downloading `.era1` files for tests
|
||||
/// in a temporary directory
|
||||
/// and caching them in memory
|
||||
/// Utility for downloading `.era` and `.era1` files for tests
|
||||
/// in a temporary directory and caching them in memory
|
||||
#[derive(Debug)]
|
||||
struct EraTestDownloader {
|
||||
/// Temporary directory for storing downloaded files
|
||||
@@ -180,7 +183,7 @@ impl EraTestDownloader {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get network configuration, URL and supported files, based on network and file type
|
||||
/// Get network configuration, URL and supported files, based on network and file type
|
||||
fn get_network_config(
|
||||
&self,
|
||||
filename: &str,
|
||||
@@ -202,14 +205,13 @@ impl EraTestDownloader {
|
||||
}
|
||||
}
|
||||
|
||||
/// open .era1 file, downloading it if necessary
|
||||
/// Open `.era1` file, downloading it if necessary
|
||||
async fn open_era1_file(&self, filename: &str, network: &str) -> Result<Era1File> {
|
||||
let path = self.download_file(filename, network).await?;
|
||||
Era1Reader::open(&path, network).map_err(|e| eyre!("Failed to open Era1 file: {e}"))
|
||||
}
|
||||
|
||||
/// open .era file, downloading it if necessary
|
||||
#[allow(dead_code)]
|
||||
/// Open `.era` file, downloading it if necessary
|
||||
async fn open_era_file(&self, filename: &str, network: &str) -> Result<EraFile> {
|
||||
let path = self.download_file(filename, network).await?;
|
||||
EraReader::open(&path, network).map_err(|e| eyre!("Failed to open Era1 file: {e}"))
|
||||
|
||||
@@ -5,7 +5,6 @@ use alloy_consensus::{
|
||||
};
|
||||
use alloy_eips::merge::BEACON_NONCE;
|
||||
use alloy_evm::{block::BlockExecutorFactory, eth::EthBlockExecutionCtx};
|
||||
use alloy_primitives::Bytes;
|
||||
use reth_chainspec::{EthChainSpec, EthereumHardforks};
|
||||
use reth_evm::execute::{BlockAssembler, BlockAssemblerInput, BlockExecutionError};
|
||||
use reth_execution_types::BlockExecutionResult;
|
||||
@@ -17,14 +16,12 @@ use revm::context::Block as _;
|
||||
pub struct EthBlockAssembler<ChainSpec = reth_chainspec::ChainSpec> {
|
||||
/// The chainspec.
|
||||
pub chain_spec: Arc<ChainSpec>,
|
||||
/// Extra data to use for the blocks.
|
||||
pub extra_data: Bytes,
|
||||
}
|
||||
|
||||
impl<ChainSpec> EthBlockAssembler<ChainSpec> {
|
||||
/// Creates a new [`EthBlockAssembler`].
|
||||
pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec, extra_data: Default::default() }
|
||||
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +107,7 @@ where
|
||||
gas_limit: evm_env.block_env.gas_limit(),
|
||||
difficulty: evm_env.block_env.difficulty(),
|
||||
gas_used: *gas_used,
|
||||
extra_data: self.extra_data.clone(),
|
||||
extra_data: ctx.extra_data,
|
||||
parent_beacon_block_root: ctx.parent_beacon_block_root,
|
||||
blob_gas_used: block_blob_gas_used,
|
||||
excess_blob_gas,
|
||||
|
||||
@@ -116,12 +116,6 @@ impl<ChainSpec, EvmFactory> EthEvmConfig<ChainSpec, EvmFactory> {
|
||||
pub const fn chain_spec(&self) -> &Arc<ChainSpec> {
|
||||
self.executor_factory.spec()
|
||||
}
|
||||
|
||||
/// Sets the extra data for the block assembler.
|
||||
pub fn with_extra_data(mut self, extra_data: Bytes) -> Self {
|
||||
self.block_assembler.extra_data = extra_data;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<ChainSpec, EvmF> ConfigureEvm for EthEvmConfig<ChainSpec, EvmF>
|
||||
@@ -193,6 +187,7 @@ where
|
||||
parent_beacon_block_root: block.header().parent_beacon_block_root,
|
||||
ommers: &block.body().ommers,
|
||||
withdrawals: block.body().withdrawals.as_ref().map(Cow::Borrowed),
|
||||
extra_data: block.header().extra_data.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -206,6 +201,7 @@ where
|
||||
parent_beacon_block_root: attributes.parent_beacon_block_root,
|
||||
ommers: &[],
|
||||
withdrawals: attributes.withdrawals.map(Cow::Owned),
|
||||
extra_data: attributes.extra_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -282,6 +278,7 @@ where
|
||||
parent_beacon_block_root: payload.sidecar.parent_beacon_block_root(),
|
||||
ommers: &[],
|
||||
withdrawals: payload.payload.withdrawals().map(|w| Cow::Owned(w.clone().into())),
|
||||
extra_data: payload.payload.as_v1().extra_data.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -289,12 +286,15 @@ where
|
||||
&self,
|
||||
payload: &ExecutionData,
|
||||
) -> Result<impl ExecutableTxIterator<Self>, Self::Error> {
|
||||
Ok(payload.payload.transactions().clone().into_iter().map(|tx| {
|
||||
let txs = payload.payload.transactions().clone().into_iter();
|
||||
let convert = |tx: Bytes| {
|
||||
let tx =
|
||||
TxTy::<Self::Primitives>::decode_2718_exact(tx.as_ref()).map_err(AnyError::new)?;
|
||||
let signer = tx.try_recover().map_err(AnyError::new)?;
|
||||
Ok::<_, AnyError>(tx.with_signer(signer))
|
||||
}))
|
||||
};
|
||||
|
||||
Ok((txs, convert))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ reth-node-core.workspace = true
|
||||
reth-e2e-test-utils.workspace = true
|
||||
reth-tasks.workspace = true
|
||||
reth-testing-utils.workspace = true
|
||||
tempfile.workspace = true
|
||||
jsonrpsee-core.workspace = true
|
||||
|
||||
alloy-primitives.workspace = true
|
||||
alloy-provider.workspace = true
|
||||
|
||||
@@ -32,15 +32,15 @@ use reth_node_builder::{
|
||||
EngineValidatorBuilder, EthApiBuilder, EthApiCtx, Identity, PayloadValidatorBuilder,
|
||||
RethRpcAddOns, RpcAddOns, RpcHandle,
|
||||
},
|
||||
BuilderContext, DebugNode, Node, NodeAdapter, PayloadBuilderConfig,
|
||||
BuilderContext, DebugNode, Node, NodeAdapter,
|
||||
};
|
||||
use reth_payload_primitives::PayloadTypes;
|
||||
use reth_provider::{providers::ProviderFactoryBuilder, EthStorage};
|
||||
use reth_rpc::{
|
||||
eth::core::{EthApiFor, EthRpcConverterFor},
|
||||
ValidationApi,
|
||||
TestingApi, ValidationApi,
|
||||
};
|
||||
use reth_rpc_api::servers::BlockSubmissionValidationApiServer;
|
||||
use reth_rpc_api::servers::{BlockSubmissionValidationApiServer, TestingApiServer};
|
||||
use reth_rpc_builder::{config::RethRpcServerConfig, middleware::RethRpcMiddleware};
|
||||
use reth_rpc_eth_api::{
|
||||
helpers::{
|
||||
@@ -313,6 +313,17 @@ where
|
||||
.modules
|
||||
.merge_if_module_configured(RethRpcModule::Eth, eth_config.into_rpc())?;
|
||||
|
||||
// testing_buildBlockV1: only wire when the hidden testing module is explicitly
|
||||
// requested on any transport. Default stays disabled to honor security guidance.
|
||||
let testing_api = TestingApi::new(
|
||||
container.registry.eth_api().clone(),
|
||||
container.registry.evm_config().clone(),
|
||||
)
|
||||
.into_rpc();
|
||||
container
|
||||
.modules
|
||||
.merge_if_module_configured(RethRpcModule::Testing, testing_api)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
@@ -426,9 +437,7 @@ where
|
||||
type EVM = EthEvmConfig<Types::ChainSpec>;
|
||||
|
||||
async fn build_evm(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::EVM> {
|
||||
let evm_config = EthEvmConfig::new(ctx.chain_spec())
|
||||
.with_extra_data(ctx.payload_builder_config().extra_data_bytes());
|
||||
Ok(evm_config)
|
||||
Ok(EthEvmConfig::new(ctx.chain_spec()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ where
|
||||
evm_config,
|
||||
EthereumBuilderConfig::new()
|
||||
.with_gas_limit(gas_limit)
|
||||
.with_max_blobs_per_block(conf.max_blobs_per_block()),
|
||||
.with_max_blobs_per_block(conf.max_blobs_per_block())
|
||||
.with_extra_data(conf.extra_data_bytes()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
|
||||
mod builder;
|
||||
mod exex;
|
||||
mod testing;
|
||||
|
||||
const fn main() {}
|
||||
|
||||
84
crates/ethereum/node/tests/it/testing.rs
Normal file
84
crates/ethereum/node/tests/it/testing.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
//! E2E tests for the testing RPC namespace.
|
||||
|
||||
use alloy_primitives::{Address, B256};
|
||||
use alloy_rpc_types_engine::ExecutionPayloadEnvelopeV4;
|
||||
use jsonrpsee_core::client::ClientT;
|
||||
use reth_db::test_utils::create_test_rw_db;
|
||||
use reth_ethereum_engine_primitives::EthPayloadAttributes;
|
||||
use reth_node_builder::{NodeBuilder, NodeConfig};
|
||||
use reth_node_core::{
|
||||
args::DatadirArgs,
|
||||
dirs::{DataDirPath, MaybePlatformPath},
|
||||
};
|
||||
use reth_node_ethereum::{node::EthereumAddOns, EthereumNode};
|
||||
use reth_rpc_api::TestingBuildBlockRequestV1;
|
||||
use reth_rpc_server_types::{RethRpcModule, RpcModuleSelection};
|
||||
use reth_tasks::TaskManager;
|
||||
use std::str::FromStr;
|
||||
use tempfile::tempdir;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn testing_rpc_build_block_works() -> eyre::Result<()> {
|
||||
let tasks = TaskManager::current();
|
||||
let mut rpc_args = reth_node_core::args::RpcServerArgs::default().with_http();
|
||||
rpc_args.http_api = Some(RpcModuleSelection::from_iter([RethRpcModule::Testing]));
|
||||
let tempdir = tempdir().expect("temp datadir");
|
||||
let datadir_args = DatadirArgs {
|
||||
datadir: MaybePlatformPath::<DataDirPath>::from_str(tempdir.path().to_str().unwrap())
|
||||
.expect("valid datadir"),
|
||||
static_files_path: Some(tempdir.path().join("static")),
|
||||
};
|
||||
let config = NodeConfig::test().with_datadir_args(datadir_args).with_rpc(rpc_args);
|
||||
let db = create_test_rw_db();
|
||||
|
||||
let (tx, rx): (
|
||||
oneshot::Sender<eyre::Result<ExecutionPayloadEnvelopeV4>>,
|
||||
oneshot::Receiver<eyre::Result<ExecutionPayloadEnvelopeV4>>,
|
||||
) = oneshot::channel();
|
||||
|
||||
let builder = NodeBuilder::new(config)
|
||||
.with_database(db)
|
||||
.with_launch_context(tasks.executor())
|
||||
.with_types::<EthereumNode>()
|
||||
.with_components(EthereumNode::components())
|
||||
.with_add_ons(EthereumAddOns::default())
|
||||
.on_rpc_started(move |ctx, handles| {
|
||||
let Some(client) = handles.rpc.http_client() else { return Ok(()) };
|
||||
|
||||
let chain = ctx.config().chain.clone();
|
||||
let parent_block_hash = chain.genesis_hash();
|
||||
let payload_attributes = EthPayloadAttributes {
|
||||
timestamp: chain.genesis().timestamp + 1,
|
||||
prev_randao: B256::ZERO,
|
||||
suggested_fee_recipient: Address::ZERO,
|
||||
withdrawals: None,
|
||||
parent_beacon_block_root: None,
|
||||
};
|
||||
|
||||
let request = TestingBuildBlockRequestV1 {
|
||||
parent_block_hash,
|
||||
payload_attributes,
|
||||
transactions: vec![],
|
||||
extra_data: None,
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
let res: eyre::Result<ExecutionPayloadEnvelopeV4> =
|
||||
client.request("testing_buildBlockV1", [request]).await.map_err(Into::into);
|
||||
let _ = tx.send(res);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
// Launch the node with the default engine launcher.
|
||||
let launcher = builder.engine_api_launcher();
|
||||
let _node = builder.launch_with(launcher).await?;
|
||||
|
||||
// Wait for the testing RPC call to return.
|
||||
let res = rx.await.expect("testing_buildBlockV1 response");
|
||||
assert!(res.is_ok(), "testing_buildBlockV1 failed: {:?}", res.err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use alloy_eips::eip1559::ETHEREUM_BLOCK_GAS_LIMIT_30M;
|
||||
use alloy_primitives::Bytes;
|
||||
use reth_primitives_traits::constants::GAS_LIMIT_BOUND_DIVISOR;
|
||||
|
||||
/// Settings for the Ethereum builder.
|
||||
@@ -13,6 +14,8 @@ pub struct EthereumBuilderConfig {
|
||||
///
|
||||
/// If `None`, defaults to the protocol maximum.
|
||||
pub max_blobs_per_block: Option<u64>,
|
||||
/// Extra data for built blocks.
|
||||
pub extra_data: Bytes,
|
||||
}
|
||||
|
||||
impl Default for EthereumBuilderConfig {
|
||||
@@ -28,6 +31,7 @@ impl EthereumBuilderConfig {
|
||||
desired_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT_30M,
|
||||
await_payload_on_missing: true,
|
||||
max_blobs_per_block: None,
|
||||
extra_data: Bytes::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +53,12 @@ impl EthereumBuilderConfig {
|
||||
self.max_blobs_per_block = max_blobs_per_block;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the extra data for built blocks.
|
||||
pub fn with_extra_data(mut self, extra_data: Bytes) -> Self {
|
||||
self.extra_data = extra_data;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl EthereumBuilderConfig {
|
||||
|
||||
@@ -168,6 +168,7 @@ where
|
||||
gas_limit: builder_config.gas_limit(parent_header.gas_limit),
|
||||
parent_beacon_block_root: attributes.parent_beacon_block_root(),
|
||||
withdrawals: Some(attributes.withdrawals().clone()),
|
||||
extra_data: builder_config.extra_data,
|
||||
},
|
||||
)
|
||||
.map_err(PayloadBuilderError::other)?;
|
||||
|
||||
@@ -18,22 +18,51 @@ pub trait ConfigureEngineEvm<ExecutionData>: ConfigureEvm {
|
||||
) -> Result<impl ExecutableTxIterator<Self>, Self::Error>;
|
||||
}
|
||||
|
||||
/// Iterator over executable transactions.
|
||||
pub trait ExecutableTxIterator<Evm: ConfigureEvm>:
|
||||
Iterator<Item = Result<Self::Tx, Self::Error>> + Send + 'static
|
||||
{
|
||||
/// A helper trait representing a pair of a "raw" transactions iterator and a closure that can be
|
||||
/// used to convert them to an executable transaction. This tuple is used in the engine to
|
||||
/// parallelize heavy work like decoding or recovery.
|
||||
pub trait ExecutableTxTuple: Into<(Self::Iter, Self::Convert)> + Send + 'static {
|
||||
/// Raw transaction that can be converted to an [`ExecutableTxTuple::Tx`]
|
||||
///
|
||||
/// This can be any type that can be converted to an [`ExecutableTxTuple::Tx`]. For example,
|
||||
/// an unrecovered transaction or just the transaction bytes.
|
||||
type RawTx: Send + Sync + 'static;
|
||||
/// The executable transaction type iterator yields.
|
||||
type Tx: ExecutableTxFor<Evm> + Clone + Send + Sync + 'static;
|
||||
type Tx: Clone + Send + Sync + 'static;
|
||||
/// Errors that may occur while recovering or decoding transactions.
|
||||
type Error: core::error::Error + Send + Sync + 'static;
|
||||
|
||||
/// Iterator over [`ExecutableTxTuple::Tx`]
|
||||
type Iter: Iterator<Item = Self::RawTx> + Send + 'static;
|
||||
/// Closure that can be used to convert a [`ExecutableTxTuple::RawTx`] to a
|
||||
/// [`ExecutableTxTuple::Tx`]. This might involve heavy work like decoding or recovery
|
||||
/// and will be parallelized in the engine.
|
||||
type Convert: Fn(Self::RawTx) -> Result<Self::Tx, Self::Error> + Send + Sync + 'static;
|
||||
}
|
||||
|
||||
impl<Evm: ConfigureEvm, Tx, Err, T> ExecutableTxIterator<Evm> for T
|
||||
impl<RawTx, Tx, Err, I, F> ExecutableTxTuple for (I, F)
|
||||
where
|
||||
Tx: ExecutableTxFor<Evm> + Clone + Send + Sync + 'static,
|
||||
RawTx: Send + Sync + 'static,
|
||||
Tx: Clone + Send + Sync + 'static,
|
||||
Err: core::error::Error + Send + Sync + 'static,
|
||||
T: Iterator<Item = Result<Tx, Err>> + Send + 'static,
|
||||
I: Iterator<Item = RawTx> + Send + 'static,
|
||||
F: Fn(RawTx) -> Result<Tx, Err> + Send + Sync + 'static,
|
||||
{
|
||||
type RawTx = RawTx;
|
||||
type Tx = Tx;
|
||||
type Error = Err;
|
||||
|
||||
type Iter = I;
|
||||
type Convert = F;
|
||||
}
|
||||
|
||||
/// Iterator over executable transactions.
|
||||
pub trait ExecutableTxIterator<Evm: ConfigureEvm>:
|
||||
ExecutableTxTuple<Tx: ExecutableTxFor<Evm>>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, Evm: ConfigureEvm> ExecutableTxIterator<Evm> for T where
|
||||
T: ExecutableTxTuple<Tx: ExecutableTxFor<Evm>>
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ use alloy_evm::{
|
||||
block::{BlockExecutorFactory, BlockExecutorFor},
|
||||
precompiles::PrecompilesMap,
|
||||
};
|
||||
use alloy_primitives::{Address, B256};
|
||||
use alloy_primitives::{Address, Bytes, B256};
|
||||
use core::{error::Error, fmt::Debug};
|
||||
use execute::{BasicBlockExecutor, BlockAssembler, BlockBuilder};
|
||||
use reth_execution_errors::BlockExecutionError;
|
||||
@@ -501,6 +501,8 @@ pub struct NextBlockEnvAttributes {
|
||||
pub parent_beacon_block_root: Option<B256>,
|
||||
/// Withdrawals
|
||||
pub withdrawals: Option<Withdrawals>,
|
||||
/// Optional extra data.
|
||||
pub extra_data: Bytes,
|
||||
}
|
||||
|
||||
/// Abstraction over transaction environment.
|
||||
|
||||
@@ -17,6 +17,14 @@ pub struct ExecutorMetrics {
|
||||
/// The Histogram for amount of gas used.
|
||||
pub gas_used_histogram: Histogram,
|
||||
|
||||
/// The Histogram for amount of time taken to execute the pre-execution changes.
|
||||
pub pre_execution_histogram: Histogram,
|
||||
/// The Histogram for amount of time taken to wait for one transaction to be available.
|
||||
pub transaction_wait_histogram: Histogram,
|
||||
/// The Histogram for amount of time taken to execute one transaction.
|
||||
pub transaction_execution_histogram: Histogram,
|
||||
/// The Histogram for amount of time taken to execute the post-execution changes.
|
||||
pub post_execution_histogram: Histogram,
|
||||
/// The Histogram for amount of time taken to execute blocks.
|
||||
pub execution_histogram: Histogram,
|
||||
/// The total amount of time it took to execute the latest block.
|
||||
|
||||
@@ -95,17 +95,33 @@ pub(super) mod serde_bincode_compat {
|
||||
/// notification: ExExNotification<N>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This enum mirrors [`super::ExExNotification`] but uses borrowed [`Chain`] types
|
||||
/// instead of `Arc<Chain>` for bincode compatibility.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[expect(missing_docs)]
|
||||
#[serde(bound = "")]
|
||||
#[expect(clippy::large_enum_variant)]
|
||||
pub enum ExExNotification<'a, N>
|
||||
where
|
||||
N: NodePrimitives,
|
||||
{
|
||||
ChainCommitted { new: Chain<'a, N> },
|
||||
ChainReorged { old: Chain<'a, N>, new: Chain<'a, N> },
|
||||
ChainReverted { old: Chain<'a, N> },
|
||||
/// Chain got committed without a reorg, and only the new chain is returned.
|
||||
ChainCommitted {
|
||||
/// The new chain after commit.
|
||||
new: Chain<'a, N>,
|
||||
},
|
||||
/// Chain got reorged, and both the old and the new chains are returned.
|
||||
ChainReorged {
|
||||
/// The old chain before reorg.
|
||||
old: Chain<'a, N>,
|
||||
/// The new chain after reorg.
|
||||
new: Chain<'a, N>,
|
||||
},
|
||||
/// Chain got reverted, and only the old chain is returned.
|
||||
ChainReverted {
|
||||
/// The old chain before reversion.
|
||||
old: Chain<'a, N>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a, N> From<&'a super::ExExNotification<N>> for ExExNotification<'a, N>
|
||||
|
||||
@@ -131,6 +131,8 @@ pub struct TransactionsManagerMetrics {
|
||||
/// capacity. Note, this is not a limit to the number of inflight requests, but a health
|
||||
/// measure.
|
||||
pub(crate) capacity_pending_pool_imports: Counter,
|
||||
/// The time it took to prepare transactions for import. This is mostly sender recovery.
|
||||
pub(crate) pool_import_prepare_duration: Histogram,
|
||||
|
||||
/* ================ POLL DURATION ================ */
|
||||
|
||||
|
||||
@@ -1338,6 +1338,8 @@ where
|
||||
let Some(peer) = self.peers.get_mut(&peer_id) else { return };
|
||||
let mut transactions = transactions.0;
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
// mark the transactions as received
|
||||
self.transaction_fetcher
|
||||
.remove_hashes_from_transaction_fetcher(transactions.iter().map(|tx| tx.tx_hash()));
|
||||
@@ -1370,21 +1372,6 @@ where
|
||||
// reallocations
|
||||
let mut new_txs = Vec::with_capacity(transactions.len());
|
||||
for tx in transactions {
|
||||
// recover transaction
|
||||
let tx = match tx.try_into_recovered() {
|
||||
Ok(tx) => tx,
|
||||
Err(badtx) => {
|
||||
trace!(target: "net::tx",
|
||||
peer_id=format!("{peer_id:#}"),
|
||||
hash=%badtx.tx_hash(),
|
||||
client_version=%peer.client_version,
|
||||
"failed ecrecovery for transaction"
|
||||
);
|
||||
has_bad_transactions = true;
|
||||
continue
|
||||
}
|
||||
};
|
||||
|
||||
match self.transactions_by_peers.entry(*tx.tx_hash()) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
// transaction was already inserted
|
||||
@@ -1402,6 +1389,21 @@ where
|
||||
} else {
|
||||
// this is a new transaction that should be imported into the pool
|
||||
|
||||
// recover transaction
|
||||
let tx = match tx.try_into_recovered() {
|
||||
Ok(tx) => tx,
|
||||
Err(badtx) => {
|
||||
trace!(target: "net::tx",
|
||||
peer_id=format!("{peer_id:#}"),
|
||||
hash=%badtx.tx_hash(),
|
||||
client_version=%peer.client_version,
|
||||
"failed ecrecovery for transaction"
|
||||
);
|
||||
has_bad_transactions = true;
|
||||
continue
|
||||
}
|
||||
};
|
||||
|
||||
let pool_transaction = Pool::Transaction::from_pooled(tx);
|
||||
new_txs.push(pool_transaction);
|
||||
|
||||
@@ -1459,6 +1461,8 @@ where
|
||||
if num_already_seen_by_peer > 0 {
|
||||
self.report_already_seen(peer_id);
|
||||
}
|
||||
|
||||
self.metrics.pool_import_prepare_duration.record(start.elapsed());
|
||||
}
|
||||
|
||||
/// Processes a [`FetchEvent`].
|
||||
|
||||
@@ -533,6 +533,27 @@ where
|
||||
}
|
||||
|
||||
/// Modifies the addons with the given closure.
|
||||
///
|
||||
/// This method provides access to methods on the addons type that don't have
|
||||
/// direct builder methods. It's useful for advanced configuration scenarios
|
||||
/// where you need to call addon-specific methods.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use tower::layer::util::Identity;
|
||||
///
|
||||
/// let builder = NodeBuilder::new(config)
|
||||
/// .with_types::<EthereumNode>()
|
||||
/// .with_components(EthereumNode::components())
|
||||
/// .with_add_ons(EthereumAddOns::default())
|
||||
/// .map_add_ons(|addons| addons.with_rpc_middleware(Identity::default()));
|
||||
/// ```
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// - [`NodeAddOns`] trait for available addon types
|
||||
/// - [`crate::NodeBuilderWithComponents::extend_rpc_modules`] for RPC module configuration
|
||||
pub fn map_add_ons<F>(self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(AO) -> AO,
|
||||
@@ -579,10 +600,10 @@ where
|
||||
/// .extend_rpc_modules(|ctx| {
|
||||
/// // Access node components, so they can used by the CustomApi
|
||||
/// let pool = ctx.pool().clone();
|
||||
///
|
||||
///
|
||||
/// // Add custom RPC namespace
|
||||
/// ctx.modules.merge_configured(CustomApi { pool }.into_rpc())?;
|
||||
///
|
||||
///
|
||||
/// Ok(())
|
||||
/// })
|
||||
/// .build()?;
|
||||
@@ -838,8 +859,8 @@ impl<Node: FullNodeTypes> BuilderContext<Node> {
|
||||
.request_handler(self.provider().clone())
|
||||
.split_with_handle();
|
||||
|
||||
self.executor.spawn_critical("p2p txpool", Box::pin(txpool));
|
||||
self.executor.spawn_critical("p2p eth request handler", Box::pin(eth));
|
||||
self.executor.spawn_critical_blocking("p2p txpool", Box::pin(txpool));
|
||||
self.executor.spawn_critical_blocking("p2p eth request handler", Box::pin(eth));
|
||||
|
||||
let default_peers_path = self.config().datadir().known_peers();
|
||||
let known_peers_file = self.config().network.persistent_peers_file(default_peers_path);
|
||||
|
||||
@@ -235,6 +235,27 @@ where
|
||||
}
|
||||
|
||||
/// Modifies the addons with the given closure.
|
||||
///
|
||||
/// This method provides access to methods on the addons type that don't have
|
||||
/// direct builder methods. It's useful for advanced configuration scenarios
|
||||
/// where you need to call addon-specific methods.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use tower::layer::util::Identity;
|
||||
///
|
||||
/// let builder = NodeBuilder::new(config)
|
||||
/// .with_types::<EthereumNode>()
|
||||
/// .with_components(EthereumNode::components())
|
||||
/// .with_add_ons(EthereumAddOns::default())
|
||||
/// .map_add_ons(|addons| addons.with_rpc_middleware(Identity::default()));
|
||||
/// ```
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// - [`NodeAddOns`] trait for available addon types
|
||||
/// - [`crate::NodeBuilderWithComponents::extend_rpc_modules`] for RPC module configuration
|
||||
pub fn map_add_ons<F>(mut self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(AO) -> AO,
|
||||
|
||||
@@ -1010,7 +1010,7 @@ where
|
||||
.with_executor(Box::new(node.task_executor().clone()))
|
||||
.with_evm_config(node.evm_config().clone())
|
||||
.with_consensus(node.consensus().clone())
|
||||
.build_with_auth_server(module_config, engine_api, eth_api);
|
||||
.build_with_auth_server(module_config, engine_api, eth_api, engine_events.clone());
|
||||
|
||||
// in dev mode we generate 20 random dev-signer accounts
|
||||
if config.dev.dev {
|
||||
@@ -1179,6 +1179,7 @@ impl<'a, N: FullNodeComponents<Types: NodeTypes<ChainSpec: Hardforks + EthereumH
|
||||
.proof_permits(self.config.proof_permits)
|
||||
.gas_oracle_config(self.config.gas_oracle)
|
||||
.max_batch_size(self.config.max_batch_size)
|
||||
.max_blocking_io_requests(self.config.max_blocking_io_requests)
|
||||
.pending_block_kind(self.config.pending_block_kind)
|
||||
.raw_tx_forwarder(self.config.raw_tx_forwarder)
|
||||
.evm_memory_limit(self.config.rpc_evm_memory_limit)
|
||||
@@ -1188,10 +1189,7 @@ impl<'a, N: FullNodeComponents<Types: NodeTypes<ChainSpec: Hardforks + EthereumH
|
||||
/// A `EthApi` that knows how to build `eth` namespace API from [`FullNodeComponents`].
|
||||
pub trait EthApiBuilder<N: FullNodeComponents>: Default + Send + 'static {
|
||||
/// The Ethapi implementation this builder will build.
|
||||
type EthApi: EthApiTypes
|
||||
+ FullEthApiServer<Provider = N::Provider, Pool = N::Pool>
|
||||
+ Unpin
|
||||
+ 'static;
|
||||
type EthApi: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>;
|
||||
|
||||
/// Builds the [`EthApiServer`](reth_rpc_api::eth::EthApiServer) from the given context.
|
||||
fn build_eth_api(
|
||||
|
||||
@@ -1,13 +1,198 @@
|
||||
//! clap [Args](clap::Args) for engine purposes
|
||||
|
||||
use clap::Args;
|
||||
use clap::{builder::Resettable, Args};
|
||||
use reth_engine_primitives::{TreeConfig, DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::node_config::{
|
||||
DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB, DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
|
||||
DEFAULT_PERSISTENCE_THRESHOLD, DEFAULT_RESERVED_CPU_CORES,
|
||||
};
|
||||
|
||||
/// Global static engine defaults
|
||||
static ENGINE_DEFAULTS: OnceLock<DefaultEngineValues> = OnceLock::new();
|
||||
|
||||
/// Default values for engine that can be customized
|
||||
///
|
||||
/// Global defaults can be set via [`DefaultEngineValues::try_init`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DefaultEngineValues {
|
||||
persistence_threshold: u64,
|
||||
memory_block_buffer_target: u64,
|
||||
legacy_state_root_task_enabled: bool,
|
||||
state_cache_disabled: bool,
|
||||
prewarming_disabled: bool,
|
||||
parallel_sparse_trie_disabled: bool,
|
||||
state_provider_metrics: bool,
|
||||
cross_block_cache_size: u64,
|
||||
state_root_task_compare_updates: bool,
|
||||
accept_execution_requests_hash: bool,
|
||||
multiproof_chunking_enabled: bool,
|
||||
multiproof_chunk_size: usize,
|
||||
reserved_cpu_cores: usize,
|
||||
precompile_cache_disabled: bool,
|
||||
state_root_fallback: bool,
|
||||
always_process_payload_attributes_on_canonical_head: bool,
|
||||
allow_unwind_canonical_header: bool,
|
||||
storage_worker_count: Option<usize>,
|
||||
account_worker_count: Option<usize>,
|
||||
}
|
||||
|
||||
impl DefaultEngineValues {
|
||||
/// Initialize the global engine defaults with this configuration
|
||||
pub fn try_init(self) -> Result<(), Self> {
|
||||
ENGINE_DEFAULTS.set(self)
|
||||
}
|
||||
|
||||
/// Get a reference to the global engine defaults
|
||||
pub fn get_global() -> &'static Self {
|
||||
ENGINE_DEFAULTS.get_or_init(Self::default)
|
||||
}
|
||||
|
||||
/// Set the default persistence threshold
|
||||
pub const fn with_persistence_threshold(mut self, v: u64) -> Self {
|
||||
self.persistence_threshold = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default memory block buffer target
|
||||
pub const fn with_memory_block_buffer_target(mut self, v: u64) -> Self {
|
||||
self.memory_block_buffer_target = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to enable legacy state root task by default
|
||||
pub const fn with_legacy_state_root_task_enabled(mut self, v: bool) -> Self {
|
||||
self.legacy_state_root_task_enabled = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable state cache by default
|
||||
pub const fn with_state_cache_disabled(mut self, v: bool) -> Self {
|
||||
self.state_cache_disabled = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable prewarming by default
|
||||
pub const fn with_prewarming_disabled(mut self, v: bool) -> Self {
|
||||
self.prewarming_disabled = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable parallel sparse trie by default
|
||||
pub const fn with_parallel_sparse_trie_disabled(mut self, v: bool) -> Self {
|
||||
self.parallel_sparse_trie_disabled = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to enable state provider metrics by default
|
||||
pub const fn with_state_provider_metrics(mut self, v: bool) -> Self {
|
||||
self.state_provider_metrics = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default cross-block cache size in MB
|
||||
pub const fn with_cross_block_cache_size(mut self, v: u64) -> Self {
|
||||
self.cross_block_cache_size = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to compare state root task updates by default
|
||||
pub const fn with_state_root_task_compare_updates(mut self, v: bool) -> Self {
|
||||
self.state_root_task_compare_updates = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to accept execution requests hash by default
|
||||
pub const fn with_accept_execution_requests_hash(mut self, v: bool) -> Self {
|
||||
self.accept_execution_requests_hash = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to enable multiproof chunking by default
|
||||
pub const fn with_multiproof_chunking_enabled(mut self, v: bool) -> Self {
|
||||
self.multiproof_chunking_enabled = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default multiproof chunk size
|
||||
pub const fn with_multiproof_chunk_size(mut self, v: usize) -> Self {
|
||||
self.multiproof_chunk_size = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default number of reserved CPU cores
|
||||
pub const fn with_reserved_cpu_cores(mut self, v: usize) -> Self {
|
||||
self.reserved_cpu_cores = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable precompile cache by default
|
||||
pub const fn with_precompile_cache_disabled(mut self, v: bool) -> Self {
|
||||
self.precompile_cache_disabled = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to enable state root fallback by default
|
||||
pub const fn with_state_root_fallback(mut self, v: bool) -> Self {
|
||||
self.state_root_fallback = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to always process payload attributes on canonical head by default
|
||||
pub const fn with_always_process_payload_attributes_on_canonical_head(
|
||||
mut self,
|
||||
v: bool,
|
||||
) -> Self {
|
||||
self.always_process_payload_attributes_on_canonical_head = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to allow unwinding canonical header by default
|
||||
pub const fn with_allow_unwind_canonical_header(mut self, v: bool) -> Self {
|
||||
self.allow_unwind_canonical_header = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default storage worker count
|
||||
pub const fn with_storage_worker_count(mut self, v: Option<usize>) -> Self {
|
||||
self.storage_worker_count = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default account worker count
|
||||
pub const fn with_account_worker_count(mut self, v: Option<usize>) -> Self {
|
||||
self.account_worker_count = v;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DefaultEngineValues {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
|
||||
memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
|
||||
legacy_state_root_task_enabled: false,
|
||||
state_cache_disabled: false,
|
||||
prewarming_disabled: false,
|
||||
parallel_sparse_trie_disabled: false,
|
||||
state_provider_metrics: false,
|
||||
cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB,
|
||||
state_root_task_compare_updates: false,
|
||||
accept_execution_requests_hash: false,
|
||||
multiproof_chunking_enabled: true,
|
||||
multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
|
||||
reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
|
||||
precompile_cache_disabled: false,
|
||||
state_root_fallback: false,
|
||||
always_process_payload_attributes_on_canonical_head: false,
|
||||
allow_unwind_canonical_header: false,
|
||||
storage_worker_count: None,
|
||||
account_worker_count: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters for configuring the engine driver.
|
||||
#[derive(Debug, Clone, Args, PartialEq, Eq)]
|
||||
#[command(next_help_heading = "Engine")]
|
||||
@@ -18,15 +203,15 @@ pub struct EngineArgs {
|
||||
///
|
||||
/// To persist blocks as fast as the node receives them, set this value to zero. This will
|
||||
/// cause more frequent DB writes.
|
||||
#[arg(long = "engine.persistence-threshold", default_value_t = DEFAULT_PERSISTENCE_THRESHOLD)]
|
||||
#[arg(long = "engine.persistence-threshold", default_value_t = DefaultEngineValues::get_global().persistence_threshold)]
|
||||
pub persistence_threshold: u64,
|
||||
|
||||
/// Configure the target number of blocks to keep in memory.
|
||||
#[arg(long = "engine.memory-block-buffer-target", default_value_t = DEFAULT_MEMORY_BLOCK_BUFFER_TARGET)]
|
||||
#[arg(long = "engine.memory-block-buffer-target", default_value_t = DefaultEngineValues::get_global().memory_block_buffer_target)]
|
||||
pub memory_block_buffer_target: u64,
|
||||
|
||||
/// Enable legacy state root
|
||||
#[arg(long = "engine.legacy-state-root", default_value = "false")]
|
||||
#[arg(long = "engine.legacy-state-root", default_value_t = DefaultEngineValues::get_global().legacy_state_root_task_enabled)]
|
||||
pub legacy_state_root_task_enabled: bool,
|
||||
|
||||
/// CAUTION: This CLI flag has no effect anymore, use --engine.disable-caching-and-prewarming
|
||||
@@ -35,8 +220,12 @@ pub struct EngineArgs {
|
||||
#[deprecated]
|
||||
pub caching_and_prewarming_enabled: bool,
|
||||
|
||||
/// Disable state cache
|
||||
#[arg(long = "engine.disable-state-cache", default_value_t = DefaultEngineValues::get_global().state_cache_disabled)]
|
||||
pub state_cache_disabled: bool,
|
||||
|
||||
/// Disable parallel prewarming
|
||||
#[arg(long = "engine.disable-prewarming", alias = "engine.disable-caching-and-prewarming")]
|
||||
#[arg(long = "engine.disable-prewarming", alias = "engine.disable-caching-and-prewarming", default_value_t = DefaultEngineValues::get_global().prewarming_disabled)]
|
||||
pub prewarming_disabled: bool,
|
||||
|
||||
/// CAUTION: This CLI flag has no effect anymore, use --engine.disable-parallel-sparse-trie
|
||||
@@ -46,38 +235,38 @@ pub struct EngineArgs {
|
||||
pub parallel_sparse_trie_enabled: bool,
|
||||
|
||||
/// Disable the parallel sparse trie in the engine.
|
||||
#[arg(long = "engine.disable-parallel-sparse-trie", default_value = "false")]
|
||||
#[arg(long = "engine.disable-parallel-sparse-trie", default_value_t = DefaultEngineValues::get_global().parallel_sparse_trie_disabled)]
|
||||
pub parallel_sparse_trie_disabled: bool,
|
||||
|
||||
/// Enable state provider latency metrics. This allows the engine to collect and report stats
|
||||
/// about how long state provider calls took during execution, but this does introduce slight
|
||||
/// overhead to state provider calls.
|
||||
#[arg(long = "engine.state-provider-metrics", default_value = "false")]
|
||||
#[arg(long = "engine.state-provider-metrics", default_value_t = DefaultEngineValues::get_global().state_provider_metrics)]
|
||||
pub state_provider_metrics: bool,
|
||||
|
||||
/// Configure the size of cross-block cache in megabytes
|
||||
#[arg(long = "engine.cross-block-cache-size", default_value_t = DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB)]
|
||||
#[arg(long = "engine.cross-block-cache-size", default_value_t = DefaultEngineValues::get_global().cross_block_cache_size)]
|
||||
pub cross_block_cache_size: u64,
|
||||
|
||||
/// Enable comparing trie updates from the state root task to the trie updates from the regular
|
||||
/// state root calculation.
|
||||
#[arg(long = "engine.state-root-task-compare-updates")]
|
||||
#[arg(long = "engine.state-root-task-compare-updates", default_value_t = DefaultEngineValues::get_global().state_root_task_compare_updates)]
|
||||
pub state_root_task_compare_updates: bool,
|
||||
|
||||
/// Enables accepting requests hash instead of an array of requests in `engine_newPayloadV4`.
|
||||
#[arg(long = "engine.accept-execution-requests-hash")]
|
||||
#[arg(long = "engine.accept-execution-requests-hash", default_value_t = DefaultEngineValues::get_global().accept_execution_requests_hash)]
|
||||
pub accept_execution_requests_hash: bool,
|
||||
|
||||
/// Whether multiproof task should chunk proof targets.
|
||||
#[arg(long = "engine.multiproof-chunking", default_value = "true")]
|
||||
#[arg(long = "engine.multiproof-chunking", default_value_t = DefaultEngineValues::get_global().multiproof_chunking_enabled)]
|
||||
pub multiproof_chunking_enabled: bool,
|
||||
|
||||
/// Multiproof task chunk size for proof targets.
|
||||
#[arg(long = "engine.multiproof-chunk-size", default_value_t = DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE)]
|
||||
#[arg(long = "engine.multiproof-chunk-size", default_value_t = DefaultEngineValues::get_global().multiproof_chunk_size)]
|
||||
pub multiproof_chunk_size: usize,
|
||||
|
||||
/// Configure the number of reserved CPU cores for non-reth processes
|
||||
#[arg(long = "engine.reserved-cpu-cores", default_value_t = DEFAULT_RESERVED_CPU_CORES)]
|
||||
#[arg(long = "engine.reserved-cpu-cores", default_value_t = DefaultEngineValues::get_global().reserved_cpu_cores)]
|
||||
pub reserved_cpu_cores: usize,
|
||||
|
||||
/// CAUTION: This CLI flag has no effect anymore, use --engine.disable-precompile-cache
|
||||
@@ -87,11 +276,11 @@ pub struct EngineArgs {
|
||||
pub precompile_cache_enabled: bool,
|
||||
|
||||
/// Disable precompile cache
|
||||
#[arg(long = "engine.disable-precompile-cache", default_value = "false")]
|
||||
#[arg(long = "engine.disable-precompile-cache", default_value_t = DefaultEngineValues::get_global().precompile_cache_disabled)]
|
||||
pub precompile_cache_disabled: bool,
|
||||
|
||||
/// Enable state root fallback, useful for testing
|
||||
#[arg(long = "engine.state-root-fallback", default_value = "false")]
|
||||
#[arg(long = "engine.state-root-fallback", default_value_t = DefaultEngineValues::get_global().state_root_fallback)]
|
||||
pub state_root_fallback: bool,
|
||||
|
||||
/// Always process payload attributes and begin a payload build process even if
|
||||
@@ -101,51 +290,73 @@ pub struct EngineArgs {
|
||||
/// Note: This is a no-op on OP Stack.
|
||||
#[arg(
|
||||
long = "engine.always-process-payload-attributes-on-canonical-head",
|
||||
default_value = "false"
|
||||
default_value_t = DefaultEngineValues::get_global().always_process_payload_attributes_on_canonical_head
|
||||
)]
|
||||
pub always_process_payload_attributes_on_canonical_head: bool,
|
||||
|
||||
/// Allow unwinding canonical header to ancestor during forkchoice updates.
|
||||
/// See `TreeConfig::unwind_canonical_header` for more details.
|
||||
#[arg(long = "engine.allow-unwind-canonical-header", default_value = "false")]
|
||||
#[arg(long = "engine.allow-unwind-canonical-header", default_value_t = DefaultEngineValues::get_global().allow_unwind_canonical_header)]
|
||||
pub allow_unwind_canonical_header: bool,
|
||||
|
||||
/// Configure the number of storage proof workers in the Tokio blocking pool.
|
||||
/// If not specified, defaults to 2x available parallelism, clamped between 2 and 64.
|
||||
#[arg(long = "engine.storage-worker-count")]
|
||||
#[arg(long = "engine.storage-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().storage_worker_count.map(|v| v.to_string().into())))]
|
||||
pub storage_worker_count: Option<usize>,
|
||||
|
||||
/// Configure the number of account proof workers in the Tokio blocking pool.
|
||||
/// If not specified, defaults to the same count as storage workers.
|
||||
#[arg(long = "engine.account-worker-count")]
|
||||
#[arg(long = "engine.account-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().account_worker_count.map(|v| v.to_string().into())))]
|
||||
pub account_worker_count: Option<usize>,
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl Default for EngineArgs {
|
||||
fn default() -> Self {
|
||||
let DefaultEngineValues {
|
||||
persistence_threshold,
|
||||
memory_block_buffer_target,
|
||||
legacy_state_root_task_enabled,
|
||||
state_cache_disabled,
|
||||
prewarming_disabled,
|
||||
parallel_sparse_trie_disabled,
|
||||
state_provider_metrics,
|
||||
cross_block_cache_size,
|
||||
state_root_task_compare_updates,
|
||||
accept_execution_requests_hash,
|
||||
multiproof_chunking_enabled,
|
||||
multiproof_chunk_size,
|
||||
reserved_cpu_cores,
|
||||
precompile_cache_disabled,
|
||||
state_root_fallback,
|
||||
always_process_payload_attributes_on_canonical_head,
|
||||
allow_unwind_canonical_header,
|
||||
storage_worker_count,
|
||||
account_worker_count,
|
||||
} = DefaultEngineValues::get_global().clone();
|
||||
Self {
|
||||
persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
|
||||
memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
|
||||
legacy_state_root_task_enabled: false,
|
||||
state_root_task_compare_updates: false,
|
||||
persistence_threshold,
|
||||
memory_block_buffer_target,
|
||||
legacy_state_root_task_enabled,
|
||||
state_root_task_compare_updates,
|
||||
caching_and_prewarming_enabled: true,
|
||||
prewarming_disabled: false,
|
||||
state_cache_disabled,
|
||||
prewarming_disabled,
|
||||
parallel_sparse_trie_enabled: true,
|
||||
parallel_sparse_trie_disabled: false,
|
||||
state_provider_metrics: false,
|
||||
cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB,
|
||||
accept_execution_requests_hash: false,
|
||||
multiproof_chunking_enabled: true,
|
||||
multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
|
||||
reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
|
||||
parallel_sparse_trie_disabled,
|
||||
state_provider_metrics,
|
||||
cross_block_cache_size,
|
||||
accept_execution_requests_hash,
|
||||
multiproof_chunking_enabled,
|
||||
multiproof_chunk_size,
|
||||
reserved_cpu_cores,
|
||||
precompile_cache_enabled: true,
|
||||
precompile_cache_disabled: false,
|
||||
state_root_fallback: false,
|
||||
always_process_payload_attributes_on_canonical_head: false,
|
||||
allow_unwind_canonical_header: false,
|
||||
storage_worker_count: None,
|
||||
account_worker_count: None,
|
||||
precompile_cache_disabled,
|
||||
state_root_fallback,
|
||||
always_process_payload_attributes_on_canonical_head,
|
||||
allow_unwind_canonical_header,
|
||||
storage_worker_count,
|
||||
account_worker_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,6 +368,7 @@ impl EngineArgs {
|
||||
.with_persistence_threshold(self.persistence_threshold)
|
||||
.with_memory_block_buffer_target(self.memory_block_buffer_target)
|
||||
.with_legacy_state_root(self.legacy_state_root_task_enabled)
|
||||
.without_state_cache(self.state_cache_disabled)
|
||||
.without_prewarming(self.prewarming_disabled)
|
||||
.with_disable_parallel_sparse_trie(self.parallel_sparse_trie_disabled)
|
||||
.with_state_provider_metrics(self.state_provider_metrics)
|
||||
@@ -202,4 +414,66 @@ mod tests {
|
||||
let args = CommandParser::<EngineArgs>::parse_from(["reth"]).args;
|
||||
assert_eq!(args, default_args);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn engine_args() {
|
||||
let args = EngineArgs {
|
||||
persistence_threshold: 100,
|
||||
memory_block_buffer_target: 50,
|
||||
legacy_state_root_task_enabled: true,
|
||||
caching_and_prewarming_enabled: true,
|
||||
state_cache_disabled: true,
|
||||
prewarming_disabled: true,
|
||||
parallel_sparse_trie_enabled: true,
|
||||
parallel_sparse_trie_disabled: true,
|
||||
state_provider_metrics: true,
|
||||
cross_block_cache_size: 256,
|
||||
state_root_task_compare_updates: true,
|
||||
accept_execution_requests_hash: true,
|
||||
multiproof_chunking_enabled: true,
|
||||
multiproof_chunk_size: 512,
|
||||
reserved_cpu_cores: 4,
|
||||
precompile_cache_enabled: true,
|
||||
precompile_cache_disabled: true,
|
||||
state_root_fallback: true,
|
||||
always_process_payload_attributes_on_canonical_head: true,
|
||||
allow_unwind_canonical_header: true,
|
||||
storage_worker_count: Some(16),
|
||||
account_worker_count: Some(8),
|
||||
};
|
||||
|
||||
let parsed_args = CommandParser::<EngineArgs>::parse_from([
|
||||
"reth",
|
||||
"--engine.persistence-threshold",
|
||||
"100",
|
||||
"--engine.memory-block-buffer-target",
|
||||
"50",
|
||||
"--engine.legacy-state-root",
|
||||
"--engine.disable-state-cache",
|
||||
"--engine.disable-prewarming",
|
||||
"--engine.disable-parallel-sparse-trie",
|
||||
"--engine.state-provider-metrics",
|
||||
"--engine.cross-block-cache-size",
|
||||
"256",
|
||||
"--engine.state-root-task-compare-updates",
|
||||
"--engine.accept-execution-requests-hash",
|
||||
"--engine.multiproof-chunking",
|
||||
"--engine.multiproof-chunk-size",
|
||||
"512",
|
||||
"--engine.reserved-cpu-cores",
|
||||
"4",
|
||||
"--engine.disable-precompile-cache",
|
||||
"--engine.state-root-fallback",
|
||||
"--engine.always-process-payload-attributes-on-canonical-head",
|
||||
"--engine.allow-unwind-canonical-header",
|
||||
"--engine.storage-worker-count",
|
||||
"16",
|
||||
"--engine.account-worker-count",
|
||||
"8",
|
||||
])
|
||||
.args;
|
||||
|
||||
assert_eq!(parsed_args, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ pub use network::{DiscoveryArgs, NetworkArgs};
|
||||
|
||||
/// RpcServerArg struct for configuring the RPC
|
||||
mod rpc_server;
|
||||
pub use rpc_server::RpcServerArgs;
|
||||
pub use rpc_server::{DefaultRpcServerArgs, RpcServerArgs};
|
||||
|
||||
/// `RpcStateCacheArgs` struct for configuring RPC state cache
|
||||
mod rpc_state_cache;
|
||||
@@ -66,7 +66,7 @@ pub use benchmark_args::BenchmarkArgs;
|
||||
|
||||
/// EngineArgs for configuring the engine
|
||||
mod engine;
|
||||
pub use engine::EngineArgs;
|
||||
pub use engine::{DefaultEngineValues, EngineArgs};
|
||||
|
||||
/// `RessArgs` for configuring ress subprotocol.
|
||||
mod ress_args;
|
||||
|
||||
@@ -119,6 +119,18 @@ pub struct NetworkArgs {
|
||||
#[arg(long)]
|
||||
pub max_inbound_peers: Option<usize>,
|
||||
|
||||
/// Maximum number of total peers (inbound + outbound).
|
||||
///
|
||||
/// Splits peers using approximately 2:1 inbound:outbound ratio. Cannot be used together with
|
||||
/// `--max-outbound-peers` or `--max-inbound-peers`.
|
||||
#[arg(
|
||||
long,
|
||||
value_name = "COUNT",
|
||||
conflicts_with = "max_outbound_peers",
|
||||
conflicts_with = "max_inbound_peers"
|
||||
)]
|
||||
pub max_peers: Option<usize>,
|
||||
|
||||
/// Max concurrent `GetPooledTransactions` requests.
|
||||
#[arg(long = "max-tx-reqs", value_name = "COUNT", default_value_t = DEFAULT_MAX_COUNT_CONCURRENT_REQUESTS, verbatim_doc_comment)]
|
||||
pub max_concurrent_tx_requests: u32,
|
||||
@@ -245,6 +257,34 @@ impl NetworkArgs {
|
||||
bootnodes.into_iter().filter_map(|node| node.resolve_blocking().ok()).collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the max inbound peers (2:1 ratio).
|
||||
pub fn resolved_max_inbound_peers(&self) -> Option<usize> {
|
||||
if let Some(max_peers) = self.max_peers {
|
||||
if max_peers == 0 {
|
||||
Some(0)
|
||||
} else {
|
||||
let outbound = (max_peers / 3).max(1);
|
||||
Some(max_peers.saturating_sub(outbound))
|
||||
}
|
||||
} else {
|
||||
self.max_inbound_peers
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the max outbound peers (1:2 ratio).
|
||||
pub fn resolved_max_outbound_peers(&self) -> Option<usize> {
|
||||
if let Some(max_peers) = self.max_peers {
|
||||
if max_peers == 0 {
|
||||
Some(0)
|
||||
} else {
|
||||
Some((max_peers / 3).max(1))
|
||||
}
|
||||
} else {
|
||||
self.max_outbound_peers
|
||||
}
|
||||
}
|
||||
|
||||
/// Configures and returns a `TransactionsManagerConfig` based on the current settings.
|
||||
pub const fn transactions_manager_config(&self) -> TransactionsManagerConfig {
|
||||
TransactionsManagerConfig {
|
||||
@@ -291,8 +331,8 @@ impl NetworkArgs {
|
||||
.peers_config_with_basic_nodes_from_file(
|
||||
self.persistent_peers_file(peers_file).as_deref(),
|
||||
)
|
||||
.with_max_inbound_opt(self.max_inbound_peers)
|
||||
.with_max_outbound_opt(self.max_outbound_peers)
|
||||
.with_max_inbound_opt(self.resolved_max_inbound_peers())
|
||||
.with_max_outbound_opt(self.resolved_max_outbound_peers())
|
||||
.with_ip_filter(ip_filter);
|
||||
|
||||
// Configure basic network stack
|
||||
@@ -434,6 +474,7 @@ impl Default for NetworkArgs {
|
||||
port: DEFAULT_DISCOVERY_PORT,
|
||||
max_outbound_peers: None,
|
||||
max_inbound_peers: None,
|
||||
max_peers: None,
|
||||
max_concurrent_tx_requests: DEFAULT_MAX_COUNT_CONCURRENT_REQUESTS,
|
||||
max_concurrent_tx_requests_per_peer: DEFAULT_MAX_COUNT_CONCURRENT_REQUESTS_PER_PEER,
|
||||
soft_limit_byte_size_pooled_transactions_response:
|
||||
@@ -758,6 +799,96 @@ mod tests {
|
||||
assert!(args.disable_tx_gossip);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_max_peers_flag() {
|
||||
let args = CommandParser::<NetworkArgs>::parse_from(["reth", "--max-peers", "90"]).args;
|
||||
|
||||
assert_eq!(args.max_peers, Some(90));
|
||||
assert_eq!(args.max_outbound_peers, None);
|
||||
assert_eq!(args.max_inbound_peers, None);
|
||||
assert_eq!(args.resolved_max_outbound_peers(), Some(30));
|
||||
assert_eq!(args.resolved_max_inbound_peers(), Some(60));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_peers_conflicts_with_outbound() {
|
||||
let result = CommandParser::<NetworkArgs>::try_parse_from([
|
||||
"reth",
|
||||
"--max-peers",
|
||||
"90",
|
||||
"--max-outbound-peers",
|
||||
"50",
|
||||
]);
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Should fail when both --max-peers and --max-outbound-peers are used"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_peers_conflicts_with_inbound() {
|
||||
let result = CommandParser::<NetworkArgs>::try_parse_from([
|
||||
"reth",
|
||||
"--max-peers",
|
||||
"90",
|
||||
"--max-inbound-peers",
|
||||
"30",
|
||||
]);
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Should fail when both --max-peers and --max-inbound-peers are used"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_peers_split_calculation() {
|
||||
let args = CommandParser::<NetworkArgs>::parse_from(["reth", "--max-peers", "90"]).args;
|
||||
|
||||
assert_eq!(args.max_peers, Some(90));
|
||||
assert_eq!(args.resolved_max_outbound_peers(), Some(30));
|
||||
assert_eq!(args.resolved_max_inbound_peers(), Some(60));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_peers_small_values() {
|
||||
let args1 = CommandParser::<NetworkArgs>::parse_from(["reth", "--max-peers", "1"]).args;
|
||||
assert_eq!(args1.resolved_max_outbound_peers(), Some(1));
|
||||
assert_eq!(args1.resolved_max_inbound_peers(), Some(0));
|
||||
|
||||
let args2 = CommandParser::<NetworkArgs>::parse_from(["reth", "--max-peers", "2"]).args;
|
||||
assert_eq!(args2.resolved_max_outbound_peers(), Some(1));
|
||||
assert_eq!(args2.resolved_max_inbound_peers(), Some(1));
|
||||
|
||||
let args3 = CommandParser::<NetworkArgs>::parse_from(["reth", "--max-peers", "3"]).args;
|
||||
assert_eq!(args3.resolved_max_outbound_peers(), Some(1));
|
||||
assert_eq!(args3.resolved_max_inbound_peers(), Some(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolved_peers_without_max_peers() {
|
||||
let args = CommandParser::<NetworkArgs>::parse_from([
|
||||
"reth",
|
||||
"--max-outbound-peers",
|
||||
"75",
|
||||
"--max-inbound-peers",
|
||||
"15",
|
||||
])
|
||||
.args;
|
||||
|
||||
assert_eq!(args.max_peers, None);
|
||||
assert_eq!(args.resolved_max_outbound_peers(), Some(75));
|
||||
assert_eq!(args.resolved_max_inbound_peers(), Some(15));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolved_peers_with_defaults() {
|
||||
let args = CommandParser::<NetworkArgs>::parse_from(["reth"]).args;
|
||||
|
||||
assert_eq!(args.max_peers, None);
|
||||
assert_eq!(args.resolved_max_outbound_peers(), None);
|
||||
assert_eq!(args.resolved_max_inbound_peers(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn network_args_default_sanity_test() {
|
||||
let default_args = NetworkArgs::default();
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::args::{
|
||||
use alloy_primitives::Address;
|
||||
use alloy_rpc_types_engine::JwtSecret;
|
||||
use clap::{
|
||||
builder::{PossibleValue, RangedU64ValueParser, TypedValueParser},
|
||||
builder::{PossibleValue, RangedU64ValueParser, Resettable, TypedValueParser},
|
||||
Arg, Args, Command,
|
||||
};
|
||||
use rand::Rng;
|
||||
@@ -19,12 +19,16 @@ use std::{
|
||||
ffi::OsStr,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::PathBuf,
|
||||
sync::OnceLock,
|
||||
time::Duration,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
use super::types::MaxOr;
|
||||
|
||||
/// Global static RPC server defaults
|
||||
static RPC_SERVER_DEFAULTS: OnceLock<DefaultRpcServerArgs> = OnceLock::new();
|
||||
|
||||
/// Default max number of subscriptions per connection.
|
||||
pub(crate) const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024;
|
||||
|
||||
@@ -37,76 +41,442 @@ pub(crate) const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15;
|
||||
pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 160;
|
||||
|
||||
/// Default number of incoming connections.
|
||||
///
|
||||
/// This restricts how many active connections (http, ws) the server accepts.
|
||||
/// Once exceeded, the server can reject new connections.
|
||||
pub(crate) const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 500;
|
||||
|
||||
/// Default values for RPC server that can be customized
|
||||
///
|
||||
/// Global defaults can be set via [`DefaultRpcServerArgs::try_init`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DefaultRpcServerArgs {
|
||||
http: bool,
|
||||
http_addr: IpAddr,
|
||||
http_port: u16,
|
||||
http_disable_compression: bool,
|
||||
http_api: Option<RpcModuleSelection>,
|
||||
http_corsdomain: Option<String>,
|
||||
ws: bool,
|
||||
ws_addr: IpAddr,
|
||||
ws_port: u16,
|
||||
ws_allowed_origins: Option<String>,
|
||||
ws_api: Option<RpcModuleSelection>,
|
||||
ipcdisable: bool,
|
||||
ipcpath: String,
|
||||
ipc_socket_permissions: Option<String>,
|
||||
auth_addr: IpAddr,
|
||||
auth_port: u16,
|
||||
auth_jwtsecret: Option<PathBuf>,
|
||||
auth_ipc: bool,
|
||||
auth_ipc_path: String,
|
||||
disable_auth_server: bool,
|
||||
rpc_jwtsecret: Option<JwtSecret>,
|
||||
rpc_max_request_size: MaxU32,
|
||||
rpc_max_response_size: MaxU32,
|
||||
rpc_max_subscriptions_per_connection: MaxU32,
|
||||
rpc_max_connections: MaxU32,
|
||||
rpc_max_tracing_requests: usize,
|
||||
rpc_max_blocking_io_requests: usize,
|
||||
rpc_max_trace_filter_blocks: u64,
|
||||
rpc_max_blocks_per_filter: ZeroAsNoneU64,
|
||||
rpc_max_logs_per_response: ZeroAsNoneU64,
|
||||
rpc_gas_cap: u64,
|
||||
rpc_evm_memory_limit: u64,
|
||||
rpc_tx_fee_cap: u128,
|
||||
rpc_max_simulate_blocks: u64,
|
||||
rpc_eth_proof_window: u64,
|
||||
rpc_proof_permits: usize,
|
||||
rpc_pending_block: PendingBlockKind,
|
||||
rpc_forwarder: Option<Url>,
|
||||
builder_disallow: Option<HashSet<Address>>,
|
||||
rpc_state_cache: RpcStateCacheArgs,
|
||||
gas_price_oracle: GasPriceOracleArgs,
|
||||
rpc_send_raw_transaction_sync_timeout: Duration,
|
||||
}
|
||||
|
||||
impl DefaultRpcServerArgs {
|
||||
/// Initialize the global RPC server defaults with this configuration
|
||||
pub fn try_init(self) -> Result<(), Self> {
|
||||
RPC_SERVER_DEFAULTS.set(self)
|
||||
}
|
||||
|
||||
/// Get a reference to the global RPC server defaults
|
||||
pub fn get_global() -> &'static Self {
|
||||
RPC_SERVER_DEFAULTS.get_or_init(Self::default)
|
||||
}
|
||||
|
||||
/// Set the default HTTP enabled state
|
||||
pub const fn with_http(mut self, v: bool) -> Self {
|
||||
self.http = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default HTTP address
|
||||
pub const fn with_http_addr(mut self, v: IpAddr) -> Self {
|
||||
self.http_addr = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default HTTP port
|
||||
pub const fn with_http_port(mut self, v: u16) -> Self {
|
||||
self.http_port = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable HTTP compression by default
|
||||
pub const fn with_http_disable_compression(mut self, v: bool) -> Self {
|
||||
self.http_disable_compression = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default HTTP API modules
|
||||
pub fn with_http_api(mut self, v: Option<RpcModuleSelection>) -> Self {
|
||||
self.http_api = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default HTTP CORS domain
|
||||
pub fn with_http_corsdomain(mut self, v: Option<String>) -> Self {
|
||||
self.http_corsdomain = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS enabled state
|
||||
pub const fn with_ws(mut self, v: bool) -> Self {
|
||||
self.ws = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS address
|
||||
pub const fn with_ws_addr(mut self, v: IpAddr) -> Self {
|
||||
self.ws_addr = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS port
|
||||
pub const fn with_ws_port(mut self, v: u16) -> Self {
|
||||
self.ws_port = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS allowed origins
|
||||
pub fn with_ws_allowed_origins(mut self, v: Option<String>) -> Self {
|
||||
self.ws_allowed_origins = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS API modules
|
||||
pub fn with_ws_api(mut self, v: Option<RpcModuleSelection>) -> Self {
|
||||
self.ws_api = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable IPC by default
|
||||
pub const fn with_ipcdisable(mut self, v: bool) -> Self {
|
||||
self.ipcdisable = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default IPC path
|
||||
pub fn with_ipcpath(mut self, v: String) -> Self {
|
||||
self.ipcpath = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default IPC socket permissions
|
||||
pub fn with_ipc_socket_permissions(mut self, v: Option<String>) -> Self {
|
||||
self.ipc_socket_permissions = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth server address
|
||||
pub const fn with_auth_addr(mut self, v: IpAddr) -> Self {
|
||||
self.auth_addr = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth server port
|
||||
pub const fn with_auth_port(mut self, v: u16) -> Self {
|
||||
self.auth_port = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth JWT secret path
|
||||
pub fn with_auth_jwtsecret(mut self, v: Option<PathBuf>) -> Self {
|
||||
self.auth_jwtsecret = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth IPC enabled state
|
||||
pub const fn with_auth_ipc(mut self, v: bool) -> Self {
|
||||
self.auth_ipc = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth IPC path
|
||||
pub fn with_auth_ipc_path(mut self, v: String) -> Self {
|
||||
self.auth_ipc_path = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable the auth server by default
|
||||
pub const fn with_disable_auth_server(mut self, v: bool) -> Self {
|
||||
self.disable_auth_server = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default RPC JWT secret
|
||||
pub const fn with_rpc_jwtsecret(mut self, v: Option<JwtSecret>) -> Self {
|
||||
self.rpc_jwtsecret = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max request size
|
||||
pub const fn with_rpc_max_request_size(mut self, v: MaxU32) -> Self {
|
||||
self.rpc_max_request_size = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max response size
|
||||
pub const fn with_rpc_max_response_size(mut self, v: MaxU32) -> Self {
|
||||
self.rpc_max_response_size = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max subscriptions per connection
|
||||
pub const fn with_rpc_max_subscriptions_per_connection(mut self, v: MaxU32) -> Self {
|
||||
self.rpc_max_subscriptions_per_connection = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max connections
|
||||
pub const fn with_rpc_max_connections(mut self, v: MaxU32) -> Self {
|
||||
self.rpc_max_connections = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max tracing requests
|
||||
pub const fn with_rpc_max_tracing_requests(mut self, v: usize) -> Self {
|
||||
self.rpc_max_tracing_requests = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max blocking IO requests
|
||||
pub const fn with_rpc_max_blocking_io_requests(mut self, v: usize) -> Self {
|
||||
self.rpc_max_blocking_io_requests = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max trace filter blocks
|
||||
pub const fn with_rpc_max_trace_filter_blocks(mut self, v: u64) -> Self {
|
||||
self.rpc_max_trace_filter_blocks = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max blocks per filter
|
||||
pub const fn with_rpc_max_blocks_per_filter(mut self, v: ZeroAsNoneU64) -> Self {
|
||||
self.rpc_max_blocks_per_filter = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max logs per response
|
||||
pub const fn with_rpc_max_logs_per_response(mut self, v: ZeroAsNoneU64) -> Self {
|
||||
self.rpc_max_logs_per_response = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default gas cap
|
||||
pub const fn with_rpc_gas_cap(mut self, v: u64) -> Self {
|
||||
self.rpc_gas_cap = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default EVM memory limit
|
||||
pub const fn with_rpc_evm_memory_limit(mut self, v: u64) -> Self {
|
||||
self.rpc_evm_memory_limit = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default tx fee cap
|
||||
pub const fn with_rpc_tx_fee_cap(mut self, v: u128) -> Self {
|
||||
self.rpc_tx_fee_cap = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max simulate blocks
|
||||
pub const fn with_rpc_max_simulate_blocks(mut self, v: u64) -> Self {
|
||||
self.rpc_max_simulate_blocks = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default eth proof window
|
||||
pub const fn with_rpc_eth_proof_window(mut self, v: u64) -> Self {
|
||||
self.rpc_eth_proof_window = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default proof permits
|
||||
pub const fn with_rpc_proof_permits(mut self, v: usize) -> Self {
|
||||
self.rpc_proof_permits = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default pending block kind
|
||||
pub const fn with_rpc_pending_block(mut self, v: PendingBlockKind) -> Self {
|
||||
self.rpc_pending_block = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default RPC forwarder
|
||||
pub fn with_rpc_forwarder(mut self, v: Option<Url>) -> Self {
|
||||
self.rpc_forwarder = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default builder disallow addresses
|
||||
pub fn with_builder_disallow(mut self, v: Option<HashSet<Address>>) -> Self {
|
||||
self.builder_disallow = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default RPC state cache args
|
||||
pub const fn with_rpc_state_cache(mut self, v: RpcStateCacheArgs) -> Self {
|
||||
self.rpc_state_cache = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default gas price oracle args
|
||||
pub const fn with_gas_price_oracle(mut self, v: GasPriceOracleArgs) -> Self {
|
||||
self.gas_price_oracle = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default send raw transaction sync timeout
|
||||
pub const fn with_rpc_send_raw_transaction_sync_timeout(mut self, v: Duration) -> Self {
|
||||
self.rpc_send_raw_transaction_sync_timeout = v;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DefaultRpcServerArgs {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
http: false,
|
||||
http_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
http_port: constants::DEFAULT_HTTP_RPC_PORT,
|
||||
http_disable_compression: false,
|
||||
http_api: None,
|
||||
http_corsdomain: None,
|
||||
ws: false,
|
||||
ws_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
ws_port: constants::DEFAULT_WS_RPC_PORT,
|
||||
ws_allowed_origins: None,
|
||||
ws_api: None,
|
||||
ipcdisable: false,
|
||||
ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(),
|
||||
ipc_socket_permissions: None,
|
||||
auth_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
auth_port: constants::DEFAULT_AUTH_PORT,
|
||||
auth_jwtsecret: None,
|
||||
auth_ipc: false,
|
||||
auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(),
|
||||
disable_auth_server: false,
|
||||
rpc_jwtsecret: None,
|
||||
rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(),
|
||||
rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(),
|
||||
rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(),
|
||||
rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(),
|
||||
rpc_max_tracing_requests: constants::default_max_tracing_requests(),
|
||||
rpc_max_blocking_io_requests: constants::DEFAULT_MAX_BLOCKING_IO_REQUEST,
|
||||
rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS,
|
||||
rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(),
|
||||
rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(),
|
||||
rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
|
||||
rpc_evm_memory_limit: (1 << 32) - 1,
|
||||
rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI,
|
||||
rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS,
|
||||
rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW,
|
||||
rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
|
||||
rpc_pending_block: PendingBlockKind::Full,
|
||||
rpc_forwarder: None,
|
||||
builder_disallow: None,
|
||||
rpc_state_cache: RpcStateCacheArgs::default(),
|
||||
gas_price_oracle: GasPriceOracleArgs::default(),
|
||||
rpc_send_raw_transaction_sync_timeout:
|
||||
constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters for configuring the rpc more granularity via CLI
|
||||
#[derive(Debug, Clone, Args, PartialEq, Eq)]
|
||||
#[command(next_help_heading = "RPC")]
|
||||
pub struct RpcServerArgs {
|
||||
/// Enable the HTTP-RPC server
|
||||
#[arg(long, default_value_if("dev", "true", "true"))]
|
||||
#[arg(long, default_value_if("dev", "true", "true"), default_value_t = DefaultRpcServerArgs::get_global().http)]
|
||||
pub http: bool,
|
||||
|
||||
/// Http server address to listen on
|
||||
#[arg(long = "http.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
|
||||
#[arg(long = "http.addr", default_value_t = DefaultRpcServerArgs::get_global().http_addr)]
|
||||
pub http_addr: IpAddr,
|
||||
|
||||
/// Http server port to listen on
|
||||
#[arg(long = "http.port", default_value_t = constants::DEFAULT_HTTP_RPC_PORT)]
|
||||
#[arg(long = "http.port", default_value_t = DefaultRpcServerArgs::get_global().http_port)]
|
||||
pub http_port: u16,
|
||||
|
||||
/// Disable compression for HTTP responses
|
||||
#[arg(long = "http.disable-compression", default_value_t = false)]
|
||||
#[arg(long = "http.disable-compression", default_value_t = DefaultRpcServerArgs::get_global().http_disable_compression)]
|
||||
pub http_disable_compression: bool,
|
||||
|
||||
/// Rpc Modules to be configured for the HTTP server
|
||||
#[arg(long = "http.api", value_parser = RpcModuleSelectionValueParser::default())]
|
||||
#[arg(long = "http.api", value_parser = RpcModuleSelectionValueParser::default(), default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_api.as_ref().map(|v| v.to_string().into())))]
|
||||
pub http_api: Option<RpcModuleSelection>,
|
||||
|
||||
/// Http Corsdomain to allow request from
|
||||
#[arg(long = "http.corsdomain")]
|
||||
#[arg(long = "http.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_corsdomain.as_ref().map(|v| v.to_string().into())))]
|
||||
pub http_corsdomain: Option<String>,
|
||||
|
||||
/// Enable the WS-RPC server
|
||||
#[arg(long)]
|
||||
#[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ws)]
|
||||
pub ws: bool,
|
||||
|
||||
/// Ws server address to listen on
|
||||
#[arg(long = "ws.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
|
||||
#[arg(long = "ws.addr", default_value_t = DefaultRpcServerArgs::get_global().ws_addr)]
|
||||
pub ws_addr: IpAddr,
|
||||
|
||||
/// Ws server port to listen on
|
||||
#[arg(long = "ws.port", default_value_t = constants::DEFAULT_WS_RPC_PORT)]
|
||||
#[arg(long = "ws.port", default_value_t = DefaultRpcServerArgs::get_global().ws_port)]
|
||||
pub ws_port: u16,
|
||||
|
||||
/// Origins from which to accept `WebSocket` requests
|
||||
#[arg(id = "ws.origins", long = "ws.origins", alias = "ws.corsdomain")]
|
||||
#[arg(id = "ws.origins", long = "ws.origins", alias = "ws.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ws_allowed_origins.as_ref().map(|v| v.to_string().into())))]
|
||||
pub ws_allowed_origins: Option<String>,
|
||||
|
||||
/// Rpc Modules to be configured for the WS server
|
||||
#[arg(long = "ws.api", value_parser = RpcModuleSelectionValueParser::default())]
|
||||
#[arg(long = "ws.api", value_parser = RpcModuleSelectionValueParser::default(), default_value = Resettable::from(DefaultRpcServerArgs::get_global().ws_api.as_ref().map(|v| v.to_string().into())))]
|
||||
pub ws_api: Option<RpcModuleSelection>,
|
||||
|
||||
/// Disable the IPC-RPC server
|
||||
#[arg(long)]
|
||||
#[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcdisable)]
|
||||
pub ipcdisable: bool,
|
||||
|
||||
/// Filename for IPC socket/pipe within the datadir
|
||||
#[arg(long, default_value_t = constants::DEFAULT_IPC_ENDPOINT.to_string())]
|
||||
#[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcpath.clone())]
|
||||
pub ipcpath: String,
|
||||
|
||||
/// Set the permissions for the IPC socket file, in octal format.
|
||||
///
|
||||
/// If not specified, the permissions will be set by the system's umask.
|
||||
#[arg(long = "ipc.permissions")]
|
||||
#[arg(long = "ipc.permissions", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ipc_socket_permissions.as_ref().map(|v| v.to_string().into())))]
|
||||
pub ipc_socket_permissions: Option<String>,
|
||||
|
||||
/// Auth server address to listen on
|
||||
#[arg(long = "authrpc.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
|
||||
#[arg(long = "authrpc.addr", default_value_t = DefaultRpcServerArgs::get_global().auth_addr)]
|
||||
pub auth_addr: IpAddr,
|
||||
|
||||
/// Auth server port to listen on
|
||||
#[arg(long = "authrpc.port", default_value_t = constants::DEFAULT_AUTH_PORT)]
|
||||
#[arg(long = "authrpc.port", default_value_t = DefaultRpcServerArgs::get_global().auth_port)]
|
||||
pub auth_port: u16,
|
||||
|
||||
/// Path to a JWT secret to use for the authenticated engine-API RPC server.
|
||||
@@ -115,22 +485,22 @@ pub struct RpcServerArgs {
|
||||
///
|
||||
/// If no path is provided, a secret will be generated and stored in the datadir under
|
||||
/// `<DIR>/<CHAIN_ID>/jwt.hex`. For mainnet this would be `~/.reth/mainnet/jwt.hex` by default.
|
||||
#[arg(long = "authrpc.jwtsecret", value_name = "PATH", global = true, required = false)]
|
||||
#[arg(long = "authrpc.jwtsecret", value_name = "PATH", global = true, required = false, default_value = Resettable::from(DefaultRpcServerArgs::get_global().auth_jwtsecret.as_ref().map(|v| v.to_string_lossy().into())))]
|
||||
pub auth_jwtsecret: Option<PathBuf>,
|
||||
|
||||
/// Enable auth engine API over IPC
|
||||
#[arg(long)]
|
||||
#[arg(long, default_value_t = DefaultRpcServerArgs::get_global().auth_ipc)]
|
||||
pub auth_ipc: bool,
|
||||
|
||||
/// Filename for auth IPC socket/pipe within the datadir
|
||||
#[arg(long = "auth-ipc.path", default_value_t = constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string())]
|
||||
#[arg(long = "auth-ipc.path", default_value_t = DefaultRpcServerArgs::get_global().auth_ipc_path.clone())]
|
||||
pub auth_ipc_path: String,
|
||||
|
||||
/// Disable the auth/engine API server.
|
||||
///
|
||||
/// This will prevent the authenticated engine-API server from starting. Use this if you're
|
||||
/// running a node that doesn't need to serve engine API requests.
|
||||
#[arg(long = "disable-auth-server", alias = "disable-engine-api")]
|
||||
#[arg(long = "disable-auth-server", alias = "disable-engine-api", default_value_t = DefaultRpcServerArgs::get_global().disable_auth_server)]
|
||||
pub disable_auth_server: bool,
|
||||
|
||||
/// Hex encoded JWT secret to authenticate the regular RPC server(s), see `--http.api` and
|
||||
@@ -138,23 +508,23 @@ pub struct RpcServerArgs {
|
||||
///
|
||||
/// This is __not__ used for the authenticated engine-API RPC server, see
|
||||
/// `--authrpc.jwtsecret`.
|
||||
#[arg(long = "rpc.jwtsecret", value_name = "HEX", global = true, required = false)]
|
||||
#[arg(long = "rpc.jwtsecret", value_name = "HEX", global = true, required = false, default_value = Resettable::from(DefaultRpcServerArgs::get_global().rpc_jwtsecret.as_ref().map(|v| format!("{:?}", v).into())))]
|
||||
pub rpc_jwtsecret: Option<JwtSecret>,
|
||||
|
||||
/// Set the maximum RPC request payload size for both HTTP and WS in megabytes.
|
||||
#[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into())]
|
||||
#[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_request_size)]
|
||||
pub rpc_max_request_size: MaxU32,
|
||||
|
||||
/// Set the maximum RPC response payload size for both HTTP and WS in megabytes.
|
||||
#[arg(long = "rpc.max-response-size", alias = "rpc-max-response-size", visible_alias = "rpc.returndata.limit", default_value_t = RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into())]
|
||||
#[arg(long = "rpc.max-response-size", alias = "rpc-max-response-size", visible_alias = "rpc.returndata.limit", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_response_size)]
|
||||
pub rpc_max_response_size: MaxU32,
|
||||
|
||||
/// Set the maximum concurrent subscriptions per connection.
|
||||
#[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = RPC_DEFAULT_MAX_SUBS_PER_CONN.into())]
|
||||
#[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_subscriptions_per_connection)]
|
||||
pub rpc_max_subscriptions_per_connection: MaxU32,
|
||||
|
||||
/// Maximum number of RPC server connections.
|
||||
#[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS.into())]
|
||||
#[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_connections)]
|
||||
pub rpc_max_connections: MaxU32,
|
||||
|
||||
/// Maximum number of concurrent tracing requests.
|
||||
@@ -163,19 +533,27 @@ pub struct RpcServerArgs {
|
||||
/// Tracing requests are generally CPU bound.
|
||||
/// Choosing a value that is higher than the available CPU cores can have a negative impact on
|
||||
/// the performance of the node and affect the node's ability to maintain sync.
|
||||
#[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = constants::default_max_tracing_requests())]
|
||||
#[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_tracing_requests)]
|
||||
pub rpc_max_tracing_requests: usize,
|
||||
|
||||
/// Maximum number of concurrent blocking IO requests.
|
||||
///
|
||||
/// Blocking IO requests include `eth_call`, `eth_estimateGas`, and similar methods that
|
||||
/// require EVM execution. These are spawned as blocking tasks to avoid blocking the async
|
||||
/// runtime.
|
||||
#[arg(long = "rpc.max-blocking-io-requests", alias = "rpc-max-blocking-io-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_blocking_io_requests)]
|
||||
pub rpc_max_blocking_io_requests: usize,
|
||||
|
||||
/// Maximum number of blocks for `trace_filter` requests.
|
||||
#[arg(long = "rpc.max-trace-filter-blocks", alias = "rpc-max-trace-filter-blocks", value_name = "COUNT", default_value_t = constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS)]
|
||||
#[arg(long = "rpc.max-trace-filter-blocks", alias = "rpc-max-trace-filter-blocks", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_trace_filter_blocks)]
|
||||
pub rpc_max_trace_filter_blocks: u64,
|
||||
|
||||
/// Maximum number of blocks that could be scanned per filter request. (0 = entire chain)
|
||||
#[arg(long = "rpc.max-blocks-per-filter", alias = "rpc-max-blocks-per-filter", value_name = "COUNT", default_value_t = ZeroAsNoneU64::new(constants::DEFAULT_MAX_BLOCKS_PER_FILTER))]
|
||||
#[arg(long = "rpc.max-blocks-per-filter", alias = "rpc-max-blocks-per-filter", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_blocks_per_filter)]
|
||||
pub rpc_max_blocks_per_filter: ZeroAsNoneU64,
|
||||
|
||||
/// Maximum number of logs that can be returned in a single response. (0 = no limit)
|
||||
#[arg(long = "rpc.max-logs-per-response", alias = "rpc-max-logs-per-response", value_name = "COUNT", default_value_t = ZeroAsNoneU64::new(constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64))]
|
||||
#[arg(long = "rpc.max-logs-per-response", alias = "rpc-max-logs-per-response", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_logs_per_response)]
|
||||
pub rpc_max_logs_per_response: ZeroAsNoneU64,
|
||||
|
||||
/// Maximum gas limit for `eth_call` and call tracing RPC methods.
|
||||
@@ -184,7 +562,7 @@ pub struct RpcServerArgs {
|
||||
alias = "rpc-gascap",
|
||||
value_name = "GAS_CAP",
|
||||
value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
|
||||
default_value_t = constants::gas_oracle::RPC_DEFAULT_GAS_CAP
|
||||
default_value_t = DefaultRpcServerArgs::get_global().rpc_gas_cap
|
||||
)]
|
||||
pub rpc_gas_cap: u64,
|
||||
|
||||
@@ -194,7 +572,7 @@ pub struct RpcServerArgs {
|
||||
alias = "rpc-evm-memory-limit",
|
||||
value_name = "MEMORY_LIMIT",
|
||||
value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
|
||||
default_value_t = (1 << 32) - 1
|
||||
default_value_t = DefaultRpcServerArgs::get_global().rpc_evm_memory_limit
|
||||
)]
|
||||
pub rpc_evm_memory_limit: u64,
|
||||
|
||||
@@ -212,7 +590,7 @@ pub struct RpcServerArgs {
|
||||
#[arg(
|
||||
long = "rpc.max-simulate-blocks",
|
||||
value_name = "BLOCKS_COUNT",
|
||||
default_value_t = constants::DEFAULT_MAX_SIMULATE_BLOCKS
|
||||
default_value_t = DefaultRpcServerArgs::get_global().rpc_max_simulate_blocks
|
||||
)]
|
||||
pub rpc_max_simulate_blocks: u64,
|
||||
|
||||
@@ -221,7 +599,7 @@ pub struct RpcServerArgs {
|
||||
/// configured number of blocks from current tip (up to `tip - window`).
|
||||
#[arg(
|
||||
long = "rpc.eth-proof-window",
|
||||
default_value_t = constants::DEFAULT_ETH_PROOF_WINDOW,
|
||||
default_value_t = DefaultRpcServerArgs::get_global().rpc_eth_proof_window,
|
||||
value_parser = RangedU64ValueParser::<u64>::new().range(..=constants::MAX_ETH_PROOF_WINDOW)
|
||||
)]
|
||||
pub rpc_eth_proof_window: u64,
|
||||
@@ -243,7 +621,7 @@ pub struct RpcServerArgs {
|
||||
|
||||
/// Path to file containing disallowed addresses, json-encoded list of strings. Block
|
||||
/// validation API will reject blocks containing transactions from these addresses.
|
||||
#[arg(long = "builder.disallow", value_name = "PATH", value_parser = reth_cli_util::parsers::read_json_from_file::<HashSet<Address>>)]
|
||||
#[arg(long = "builder.disallow", value_name = "PATH", value_parser = reth_cli_util::parsers::read_json_from_file::<HashSet<Address>>, default_value = Resettable::from(DefaultRpcServerArgs::get_global().builder_disallow.as_ref().map(|v| format!("{:?}", v).into())))]
|
||||
pub builder_disallow: Option<HashSet<Address>>,
|
||||
|
||||
/// State cache configuration.
|
||||
@@ -387,49 +765,93 @@ impl RpcServerArgs {
|
||||
|
||||
impl Default for RpcServerArgs {
|
||||
fn default() -> Self {
|
||||
let DefaultRpcServerArgs {
|
||||
http,
|
||||
http_addr,
|
||||
http_port,
|
||||
http_disable_compression,
|
||||
http_api,
|
||||
http_corsdomain,
|
||||
ws,
|
||||
ws_addr,
|
||||
ws_port,
|
||||
ws_allowed_origins,
|
||||
ws_api,
|
||||
ipcdisable,
|
||||
ipcpath,
|
||||
ipc_socket_permissions,
|
||||
auth_addr,
|
||||
auth_port,
|
||||
auth_jwtsecret,
|
||||
auth_ipc,
|
||||
auth_ipc_path,
|
||||
disable_auth_server,
|
||||
rpc_jwtsecret,
|
||||
rpc_max_request_size,
|
||||
rpc_max_response_size,
|
||||
rpc_max_subscriptions_per_connection,
|
||||
rpc_max_connections,
|
||||
rpc_max_tracing_requests,
|
||||
rpc_max_blocking_io_requests,
|
||||
rpc_max_trace_filter_blocks,
|
||||
rpc_max_blocks_per_filter,
|
||||
rpc_max_logs_per_response,
|
||||
rpc_gas_cap,
|
||||
rpc_evm_memory_limit,
|
||||
rpc_tx_fee_cap,
|
||||
rpc_max_simulate_blocks,
|
||||
rpc_eth_proof_window,
|
||||
rpc_proof_permits,
|
||||
rpc_pending_block,
|
||||
rpc_forwarder,
|
||||
builder_disallow,
|
||||
rpc_state_cache,
|
||||
gas_price_oracle,
|
||||
rpc_send_raw_transaction_sync_timeout,
|
||||
} = DefaultRpcServerArgs::get_global().clone();
|
||||
Self {
|
||||
http: false,
|
||||
http_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
http_port: constants::DEFAULT_HTTP_RPC_PORT,
|
||||
http_disable_compression: false,
|
||||
http_api: None,
|
||||
http_corsdomain: None,
|
||||
ws: false,
|
||||
ws_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
ws_port: constants::DEFAULT_WS_RPC_PORT,
|
||||
ws_allowed_origins: None,
|
||||
ws_api: None,
|
||||
ipcdisable: false,
|
||||
ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(),
|
||||
ipc_socket_permissions: None,
|
||||
auth_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
auth_port: constants::DEFAULT_AUTH_PORT,
|
||||
auth_jwtsecret: None,
|
||||
auth_ipc: false,
|
||||
auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(),
|
||||
disable_auth_server: false,
|
||||
rpc_jwtsecret: None,
|
||||
rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(),
|
||||
rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(),
|
||||
rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(),
|
||||
rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(),
|
||||
rpc_max_tracing_requests: constants::default_max_tracing_requests(),
|
||||
rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS,
|
||||
rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(),
|
||||
rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(),
|
||||
rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
|
||||
rpc_evm_memory_limit: (1 << 32) - 1,
|
||||
rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI,
|
||||
rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS,
|
||||
rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW,
|
||||
rpc_pending_block: PendingBlockKind::Full,
|
||||
gas_price_oracle: GasPriceOracleArgs::default(),
|
||||
rpc_state_cache: RpcStateCacheArgs::default(),
|
||||
rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
|
||||
rpc_forwarder: None,
|
||||
builder_disallow: Default::default(),
|
||||
rpc_send_raw_transaction_sync_timeout:
|
||||
constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
|
||||
http,
|
||||
http_addr,
|
||||
http_port,
|
||||
http_disable_compression,
|
||||
http_api,
|
||||
http_corsdomain,
|
||||
ws,
|
||||
ws_addr,
|
||||
ws_port,
|
||||
ws_allowed_origins,
|
||||
ws_api,
|
||||
ipcdisable,
|
||||
ipcpath,
|
||||
ipc_socket_permissions,
|
||||
auth_addr,
|
||||
auth_port,
|
||||
auth_jwtsecret,
|
||||
auth_ipc,
|
||||
auth_ipc_path,
|
||||
disable_auth_server,
|
||||
rpc_jwtsecret,
|
||||
rpc_max_request_size,
|
||||
rpc_max_response_size,
|
||||
rpc_max_subscriptions_per_connection,
|
||||
rpc_max_connections,
|
||||
rpc_max_tracing_requests,
|
||||
rpc_max_blocking_io_requests,
|
||||
rpc_max_trace_filter_blocks,
|
||||
rpc_max_blocks_per_filter,
|
||||
rpc_max_logs_per_response,
|
||||
rpc_gas_cap,
|
||||
rpc_evm_memory_limit,
|
||||
rpc_tx_fee_cap,
|
||||
rpc_max_simulate_blocks,
|
||||
rpc_eth_proof_window,
|
||||
rpc_proof_permits,
|
||||
rpc_pending_block,
|
||||
rpc_forwarder,
|
||||
builder_disallow,
|
||||
rpc_state_cache,
|
||||
gas_price_oracle,
|
||||
rpc_send_raw_transaction_sync_timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -542,4 +964,159 @@ mod tests {
|
||||
let expected = 1_000_000_000_000_000_000u128;
|
||||
assert_eq!(args.rpc_tx_fee_cap, expected); // 1 ETH default cap
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rpc_server_args() {
|
||||
let args = RpcServerArgs {
|
||||
http: true,
|
||||
http_addr: "127.0.0.1".parse().unwrap(),
|
||||
http_port: 8545,
|
||||
http_disable_compression: false,
|
||||
http_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
|
||||
http_corsdomain: Some("*".to_string()),
|
||||
ws: true,
|
||||
ws_addr: "127.0.0.1".parse().unwrap(),
|
||||
ws_port: 8546,
|
||||
ws_allowed_origins: Some("*".to_string()),
|
||||
ws_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
|
||||
ipcdisable: false,
|
||||
ipcpath: "reth.ipc".to_string(),
|
||||
ipc_socket_permissions: Some("0o666".to_string()),
|
||||
auth_addr: "127.0.0.1".parse().unwrap(),
|
||||
auth_port: 8551,
|
||||
auth_jwtsecret: Some(std::path::PathBuf::from("/tmp/jwt.hex")),
|
||||
auth_ipc: false,
|
||||
auth_ipc_path: "engine.ipc".to_string(),
|
||||
disable_auth_server: false,
|
||||
rpc_jwtsecret: Some(
|
||||
JwtSecret::from_hex(
|
||||
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
rpc_max_request_size: 15u32.into(),
|
||||
rpc_max_response_size: 160u32.into(),
|
||||
rpc_max_subscriptions_per_connection: 1024u32.into(),
|
||||
rpc_max_connections: 500u32.into(),
|
||||
rpc_max_tracing_requests: 16,
|
||||
rpc_max_blocking_io_requests: 256,
|
||||
rpc_max_trace_filter_blocks: 4000,
|
||||
rpc_max_blocks_per_filter: 1000u64.into(),
|
||||
rpc_max_logs_per_response: 10000u64.into(),
|
||||
rpc_gas_cap: 50_000_000,
|
||||
rpc_evm_memory_limit: 256,
|
||||
rpc_tx_fee_cap: 2_000_000_000_000_000_000u128,
|
||||
rpc_max_simulate_blocks: 256,
|
||||
rpc_eth_proof_window: 100_000,
|
||||
rpc_proof_permits: 16,
|
||||
rpc_pending_block: PendingBlockKind::Full,
|
||||
rpc_forwarder: Some("http://localhost:8545".parse().unwrap()),
|
||||
builder_disallow: None,
|
||||
rpc_state_cache: RpcStateCacheArgs {
|
||||
max_blocks: 5000,
|
||||
max_receipts: 2000,
|
||||
max_headers: 1000,
|
||||
max_concurrent_db_requests: 512,
|
||||
},
|
||||
gas_price_oracle: GasPriceOracleArgs {
|
||||
blocks: 20,
|
||||
ignore_price: 2,
|
||||
max_price: 500_000_000_000,
|
||||
percentile: 60,
|
||||
default_suggested_fee: None,
|
||||
},
|
||||
rpc_send_raw_transaction_sync_timeout: std::time::Duration::from_secs(30),
|
||||
};
|
||||
|
||||
let parsed_args = CommandParser::<RpcServerArgs>::parse_from([
|
||||
"reth",
|
||||
"--http",
|
||||
"--http.addr",
|
||||
"127.0.0.1",
|
||||
"--http.port",
|
||||
"8545",
|
||||
"--http.api",
|
||||
"eth,admin",
|
||||
"--http.corsdomain",
|
||||
"*",
|
||||
"--ws",
|
||||
"--ws.addr",
|
||||
"127.0.0.1",
|
||||
"--ws.port",
|
||||
"8546",
|
||||
"--ws.origins",
|
||||
"*",
|
||||
"--ws.api",
|
||||
"eth,admin",
|
||||
"--ipcpath",
|
||||
"reth.ipc",
|
||||
"--ipc.permissions",
|
||||
"0o666",
|
||||
"--authrpc.addr",
|
||||
"127.0.0.1",
|
||||
"--authrpc.port",
|
||||
"8551",
|
||||
"--authrpc.jwtsecret",
|
||||
"/tmp/jwt.hex",
|
||||
"--auth-ipc.path",
|
||||
"engine.ipc",
|
||||
"--rpc.jwtsecret",
|
||||
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"--rpc.max-request-size",
|
||||
"15",
|
||||
"--rpc.max-response-size",
|
||||
"160",
|
||||
"--rpc.max-subscriptions-per-connection",
|
||||
"1024",
|
||||
"--rpc.max-connections",
|
||||
"500",
|
||||
"--rpc.max-tracing-requests",
|
||||
"16",
|
||||
"--rpc.max-blocking-io-requests",
|
||||
"256",
|
||||
"--rpc.max-trace-filter-blocks",
|
||||
"4000",
|
||||
"--rpc.max-blocks-per-filter",
|
||||
"1000",
|
||||
"--rpc.max-logs-per-response",
|
||||
"10000",
|
||||
"--rpc.gascap",
|
||||
"50000000",
|
||||
"--rpc.evm-memory-limit",
|
||||
"256",
|
||||
"--rpc.txfeecap",
|
||||
"2.0",
|
||||
"--rpc.max-simulate-blocks",
|
||||
"256",
|
||||
"--rpc.eth-proof-window",
|
||||
"100000",
|
||||
"--rpc.proof-permits",
|
||||
"16",
|
||||
"--rpc.pending-block",
|
||||
"full",
|
||||
"--rpc.forwarder",
|
||||
"http://localhost:8545",
|
||||
"--rpc-cache.max-blocks",
|
||||
"5000",
|
||||
"--rpc-cache.max-receipts",
|
||||
"2000",
|
||||
"--rpc-cache.max-headers",
|
||||
"1000",
|
||||
"--rpc-cache.max-concurrent-db-requests",
|
||||
"512",
|
||||
"--gpo.blocks",
|
||||
"20",
|
||||
"--gpo.ignoreprice",
|
||||
"2",
|
||||
"--gpo.maxprice",
|
||||
"500000000000",
|
||||
"--gpo.percentile",
|
||||
"60",
|
||||
"--rpc.send-raw-transaction-sync-timeout",
|
||||
"30s",
|
||||
])
|
||||
.args;
|
||||
|
||||
assert_eq!(parsed_args, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ use reth_chainspec::{
|
||||
};
|
||||
use reth_ethereum_forks::{ChainHardforks, EthereumHardfork, ForkCondition};
|
||||
use reth_network_peers::NodeRecord;
|
||||
use reth_optimism_primitives::ADDRESS_L2_TO_L1_MESSAGE_PASSER;
|
||||
use reth_optimism_primitives::L2_TO_L1_MESSAGE_PASSER_ADDRESS;
|
||||
use reth_primitives_traits::{sync::LazyLock, SealedHeader};
|
||||
|
||||
/// Chain spec builder for a OP stack chain.
|
||||
@@ -499,7 +499,7 @@ pub fn make_op_genesis_header(genesis: &Genesis, hardforks: &ChainHardforks) ->
|
||||
// If Isthmus is active, overwrite the withdrawals root with the storage root of predeploy
|
||||
// `L2ToL1MessagePasser.sol`
|
||||
if hardforks.fork(OpHardfork::Isthmus).active_at_timestamp(header.timestamp) &&
|
||||
let Some(predeploy) = genesis.alloc.get(&ADDRESS_L2_TO_L1_MESSAGE_PASSER) &&
|
||||
let Some(predeploy) = genesis.alloc.get(&L2_TO_L1_MESSAGE_PASSER_ADDRESS) &&
|
||||
let Some(storage) = &predeploy.storage
|
||||
{
|
||||
header.withdrawals_root =
|
||||
|
||||
@@ -98,7 +98,7 @@ mod tests {
|
||||
OP_SEPOLIA_CANYON_TIMESTAMP, OP_SEPOLIA_ECOTONE_TIMESTAMP, OP_SEPOLIA_ISTHMUS_TIMESTAMP,
|
||||
OP_SEPOLIA_JOVIAN_TIMESTAMP,
|
||||
};
|
||||
use reth_optimism_primitives::ADDRESS_L2_TO_L1_MESSAGE_PASSER;
|
||||
use reth_optimism_primitives::L2_TO_L1_MESSAGE_PASSER_ADDRESS;
|
||||
use tar_no_std::TarArchiveRef;
|
||||
|
||||
#[test]
|
||||
@@ -106,7 +106,7 @@ mod tests {
|
||||
let genesis = read_superchain_genesis("unichain", "mainnet").unwrap();
|
||||
assert_eq!(genesis.config.chain_id, 130);
|
||||
assert_eq!(genesis.timestamp, 1730748359);
|
||||
assert!(genesis.alloc.contains_key(&ADDRESS_L2_TO_L1_MESSAGE_PASSER));
|
||||
assert!(genesis.alloc.contains_key(&L2_TO_L1_MESSAGE_PASSER_ADDRESS));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -114,7 +114,7 @@ mod tests {
|
||||
let genesis = read_superchain_genesis("funki", "mainnet").unwrap();
|
||||
assert_eq!(genesis.config.chain_id, 33979);
|
||||
assert_eq!(genesis.timestamp, 1721211095);
|
||||
assert!(genesis.alloc.contains_key(&ADDRESS_L2_TO_L1_MESSAGE_PASSER));
|
||||
assert!(genesis.alloc.contains_key(&L2_TO_L1_MESSAGE_PASSER_ADDRESS));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -241,7 +241,7 @@ mod tests {
|
||||
|
||||
use alloy_consensus::{BlockBody, Eip658Value, Header, Receipt, TxEip7702, TxReceipt};
|
||||
use alloy_eips::{eip4895::Withdrawals, eip7685::Requests};
|
||||
use alloy_primitives::{Address, Bytes, Signature, U256};
|
||||
use alloy_primitives::{Address, Bytes, Log, Signature, U256};
|
||||
use op_alloy_consensus::{
|
||||
encode_holocene_extra_data, encode_jovian_extra_data, OpTypedTransaction,
|
||||
};
|
||||
@@ -367,7 +367,7 @@ mod tests {
|
||||
|
||||
let beacon_consensus = OpBeaconConsensus::new(Arc::new(chain_spec));
|
||||
|
||||
let receipt = OpReceipt::Eip7702(Receipt {
|
||||
let receipt = OpReceipt::Eip7702(Receipt::<Log> {
|
||||
status: Eip658Value::success(),
|
||||
cumulative_gas_used: GAS_USED,
|
||||
logs: vec![],
|
||||
@@ -436,7 +436,7 @@ mod tests {
|
||||
|
||||
let beacon_consensus = OpBeaconConsensus::new(Arc::new(chain_spec));
|
||||
|
||||
let receipt = OpReceipt::Eip7702(Receipt {
|
||||
let receipt = OpReceipt::Eip7702(Receipt::<Log> {
|
||||
status: Eip658Value::success(),
|
||||
cumulative_gas_used: GAS_USED,
|
||||
logs: vec![],
|
||||
@@ -451,7 +451,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: GAS_USED,
|
||||
timestamp: u64::MAX,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
..Default::default()
|
||||
};
|
||||
@@ -509,7 +511,7 @@ mod tests {
|
||||
|
||||
let beacon_consensus = OpBeaconConsensus::new(Arc::new(chain_spec));
|
||||
|
||||
let receipt = OpReceipt::Eip7702(Receipt {
|
||||
let receipt = OpReceipt::Eip7702(Receipt::<Log> {
|
||||
status: Eip658Value::success(),
|
||||
cumulative_gas_used: 0,
|
||||
logs: vec![],
|
||||
@@ -526,7 +528,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: 0,
|
||||
timestamp: u64::MAX - 1,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
extra_data: encode_jovian_extra_data(
|
||||
Default::default(),
|
||||
@@ -549,7 +553,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: 0,
|
||||
timestamp: u64::MAX,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
parent_hash: parent.hash(),
|
||||
..Default::default()
|
||||
@@ -576,7 +582,7 @@ mod tests {
|
||||
|
||||
let beacon_consensus = OpBeaconConsensus::new(Arc::new(chain_spec));
|
||||
|
||||
let receipt = OpReceipt::Eip7702(Receipt {
|
||||
let receipt = OpReceipt::Eip7702(Receipt::<Log> {
|
||||
status: Eip658Value::success(),
|
||||
cumulative_gas_used: 0,
|
||||
logs: vec![],
|
||||
@@ -593,7 +599,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: 0,
|
||||
timestamp: u64::MAX - 1,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
extra_data: encode_jovian_extra_data(
|
||||
Default::default(),
|
||||
@@ -616,7 +624,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: 0,
|
||||
timestamp: u64::MAX,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
parent_hash: parent.hash(),
|
||||
..Default::default()
|
||||
@@ -652,7 +662,7 @@ mod tests {
|
||||
|
||||
let beacon_consensus = OpBeaconConsensus::new(Arc::new(chain_spec));
|
||||
|
||||
let receipt = OpReceipt::Eip7702(Receipt {
|
||||
let receipt = OpReceipt::Eip7702(Receipt::<Log> {
|
||||
status: Eip658Value::success(),
|
||||
cumulative_gas_used: 0,
|
||||
logs: vec![],
|
||||
@@ -669,7 +679,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: 0,
|
||||
timestamp: u64::MAX - 1,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
extra_data: encode_jovian_extra_data(
|
||||
Default::default(),
|
||||
@@ -693,7 +705,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: 0,
|
||||
timestamp: u64::MAX,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
parent_hash: parent.hash(),
|
||||
..Default::default()
|
||||
@@ -722,7 +736,7 @@ mod tests {
|
||||
|
||||
let beacon_consensus = OpBeaconConsensus::new(Arc::new(chain_spec));
|
||||
|
||||
let receipt = OpReceipt::Eip7702(Receipt {
|
||||
let receipt = OpReceipt::Eip7702(Receipt::<Log> {
|
||||
status: Eip658Value::success(),
|
||||
cumulative_gas_used: 0,
|
||||
logs: vec![],
|
||||
@@ -739,7 +753,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: 0,
|
||||
timestamp: u64::MAX - 1,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
extra_data: encode_holocene_extra_data(Default::default(), BaseFeeParams::optimism())
|
||||
.unwrap(),
|
||||
@@ -759,7 +775,9 @@ mod tests {
|
||||
)),
|
||||
gas_used: 0,
|
||||
timestamp: u64::MAX,
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(&receipt)),
|
||||
receipts_root: proofs::calculate_receipt_root(std::slice::from_ref(
|
||||
&receipt.with_bloom_ref(),
|
||||
)),
|
||||
logs_bloom: receipt.bloom(),
|
||||
parent_hash: parent.hash(),
|
||||
..Default::default()
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::OpConsensusError;
|
||||
use alloy_consensus::BlockHeader;
|
||||
use alloy_primitives::B256;
|
||||
use alloy_trie::EMPTY_ROOT_HASH;
|
||||
use reth_optimism_primitives::ADDRESS_L2_TO_L1_MESSAGE_PASSER;
|
||||
use reth_optimism_primitives::L2_TO_L1_MESSAGE_PASSER_ADDRESS;
|
||||
use reth_storage_api::{errors::ProviderResult, StorageRootProvider};
|
||||
use reth_trie_common::HashedStorage;
|
||||
use revm::database::BundleState;
|
||||
@@ -32,7 +32,7 @@ pub fn withdrawals_root<DB: StorageRootProvider>(
|
||||
withdrawals_root_prehashed(
|
||||
state_updates
|
||||
.state()
|
||||
.get(&ADDRESS_L2_TO_L1_MESSAGE_PASSER)
|
||||
.get(&L2_TO_L1_MESSAGE_PASSER_ADDRESS)
|
||||
.map(|acc| {
|
||||
HashedStorage::from_plain_storage(
|
||||
acc.status,
|
||||
@@ -52,7 +52,7 @@ pub fn withdrawals_root_prehashed<DB: StorageRootProvider>(
|
||||
hashed_storage_updates: HashedStorage,
|
||||
state: DB,
|
||||
) -> ProviderResult<B256> {
|
||||
state.storage_root(ADDRESS_L2_TO_L1_MESSAGE_PASSER, hashed_storage_updates)
|
||||
state.storage_root(L2_TO_L1_MESSAGE_PASSER_ADDRESS, hashed_storage_updates)
|
||||
}
|
||||
|
||||
/// Verifies block header field `withdrawals_root` against storage root of
|
||||
@@ -146,7 +146,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn l2tol1_message_passer_no_withdrawals() {
|
||||
let hashed_address = keccak256(ADDRESS_L2_TO_L1_MESSAGE_PASSER);
|
||||
let hashed_address = keccak256(L2_TO_L1_MESSAGE_PASSER_ADDRESS);
|
||||
|
||||
// create account storage
|
||||
let init_storage = HashedStorage::from_iter(
|
||||
|
||||
@@ -16,7 +16,7 @@ use alloy_consensus::{BlockHeader, Header};
|
||||
use alloy_eips::Decodable2718;
|
||||
use alloy_evm::{EvmFactory, FromRecoveredTx, FromTxWithEncoded};
|
||||
use alloy_op_evm::block::{receipt_builder::OpReceiptBuilder, OpTxEnv};
|
||||
use alloy_primitives::U256;
|
||||
use alloy_primitives::{Bytes, U256};
|
||||
use core::fmt::Debug;
|
||||
use op_alloy_consensus::EIP1559ParamError;
|
||||
use op_alloy_rpc_types_engine::OpExecutionData;
|
||||
@@ -265,12 +265,15 @@ where
|
||||
&self,
|
||||
payload: &OpExecutionData,
|
||||
) -> Result<impl ExecutableTxIterator<Self>, Self::Error> {
|
||||
Ok(payload.payload.transactions().clone().into_iter().map(|encoded| {
|
||||
let transactions = payload.payload.transactions().clone().into_iter();
|
||||
let convert = |encoded: Bytes| {
|
||||
let tx = TxTy::<Self::Primitives>::decode_2718_exact(encoded.as_ref())
|
||||
.map_err(AnyError::new)?;
|
||||
let signer = tx.try_recover().map_err(AnyError::new)?;
|
||||
Ok::<_, AnyError>(WithEncoded::new(encoded, tx.with_signer(signer)))
|
||||
}))
|
||||
};
|
||||
|
||||
Ok((transactions, convert))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,14 +486,14 @@ mod tests {
|
||||
block2.set_hash(block2_hash);
|
||||
|
||||
// Create a random receipt object, receipt1
|
||||
let receipt1 = OpReceipt::Legacy(Receipt {
|
||||
let receipt1 = OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![],
|
||||
status: true.into(),
|
||||
});
|
||||
|
||||
// Create another random receipt object, receipt2
|
||||
let receipt2 = OpReceipt::Legacy(Receipt {
|
||||
let receipt2 = OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 1325345,
|
||||
logs: vec![],
|
||||
status: true.into(),
|
||||
@@ -541,7 +544,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// Create a Receipts object with a vector of receipt vectors
|
||||
let receipts = vec![vec![Some(OpReceipt::Legacy(Receipt {
|
||||
let receipts = vec![vec![Some(OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![],
|
||||
status: true.into(),
|
||||
@@ -599,7 +602,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_block_number_to_index() {
|
||||
// Create a Receipts object with a vector of receipt vectors
|
||||
let receipts = vec![vec![Some(OpReceipt::Legacy(Receipt {
|
||||
let receipts = vec![vec![Some(OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![],
|
||||
status: true.into(),
|
||||
@@ -630,7 +633,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_get_logs() {
|
||||
// Create a Receipts object with a vector of receipt vectors
|
||||
let receipts = vec![vec![OpReceipt::Legacy(Receipt {
|
||||
let receipts = vec![vec![OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![Log::<LogData>::default()],
|
||||
status: true.into(),
|
||||
@@ -658,7 +661,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_receipts_by_block() {
|
||||
// Create a Receipts object with a vector of receipt vectors
|
||||
let receipts = vec![vec![Some(OpReceipt::Legacy(Receipt {
|
||||
let receipts = vec![vec![Some(OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![Log::<LogData>::default()],
|
||||
status: true.into(),
|
||||
@@ -682,7 +685,7 @@ mod tests {
|
||||
// Assert that the receipts for block number 123 match the expected receipts
|
||||
assert_eq!(
|
||||
receipts_by_block,
|
||||
vec![&Some(OpReceipt::Legacy(Receipt {
|
||||
vec![&Some(OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![Log::<LogData>::default()],
|
||||
status: true.into(),
|
||||
@@ -693,7 +696,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_receipts_len() {
|
||||
// Create a Receipts object with a vector of receipt vectors
|
||||
let receipts = vec![vec![Some(OpReceipt::Legacy(Receipt {
|
||||
let receipts = vec![vec![Some(OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![Log::<LogData>::default()],
|
||||
status: true.into(),
|
||||
@@ -738,7 +741,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_revert_to() {
|
||||
// Create a random receipt object
|
||||
let receipt = OpReceipt::Legacy(Receipt {
|
||||
let receipt = OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![],
|
||||
status: true.into(),
|
||||
@@ -783,7 +786,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_extend_execution_outcome() {
|
||||
// Create a Receipt object with specific attributes.
|
||||
let receipt = OpReceipt::Legacy(Receipt {
|
||||
let receipt = OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![],
|
||||
status: true.into(),
|
||||
@@ -823,7 +826,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_split_at_execution_outcome() {
|
||||
// Create a random receipt object
|
||||
let receipt = OpReceipt::Legacy(Receipt {
|
||||
let receipt = OpReceipt::Legacy(Receipt::<Log> {
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![],
|
||||
status: true.into(),
|
||||
|
||||
@@ -18,7 +18,7 @@ use reth_node_api::{
|
||||
use reth_optimism_consensus::isthmus;
|
||||
use reth_optimism_forks::OpHardforks;
|
||||
use reth_optimism_payload_builder::{OpExecutionPayloadValidator, OpPayloadTypes};
|
||||
use reth_optimism_primitives::{OpBlock, ADDRESS_L2_TO_L1_MESSAGE_PASSER};
|
||||
use reth_optimism_primitives::{OpBlock, L2_TO_L1_MESSAGE_PASSER_ADDRESS};
|
||||
use reth_primitives_traits::{Block, RecoveredBlock, SealedBlock, SignedTransaction};
|
||||
use reth_provider::StateProviderFactory;
|
||||
use reth_trie_common::{HashedPostState, KeyHasher};
|
||||
@@ -76,7 +76,7 @@ pub struct OpEngineValidator<P, Tx, ChainSpec> {
|
||||
impl<P, Tx, ChainSpec> OpEngineValidator<P, Tx, ChainSpec> {
|
||||
/// Instantiates a new validator.
|
||||
pub fn new<KH: KeyHasher>(chain_spec: Arc<ChainSpec>, provider: P) -> Self {
|
||||
let hashed_addr_l2tol1_msg_passer = KH::hash_key(ADDRESS_L2_TO_L1_MESSAGE_PASSER);
|
||||
let hashed_addr_l2tol1_msg_passer = KH::hash_key(L2_TO_L1_MESSAGE_PASSER_ADDRESS);
|
||||
Self {
|
||||
inner: OpExecutionPayloadValidator::new(chain_spec),
|
||||
provider,
|
||||
|
||||
@@ -20,7 +20,7 @@ use reth_evm::{
|
||||
};
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
use reth_optimism_forks::OpHardforks;
|
||||
use reth_optimism_primitives::{transaction::OpTransaction, ADDRESS_L2_TO_L1_MESSAGE_PASSER};
|
||||
use reth_optimism_primitives::{transaction::OpTransaction, L2_TO_L1_MESSAGE_PASSER_ADDRESS};
|
||||
use reth_optimism_txpool::{
|
||||
estimated_da_size::DataAvailabilitySized,
|
||||
interop::{is_valid_interop, MaybeInteropTransaction},
|
||||
@@ -435,7 +435,7 @@ impl<Txs> OpBuilder<'_, Txs> {
|
||||
if ctx.chain_spec.is_isthmus_active_at_timestamp(ctx.attributes().timestamp()) {
|
||||
// force load `L2ToL1MessagePasser.sol` so l2 withdrawals root can be computed even if
|
||||
// no l2 withdrawals in block
|
||||
_ = db.load_cache_account(ADDRESS_L2_TO_L1_MESSAGE_PASSER)?;
|
||||
_ = db.load_cache_account(L2_TO_L1_MESSAGE_PASSER_ADDRESS)?;
|
||||
}
|
||||
|
||||
let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number: _ } =
|
||||
|
||||
@@ -13,8 +13,8 @@ extern crate alloc;
|
||||
|
||||
pub mod bedrock;
|
||||
|
||||
pub mod predeploys;
|
||||
pub use predeploys::ADDRESS_L2_TO_L1_MESSAGE_PASSER;
|
||||
// Re-export predeploys from op-alloy-consensus
|
||||
pub use op_alloy_consensus::L2_TO_L1_MESSAGE_PASSER_ADDRESS;
|
||||
|
||||
pub mod transaction;
|
||||
pub use transaction::*;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
//! Addresses of OP pre-deploys.
|
||||
// todo: move to op-alloy
|
||||
|
||||
use alloy_primitives::{address, Address};
|
||||
|
||||
/// The L2 contract `L2ToL1MessagePasser`, stores commitments to withdrawal transactions.
|
||||
pub const ADDRESS_L2_TO_L1_MESSAGE_PASSER: Address =
|
||||
address!("0x4200000000000000000000000000000000000016");
|
||||
@@ -176,7 +176,7 @@ mod tests {
|
||||
|
||||
let mut data = Vec::with_capacity(expected.length());
|
||||
let receipt = ReceiptWithBloom {
|
||||
receipt: OpReceipt::Legacy(Receipt {
|
||||
receipt: OpReceipt::Legacy(Receipt::<Log> {
|
||||
status: Eip658Value::Eip658(false),
|
||||
cumulative_gas_used: 0x1,
|
||||
logs: vec![Log::new_unchecked(
|
||||
@@ -207,7 +207,7 @@ mod tests {
|
||||
|
||||
// EIP658Receipt
|
||||
let expected = ReceiptWithBloom {
|
||||
receipt: OpReceipt::Legacy(Receipt {
|
||||
receipt: OpReceipt::Legacy(Receipt::<Log> {
|
||||
status: Eip658Value::Eip658(false),
|
||||
cumulative_gas_used: 0x1,
|
||||
logs: vec![Log::new_unchecked(
|
||||
@@ -235,7 +235,7 @@ mod tests {
|
||||
// Deposit Receipt (post-regolith)
|
||||
let expected = ReceiptWithBloom {
|
||||
receipt: OpReceipt::Deposit(OpDepositReceipt {
|
||||
inner: Receipt {
|
||||
inner: Receipt::<Log> {
|
||||
status: Eip658Value::Eip658(true),
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![],
|
||||
@@ -260,10 +260,10 @@ mod tests {
|
||||
"b901117ef9010d0182b741b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0833d3bbf01"
|
||||
);
|
||||
|
||||
// Deposit Receipt (post-regolith)
|
||||
// Deposit Receipt (post-canyon)
|
||||
let expected = ReceiptWithBloom {
|
||||
receipt: OpReceipt::Deposit(OpDepositReceipt {
|
||||
inner: Receipt {
|
||||
inner: Receipt::<Log> {
|
||||
status: Eip658Value::Eip658(true),
|
||||
cumulative_gas_used: 46913,
|
||||
logs: vec![],
|
||||
@@ -284,7 +284,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn gigantic_receipt() {
|
||||
let receipt = OpReceipt::Legacy(Receipt {
|
||||
let receipt = OpReceipt::Legacy(Receipt::<Log> {
|
||||
status: Eip658Value::Eip658(true),
|
||||
cumulative_gas_used: 16747627,
|
||||
logs: vec![
|
||||
@@ -314,7 +314,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_encode_2718_length() {
|
||||
let receipt = ReceiptWithBloom {
|
||||
receipt: OpReceipt::Eip1559(Receipt {
|
||||
receipt: OpReceipt::Eip1559(Receipt::<Log> {
|
||||
status: Eip658Value::Eip658(true),
|
||||
cumulative_gas_used: 21000,
|
||||
logs: vec![],
|
||||
@@ -331,7 +331,7 @@ mod tests {
|
||||
|
||||
// Test for legacy receipt as well
|
||||
let legacy_receipt = ReceiptWithBloom {
|
||||
receipt: OpReceipt::Legacy(Receipt {
|
||||
receipt: OpReceipt::Legacy(Receipt::<Log> {
|
||||
status: Eip658Value::Eip658(true),
|
||||
cumulative_gas_used: 21000,
|
||||
logs: vec![],
|
||||
|
||||
@@ -272,6 +272,11 @@ where
|
||||
fn tracing_task_guard(&self) -> &BlockingTaskGuard {
|
||||
self.inner.eth_api.blocking_task_guard()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn blocking_io_task_guard(&self) -> &Arc<tokio::sync::Semaphore> {
|
||||
self.inner.eth_api.blocking_io_request_semaphore()
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, Rpc> LoadFee for OpEthApi<N, Rpc>
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
//! Loads and formats OP receipt RPC response.
|
||||
|
||||
use crate::{eth::RpcNodeCore, OpEthApi, OpEthApiError};
|
||||
use alloy_consensus::{BlockHeader, Receipt, TxReceipt};
|
||||
use alloy_consensus::{BlockHeader, Receipt, ReceiptWithBloom, TxReceipt};
|
||||
use alloy_eips::eip2718::Encodable2718;
|
||||
use alloy_rpc_types_eth::{Log, TransactionReceipt};
|
||||
use op_alloy_consensus::{OpReceiptEnvelope, OpTransaction};
|
||||
use op_alloy_consensus::{OpReceipt, OpTransaction};
|
||||
use op_alloy_rpc_types::{L1BlockInfo, OpTransactionReceipt, OpTransactionReceiptFields};
|
||||
use op_revm::estimate_tx_compressed_size;
|
||||
use reth_chainspec::ChainSpecProvider;
|
||||
use reth_node_api::NodePrimitives;
|
||||
use reth_optimism_evm::RethL1BlockInfo;
|
||||
use reth_optimism_forks::OpHardforks;
|
||||
use reth_optimism_primitives::OpReceipt;
|
||||
use reth_primitives_traits::SealedBlock;
|
||||
use reth_rpc_eth_api::{
|
||||
helpers::LoadReceipt,
|
||||
@@ -270,7 +269,7 @@ impl OpReceiptFieldsBuilder {
|
||||
#[derive(Debug)]
|
||||
pub struct OpReceiptBuilder {
|
||||
/// Core receipt, has all the fields of an L1 receipt and is the basis for the OP receipt.
|
||||
pub core_receipt: TransactionReceipt<OpReceiptEnvelope<Log>>,
|
||||
pub core_receipt: TransactionReceipt<ReceiptWithBloom<OpReceipt<Log>>>,
|
||||
/// Additional OP receipt fields.
|
||||
pub op_receipt_fields: OpTransactionReceiptFields,
|
||||
}
|
||||
@@ -294,24 +293,14 @@ impl OpReceiptBuilder {
|
||||
let logs = Log::collect_for_receipt(next_log_index, meta, logs);
|
||||
Receipt { status, cumulative_gas_used, logs }
|
||||
};
|
||||
match receipt {
|
||||
OpReceipt::Legacy(receipt) => {
|
||||
OpReceiptEnvelope::Legacy(map_logs(receipt).into_with_bloom())
|
||||
}
|
||||
OpReceipt::Eip2930(receipt) => {
|
||||
OpReceiptEnvelope::Eip2930(map_logs(receipt).into_with_bloom())
|
||||
}
|
||||
OpReceipt::Eip1559(receipt) => {
|
||||
OpReceiptEnvelope::Eip1559(map_logs(receipt).into_with_bloom())
|
||||
}
|
||||
OpReceipt::Eip7702(receipt) => {
|
||||
OpReceiptEnvelope::Eip7702(map_logs(receipt).into_with_bloom())
|
||||
}
|
||||
|
||||
OpReceipt::Deposit(receipt) => {
|
||||
OpReceiptEnvelope::Deposit(receipt.map_inner(map_logs).into_with_bloom())
|
||||
}
|
||||
}
|
||||
let mapped_receipt: OpReceipt<Log> = match receipt {
|
||||
OpReceipt::Legacy(receipt) => OpReceipt::Legacy(map_logs(receipt)),
|
||||
OpReceipt::Eip2930(receipt) => OpReceipt::Eip2930(map_logs(receipt)),
|
||||
OpReceipt::Eip1559(receipt) => OpReceipt::Eip1559(map_logs(receipt)),
|
||||
OpReceipt::Eip7702(receipt) => OpReceipt::Eip7702(map_logs(receipt)),
|
||||
OpReceipt::Deposit(receipt) => OpReceipt::Deposit(receipt.map_inner(map_logs)),
|
||||
};
|
||||
mapped_receipt.into_with_bloom()
|
||||
});
|
||||
|
||||
// In jovian, we're using the blob gas used field to store the current da
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use crate::{MessageValidationKind, PayloadAttributes};
|
||||
use alloc::vec::Vec;
|
||||
use alloy_eips::{eip1898::BlockWithParent, eip4895::Withdrawal, eip7685::Requests, BlockNumHash};
|
||||
use alloy_primitives::B256;
|
||||
use alloy_primitives::{Bytes, B256};
|
||||
use alloy_rpc_types_engine::ExecutionData;
|
||||
use core::fmt::Debug;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
@@ -40,6 +40,11 @@ pub trait ExecutionPayload:
|
||||
/// Returns `None` for pre-Shanghai blocks.
|
||||
fn withdrawals(&self) -> Option<&Vec<Withdrawal>>;
|
||||
|
||||
/// Returns the access list included in this payload.
|
||||
///
|
||||
/// Returns `None` for pre-Amsterdam blocks.
|
||||
fn block_access_list(&self) -> Option<&Bytes>;
|
||||
|
||||
/// Returns the beacon block root associated with this payload.
|
||||
///
|
||||
/// Returns `None` for pre-merge payloads.
|
||||
@@ -69,6 +74,10 @@ impl ExecutionPayload for ExecutionData {
|
||||
self.payload.withdrawals()
|
||||
}
|
||||
|
||||
fn block_access_list(&self) -> Option<&Bytes> {
|
||||
None
|
||||
}
|
||||
|
||||
fn parent_beacon_block_root(&self) -> Option<B256> {
|
||||
self.sidecar.parent_beacon_block_root()
|
||||
}
|
||||
@@ -172,6 +181,10 @@ impl ExecutionPayload for op_alloy_rpc_types_engine::OpExecutionData {
|
||||
self.payload.as_v2().map(|p| &p.withdrawals)
|
||||
}
|
||||
|
||||
fn block_access_list(&self) -> Option<&Bytes> {
|
||||
None
|
||||
}
|
||||
|
||||
fn parent_beacon_block_root(&self) -> Option<B256> {
|
||||
self.sidecar.parent_beacon_block_root()
|
||||
}
|
||||
|
||||
@@ -198,6 +198,47 @@ pub trait BlockBody:
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator over `Recovered<&Transaction>` for all transactions in the block body.
|
||||
///
|
||||
/// This method recovers signers and returns an iterator without cloning transactions,
|
||||
/// making it more efficient than [`BlockBody::recover_transactions`] when owned values are not
|
||||
/// required.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if any transaction's signature is invalid.
|
||||
fn recover_transactions_ref(
|
||||
&self,
|
||||
) -> Result<impl Iterator<Item = Recovered<&Self::Transaction>> + '_, RecoveryError> {
|
||||
let signers = self.recover_signers()?;
|
||||
Ok(self
|
||||
.transactions()
|
||||
.iter()
|
||||
.zip(signers)
|
||||
.map(|(tx, signer)| Recovered::new_unchecked(tx, signer)))
|
||||
}
|
||||
|
||||
/// Returns an iterator over `Recovered<&Transaction>` for all transactions in the block body
|
||||
/// _without ensuring that the signature has a low `s` value_.
|
||||
///
|
||||
/// This method recovers signers and returns an iterator without cloning transactions,
|
||||
/// making it more efficient than recovering with owned transactions when owned values are not
|
||||
/// required.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if any transaction's signature is invalid.
|
||||
fn recover_transactions_unchecked_ref(
|
||||
&self,
|
||||
) -> Result<impl Iterator<Item = Recovered<&Self::Transaction>> + '_, RecoveryError> {
|
||||
let signers = self.recover_signers_unchecked()?;
|
||||
Ok(self
|
||||
.transactions()
|
||||
.iter()
|
||||
.zip(signers)
|
||||
.map(|(tx, signer)| Recovered::new_unchecked(tx, signer)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, H> BlockBody for alloy_consensus::BlockBody<T, H>
|
||||
|
||||
@@ -164,7 +164,7 @@ pub use alloy_primitives::{logs_bloom, Log, LogData};
|
||||
pub mod proofs;
|
||||
|
||||
mod storage;
|
||||
pub use storage::StorageEntry;
|
||||
pub use storage::{StorageEntry, ValueWithSubKey};
|
||||
|
||||
pub mod sync;
|
||||
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
use alloy_primitives::{B256, U256};
|
||||
|
||||
/// Trait for `DupSort` table values that contain a subkey.
|
||||
///
|
||||
/// This trait allows extracting the subkey from a value during database iteration,
|
||||
/// enabling proper range queries and filtering on `DupSort` tables.
|
||||
pub trait ValueWithSubKey {
|
||||
/// The type of the subkey.
|
||||
type SubKey;
|
||||
|
||||
/// Extract the subkey from the value.
|
||||
fn get_subkey(&self) -> Self::SubKey;
|
||||
}
|
||||
|
||||
/// Account storage entry.
|
||||
///
|
||||
/// `key` is the subkey when used as a value in the `StorageChangeSets` table.
|
||||
@@ -21,6 +33,14 @@ impl StorageEntry {
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueWithSubKey for StorageEntry {
|
||||
type SubKey = B256;
|
||||
|
||||
fn get_subkey(&self) -> Self::SubKey {
|
||||
self.key
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(B256, U256)> for StorageEntry {
|
||||
fn from((key, value): (B256, U256)) -> Self {
|
||||
Self { key, value }
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use crate::PruneLimiter;
|
||||
use reth_db_api::{
|
||||
cursor::{DbCursorRO, DbCursorRW, RangeWalker},
|
||||
table::{Table, TableRow},
|
||||
transaction::DbTxMut,
|
||||
table::{DupSort, Table, TableRow},
|
||||
transaction::{DbTx, DbTxMut},
|
||||
DatabaseError,
|
||||
};
|
||||
use std::{fmt::Debug, ops::RangeBounds};
|
||||
use tracing::debug;
|
||||
|
||||
pub(crate) trait DbTxPruneExt: DbTxMut {
|
||||
pub(crate) trait DbTxPruneExt: DbTxMut + DbTx {
|
||||
/// Prune the table for the specified pre-sorted key iterator.
|
||||
///
|
||||
/// Returns number of rows pruned.
|
||||
@@ -123,9 +123,55 @@ pub(crate) trait DbTxPruneExt: DbTxMut {
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Prune a DUPSORT table for the specified key range.
|
||||
///
|
||||
/// Returns number of rows pruned.
|
||||
fn prune_dupsort_table_with_range<T: DupSort>(
|
||||
&self,
|
||||
keys: impl RangeBounds<T::Key> + Clone + Debug,
|
||||
limiter: &mut PruneLimiter,
|
||||
mut delete_callback: impl FnMut(TableRow<T>),
|
||||
) -> Result<(usize, bool), DatabaseError> {
|
||||
let starting_entries = self.entries::<T>()?;
|
||||
let mut cursor = self.cursor_dup_write::<T>()?;
|
||||
let mut walker = cursor.walk_range(keys)?;
|
||||
|
||||
let done = loop {
|
||||
if limiter.is_limit_reached() {
|
||||
debug!(
|
||||
target: "providers::db",
|
||||
?limiter,
|
||||
deleted_entries_limit = %limiter.is_deleted_entries_limit_reached(),
|
||||
time_limit = %limiter.is_time_limit_reached(),
|
||||
table = %T::NAME,
|
||||
"Pruning limit reached"
|
||||
);
|
||||
break false
|
||||
}
|
||||
|
||||
let Some(res) = walker.next() else { break true };
|
||||
let row = res?;
|
||||
|
||||
walker.delete_current_duplicates()?;
|
||||
limiter.increment_deleted_entries_count();
|
||||
delete_callback(row);
|
||||
};
|
||||
|
||||
debug!(
|
||||
target: "providers::db",
|
||||
table=?T::NAME,
|
||||
cursor_current=?cursor.current(),
|
||||
"done walking",
|
||||
);
|
||||
|
||||
let ending_entries = self.entries::<T>()?;
|
||||
|
||||
Ok((starting_entries - ending_entries, done))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tx> DbTxPruneExt for Tx where Tx: DbTxMut {}
|
||||
impl<Tx> DbTxPruneExt for Tx where Tx: DbTxMut + DbTx {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -71,10 +71,9 @@ where
|
||||
|
||||
let mut last_storages_pruned_block = None;
|
||||
let (storages_pruned, done) =
|
||||
provider.tx_ref().prune_table_with_range::<tables::StoragesTrieChangeSets>(
|
||||
provider.tx_ref().prune_dupsort_table_with_range::<tables::StoragesTrieChangeSets>(
|
||||
storage_range,
|
||||
&mut limiter,
|
||||
|_| false,
|
||||
|(BlockNumberHashedAddress((block_number, _)), _)| {
|
||||
last_storages_pruned_block = Some(block_number);
|
||||
},
|
||||
@@ -90,10 +89,9 @@ where
|
||||
.unwrap_or(block_range_end);
|
||||
|
||||
let (accounts_pruned, done) =
|
||||
provider.tx_ref().prune_table_with_range::<tables::AccountsTrieChangeSets>(
|
||||
provider.tx_ref().prune_dupsort_table_with_range::<tables::AccountsTrieChangeSets>(
|
||||
block_range,
|
||||
&mut limiter,
|
||||
|_| false,
|
||||
|row| last_accounts_pruned_block = row.0,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ pub enum HistoryType {
|
||||
|
||||
/// Default number of blocks to retain for merkle changesets.
|
||||
/// This is used by both the `MerkleChangeSets` stage and the pruner segment.
|
||||
pub const MERKLE_CHANGESETS_RETENTION_BLOCKS: u64 = 64;
|
||||
pub const MERKLE_CHANGESETS_RETENTION_BLOCKS: u64 = 128;
|
||||
|
||||
/// Default pruning mode for merkle changesets
|
||||
const fn default_merkle_changesets_mode() -> PruneMode {
|
||||
@@ -95,13 +95,7 @@ pub struct PruneModes {
|
||||
pub bodies_history: Option<PruneMode>,
|
||||
/// Merkle Changesets pruning configuration for `AccountsTrieChangeSets` and
|
||||
/// `StoragesTrieChangeSets`.
|
||||
#[cfg_attr(
|
||||
any(test, feature = "serde"),
|
||||
serde(
|
||||
default = "default_merkle_changesets_mode",
|
||||
deserialize_with = "deserialize_prune_mode_with_min_blocks::<MERKLE_CHANGESETS_RETENTION_BLOCKS, _>"
|
||||
)
|
||||
)]
|
||||
#[cfg_attr(any(test, feature = "serde"), serde(default = "default_merkle_changesets_mode"))]
|
||||
pub merkle_changesets: PruneMode,
|
||||
/// Receipts pruning configuration by retaining only those receipts that contain logs emitted
|
||||
/// by the specified addresses, discarding others. This setting is overridden by `receipts`.
|
||||
@@ -155,14 +149,15 @@ impl PruneModes {
|
||||
/// Returns `true` if any migration was performed.
|
||||
///
|
||||
/// Currently migrates:
|
||||
/// - `merkle_changesets`: `Distance(10064)` -> `Distance(64)`
|
||||
pub fn migrate(&mut self) -> bool {
|
||||
if self.merkle_changesets == PruneMode::Distance(MINIMUM_PRUNING_DISTANCE) {
|
||||
/// - `merkle_changesets`: `Distance(n)` where `n < 128` or `n == 10064` -> `Distance(128)`
|
||||
pub const fn migrate(&mut self) -> bool {
|
||||
if let PruneMode::Distance(d) = self.merkle_changesets &&
|
||||
(d < MERKLE_CHANGESETS_RETENTION_BLOCKS || d == MINIMUM_PRUNING_DISTANCE)
|
||||
{
|
||||
self.merkle_changesets = PruneMode::Distance(MERKLE_CHANGESETS_RETENTION_BLOCKS);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns an error if we can't unwind to the targeted block because the target block is
|
||||
@@ -214,28 +209,6 @@ impl PruneModes {
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes [`PruneMode`] and validates that the value is not less than the const
|
||||
/// generic parameter `MIN_BLOCKS`. This parameter represents the number of blocks that needs to be
|
||||
/// left in database after the pruning.
|
||||
///
|
||||
/// 1. For [`PruneMode::Full`], it fails if `MIN_BLOCKS > 0`.
|
||||
/// 2. For [`PruneMode::Distance`], it fails if `distance < MIN_BLOCKS + 1`. `+ 1` is needed because
|
||||
/// `PruneMode::Distance(0)` means that we leave zero blocks from the latest, meaning we have one
|
||||
/// block in the database.
|
||||
#[cfg(any(test, feature = "serde"))]
|
||||
fn deserialize_prune_mode_with_min_blocks<
|
||||
'de,
|
||||
const MIN_BLOCKS: u64,
|
||||
D: serde::Deserializer<'de>,
|
||||
>(
|
||||
deserializer: D,
|
||||
) -> Result<PruneMode, D::Error> {
|
||||
use serde::Deserialize;
|
||||
let prune_mode = PruneMode::deserialize(deserializer)?;
|
||||
serde_deserialize_validate::<MIN_BLOCKS, D>(&prune_mode)?;
|
||||
Ok(prune_mode)
|
||||
}
|
||||
|
||||
/// Deserializes [`Option<PruneMode>`] and validates that the value is not less than the const
|
||||
/// generic parameter `MIN_BLOCKS`. This parameter represents the number of blocks that needs to be
|
||||
/// left in database after the pruning.
|
||||
|
||||
@@ -107,18 +107,13 @@ impl RpcServiceT for RpcService {
|
||||
|
||||
fn batch<'a>(&self, req: Batch<'a>) -> impl Future<Output = Self::BatchResponse> + Send + 'a {
|
||||
let entries: Vec<_> = req.into_iter().collect();
|
||||
|
||||
let mut got_notif = false;
|
||||
let mut batch_response = BatchResponseBuilder::new_with_limit(self.max_response_body_size);
|
||||
|
||||
let mut pending_calls: FuturesOrdered<_> = entries
|
||||
.into_iter()
|
||||
.filter_map(|v| match v {
|
||||
Ok(BatchEntry::Call(call)) => Some(Either::Right(self.call(call))),
|
||||
Ok(BatchEntry::Notification(_n)) => {
|
||||
got_notif = true;
|
||||
None
|
||||
}
|
||||
Ok(BatchEntry::Notification(_n)) => None,
|
||||
Err(_err) => Some(Either::Left(async {
|
||||
MethodResponse::error(Id::Null, ErrorObject::from(ErrorCode::InvalidRequest))
|
||||
})),
|
||||
|
||||
@@ -35,9 +35,11 @@ alloy-serde.workspace = true
|
||||
alloy-rpc-types-beacon.workspace = true
|
||||
alloy-rpc-types-engine.workspace = true
|
||||
alloy-genesis.workspace = true
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
# misc
|
||||
jsonrpsee = { workspace = true, features = ["server", "macros"] }
|
||||
serde_json.workspace = true
|
||||
|
||||
[features]
|
||||
client = [
|
||||
@@ -45,3 +47,8 @@ client = [
|
||||
"jsonrpsee/async-client",
|
||||
"reth-rpc-eth-api/client",
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
||||
jsonrpsee = { workspace = true, features = ["client", "async-client", "http-client"] }
|
||||
|
||||
@@ -3,7 +3,7 @@ use alloy_genesis::ChainConfig;
|
||||
use alloy_json_rpc::RpcObject;
|
||||
use alloy_primitives::{Address, Bytes, B256};
|
||||
use alloy_rpc_types_debug::ExecutionWitness;
|
||||
use alloy_rpc_types_eth::{Block, Bundle, StateContext};
|
||||
use alloy_rpc_types_eth::{Bundle, StateContext};
|
||||
use alloy_rpc_types_trace::geth::{
|
||||
BlockTraceResult, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult,
|
||||
};
|
||||
@@ -38,7 +38,7 @@ pub trait DebugApi<TxReq: RpcObject> {
|
||||
|
||||
/// Returns an array of recent bad blocks that the client has seen on the network.
|
||||
#[method(name = "getBadBlocks")]
|
||||
async fn bad_blocks(&self) -> RpcResult<Vec<Block>>;
|
||||
async fn bad_blocks(&self) -> RpcResult<Vec<serde_json::Value>>;
|
||||
|
||||
/// Returns the structured logs created during the execution of EVM between two blocks
|
||||
/// (excluding start) as a JSON object.
|
||||
|
||||
@@ -25,11 +25,14 @@ mod net;
|
||||
mod otterscan;
|
||||
mod reth;
|
||||
mod rpc;
|
||||
mod testing;
|
||||
mod trace;
|
||||
mod txpool;
|
||||
mod validation;
|
||||
mod web3;
|
||||
|
||||
pub use testing::{TestingBuildBlockRequestV1, TESTING_BUILD_BLOCK_V1};
|
||||
|
||||
/// re-export of all server traits
|
||||
pub use servers::*;
|
||||
|
||||
@@ -45,6 +48,7 @@ pub mod servers {
|
||||
otterscan::OtterscanServer,
|
||||
reth::RethApiServer,
|
||||
rpc::RpcApiServer,
|
||||
testing::TestingApiServer,
|
||||
trace::TraceApiServer,
|
||||
txpool::TxPoolApiServer,
|
||||
validation::BlockSubmissionValidationApiServer,
|
||||
@@ -75,6 +79,7 @@ pub mod clients {
|
||||
otterscan::OtterscanClient,
|
||||
reth::RethApiClient,
|
||||
rpc::RpcApiServer,
|
||||
testing::TestingApiClient,
|
||||
trace::TraceApiClient,
|
||||
txpool::TxPoolApiClient,
|
||||
validation::BlockSubmissionValidationApiClient,
|
||||
|
||||
45
crates/rpc/rpc-api/src/testing.rs
Normal file
45
crates/rpc/rpc-api/src/testing.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
//! Testing namespace for building a block in a single call.
|
||||
//!
|
||||
//! This follows the `testing_buildBlockV1` specification. **Highly sensitive:**
|
||||
//! testing-only, powerful enough to include arbitrary transactions; must stay
|
||||
//! disabled by default and never be exposed on public-facing RPC without an
|
||||
//! explicit operator flag.
|
||||
|
||||
use alloy_primitives::{Bytes, B256};
|
||||
use alloy_rpc_types_engine::{
|
||||
ExecutionPayloadEnvelopeV5, PayloadAttributes as EthPayloadAttributes,
|
||||
};
|
||||
use jsonrpsee::proc_macros::rpc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Capability string for `testing_buildBlockV1`.
|
||||
pub const TESTING_BUILD_BLOCK_V1: &str = "testing_buildBlockV1";
|
||||
|
||||
/// Request payload for `testing_buildBlockV1`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TestingBuildBlockRequestV1 {
|
||||
/// Parent block hash of the block to build.
|
||||
pub parent_block_hash: B256,
|
||||
/// Payload attributes (Cancun version).
|
||||
pub payload_attributes: EthPayloadAttributes,
|
||||
/// Raw signed transactions to force-include in order.
|
||||
pub transactions: Vec<Bytes>,
|
||||
/// Optional extra data for the block header.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub extra_data: Option<Bytes>,
|
||||
}
|
||||
|
||||
/// Testing RPC interface for building a block in a single call.
|
||||
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "testing"))]
|
||||
#[cfg_attr(feature = "client", rpc(server, client, namespace = "testing"))]
|
||||
pub trait TestingApi {
|
||||
/// Builds a block using the provided parent, payload attributes, and transactions.
|
||||
///
|
||||
/// See <https://github.com/marcindsobczak/execution-apis/blob/main/src/testing/testing_buildBlockV1.md>
|
||||
#[method(name = "buildBlockV1")]
|
||||
async fn build_block_v1(
|
||||
&self,
|
||||
request: TestingBuildBlockRequestV1,
|
||||
) -> jsonrpsee::core::RpcResult<ExecutionPayloadEnvelopeV5>;
|
||||
}
|
||||
@@ -17,6 +17,7 @@ reth-primitives-traits.workspace = true
|
||||
reth-ipc.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
reth-consensus.workspace = true
|
||||
reth-engine-primitives.workspace = true
|
||||
reth-network-api.workspace = true
|
||||
reth-node-core.workspace = true
|
||||
reth-rpc.workspace = true
|
||||
@@ -26,6 +27,7 @@ reth-rpc-layer.workspace = true
|
||||
reth-rpc-eth-types.workspace = true
|
||||
reth-rpc-server-types.workspace = true
|
||||
reth-tasks = { workspace = true, features = ["rayon"] }
|
||||
reth-tokio-util.workspace = true
|
||||
reth-transaction-pool.workspace = true
|
||||
reth-storage-api.workspace = true
|
||||
reth-chain-state.workspace = true
|
||||
@@ -63,7 +65,6 @@ reth-rpc-api = { workspace = true, features = ["client"] }
|
||||
reth-rpc-engine-api.workspace = true
|
||||
reth-tracing.workspace = true
|
||||
reth-transaction-pool = { workspace = true, features = ["test-utils"] }
|
||||
reth-engine-primitives.workspace = true
|
||||
reth-node-ethereum.workspace = true
|
||||
|
||||
alloy-primitives.workspace = true
|
||||
|
||||
@@ -94,6 +94,7 @@ impl RethRpcServerConfig for RpcServerArgs {
|
||||
fn eth_config(&self) -> EthConfig {
|
||||
EthConfig::default()
|
||||
.max_tracing_requests(self.rpc_max_tracing_requests)
|
||||
.max_blocking_io_requests(self.rpc_max_blocking_io_requests)
|
||||
.max_trace_filter_blocks(self.rpc_max_trace_filter_blocks)
|
||||
.max_blocks_per_filter(self.rpc_max_blocks_per_filter.unwrap_or_max())
|
||||
.max_logs_per_response(self.rpc_max_logs_per_response.unwrap_or_max() as usize)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user