Compare commits

...

79 Commits

Author SHA1 Message Date
Ishika Choudhury
473deed90d chore: fix bal devnet 2 (#23141)
Co-authored-by: Soubhik Singha Mahapatra <soubhiksmp2004@gmail.com>
Co-authored-by: stevencartavia <112043913+stevencartavia@users.noreply.github.com>
Co-authored-by: Emma Jamieson-Hoare <ejamieson19@gmail.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-03-23 11:12:27 +00:00
Emma Jamieson-Hoare
61dd104871 Merge remote-tracking branch 'origin/main' into bal-devnet-2
Amp-Thread-ID: https://ampcode.com/threads/T-019d0bad-ef5a-716a-914d-62f3b017eada
Co-authored-by: Amp <amp@ampcode.com>

# Conflicts:
#	.github/workflows/hive.yml
#	Cargo.lock
#	Cargo.toml
#	bin/reth-bench/src/bench/helpers.rs
#	bin/reth-bench/src/bench/persistence_waiter.rs
#	crates/engine/primitives/src/config.rs
#	crates/node/core/src/args/engine.rs
2026-03-20 15:07:27 +00:00
Ishika Choudhury
0632bc72c9 feat: fix devnet2(BAL) (#22988)
Co-authored-by: Soubhik Singha Mahapatra <soubhiksmp2004@gmail.com>
Co-authored-by: Emma Jamieson-Hoare <emmajam@users.noreply.github.com>
Co-authored-by: Emma Jamieson-Hoare <ejamieson19@gmail.com>
Co-authored-by: Soubhik Singha Mahapatra <160333583+Soubhik-10@users.noreply.github.com>
2026-03-13 12:40:09 +01:00
Emma Jamieson-Hoare
2fb2246579 chore: merge main and resolve Cargo.lock conflict
Amp-Thread-ID: https://ampcode.com/threads/T-019cd35b-fa36-71cc-84d0-90b13ee9dfb9
Co-authored-by: Amp <amp@ampcode.com>
2026-03-09 16:32:10 +00:00
Emma Jamieson-Hoare
4174045d47 fix lockfile 2026-03-09 16:26:07 +00:00
Emma Jamieson-Hoare
81262c0057 Merge remote-tracking branch 'origin/main' into bal-devnet-2
Amp-Thread-ID: https://ampcode.com/threads/T-019cd250-92a0-730a-9fac-7b7b326134a4
Co-authored-by: Amp <amp@ampcode.com>

# Conflicts:
#	.github/scripts/hive/expected_failures.yaml
#	Cargo.lock
#	Cargo.toml
#	crates/engine/tree/src/tree/payload_validator.rs
#	crates/ethereum/evm/src/lib.rs
#	crates/evm/evm/src/execute.rs
#	crates/primitives-traits/src/account.rs
#	crates/revm/src/witness.rs
#	crates/rpc/rpc-eth-api/src/helpers/estimate.rs
#	crates/storage/provider/src/providers/database/provider.rs
2026-03-09 11:42:59 +00:00
Emma Jamieson-Hoare
4250314722 feat: add cli flags for bal (#22777) 2026-03-04 16:24:51 +00:00
Stefan
b07c223530 fix: defer insert_state until after block validation to prevent cache race (#22199)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:24:23 +00:00
Emma Jamieson-Hoare
49c05aed05 fix hive tests 2026-02-27 17:22:46 +00:00
Emma Jamieson-Hoare
a600f08593 fix tests 2026-02-27 16:51:12 +00:00
Emma Jamieson-Hoare
b5c1e0d08e fix book job 2026-02-27 16:13:55 +00:00
Emma Jamieson-Hoare
accf15e2e4 fix lockfile 2026-02-27 16:03:51 +00:00
Emma Jamieson-Hoare
e794626df6 chore: update lockfile 2026-02-27 15:57:46 +00:00
Emma Jamieson-Hoare
2e9d969033 Merge remote-tracking branch 'origin/main' into bal-devnet-2
Amp-Thread-ID: https://ampcode.com/threads/T-019c9fc0-77ab-76c8-ad48-2eb18aea3ba5
Co-authored-by: Amp <amp@ampcode.com>

# Conflicts:
#	Cargo.lock
2026-02-27 15:39:56 +00:00
Emma Jamieson-Hoare
3e85ec2670 chore: fix hive tests 2026-02-27 15:23:18 +00:00
Emma Jamieson-Hoare
8c5b6c9b15 chore: fix hive failures (#22643) 2026-02-27 13:53:59 +00:00
Emma Jamieson-Hoare
a66d49c190 Merge branch 'main' into bal-devnet-2 2026-02-27 11:32:19 +00:00
Emma Jamieson-Hoare
ab2252c33d fix merge issues 2026-02-27 11:22:03 +00:00
Emma Jamieson-Hoare
8dbb015770 Merge remote-tracking branch 'origin/main' into bal-devnet-2 2026-02-27 11:07:57 +00:00
Ishika Choudhury
96be836679 chore: expected failing test for devnet 2 bal (#22453)
Co-authored-by: Soubhik Singha Mahapatra <soubhiksmp2004@gmail.com>
Co-authored-by: Soubhik Singha Mahapatra <160333583+Soubhik-10@users.noreply.github.com>
2026-02-27 10:56:20 +00:00
Emma Jamieson-Hoare
ab5f2db594 Merge branch 'main' into bal-devnet-2 2026-02-23 15:46:05 +00:00
Emma Jamieson-Hoare
6a633a42f0 fix: handle EIP-7778 gas accounting mismatch in payload builder (#22490)
Co-authored-by: Amp <amp@ampcode.com>
2026-02-23 13:51:48 +01:00
Emma Jamieson-Hoare
08fd55d8c9 ci: use larger runner for hive reth builds
Amp-Thread-ID: https://ampcode.com/threads/T-019c7acf-3e9a-7459-8100-dae97ec43d52
Co-authored-by: Amp <amp@ampcode.com>
2026-02-20 11:59:27 +00:00
Emma Jamieson-Hoare
fab95c1f3a Merge branch 'main' into bal-devnet-2 2026-02-20 11:13:52 +00:00
Emma Jamieson-Hoare
e4191ccea8 Merge branch 'main' into bal-devnet-2 2026-02-19 10:27:42 +00:00
Ishika Choudhury
080ff004e3 chore: fixed bal devnet error (#22325)
Co-authored-by: Soubhik Singha Mahapatra <soubhiksmp2004@gmail.com>
2026-02-18 18:36:22 +01:00
Emma Jamieson-Hoare
18599f1732 Merge branch 'main' into bal-devnet-2 2026-02-18 12:47:57 +00:00
Emma Jamieson-Hoare
9fd35e2917 Revert "chore: merge main into devnet-2 branch (#22316)"
This reverts commit c1a5e20b50.
2026-02-18 12:40:23 +00:00
Emma Jamieson-Hoare
c1a5e20b50 chore: merge main into devnet-2 branch (#22316) 2026-02-18 12:39:07 +00:00
Ishika Choudhury
0ff16ea053 chore: fix failing tests(hive) for devnet 2 BAL (#22259) 2026-02-18 11:17:01 +01:00
Emma Jamieson-Hoare
3541bd7f65 fix rust issue 2026-02-17 12:52:09 +00:00
Emma Jamieson-Hoare
a3aec0c662 merge: resolve conflict with main in payload_validator.rs
Amp-Thread-ID: https://ampcode.com/threads/T-019c6b9f-1ef5-76f8-bc77-7547d5460bf8
Co-authored-by: Amp <amp@ampcode.com>
2026-02-17 12:42:29 +00:00
Emma Jamieson-Hoare
0dfdaca3f0 Merge branch 'main' into bal-devnet-2 2026-02-17 11:20:26 +00:00
Emma Jamieson-Hoare
c535a7fb5b Merge branch 'main' into bal-devnet-2 2026-02-16 12:26:52 -05:00
Soubhik Singha Mahapatra
bf6270b8a3 chore: try validation of bal after execution (#22165)
Co-authored-by: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Co-authored-by: Emma Jamieson-Hoare <ejamieson19@gmail.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-02-16 18:25:20 +01:00
jenpaff
1e78685a6c fix: resolve clippy and build issues from revm hashmap changes
- Fix doc-markdown warnings in validation.rs (backtick identifiers)
- Fix StorageKeyMap type mismatch from revm specialized hashmaps
- Remove unused HashMap import

Amp-Thread-ID: https://ampcode.com/threads/T-019c66b1-1100-777b-98e4-42a7e5d2be57
Co-authored-by: Amp <amp@ampcode.com>
2026-02-16 15:53:25 +00:00
jenpaff
1f1e320643 fix: gate BytecodeKind import behind reth-codec feature
Fixes cargo hack --no-default-features check for reth-primitives-traits.

Amp-Thread-ID: https://ampcode.com/threads/T-019c66b1-1100-777b-98e4-42a7e5d2be57
Co-authored-by: Amp <amp@ampcode.com>
2026-02-16 14:38:44 +00:00
jenpaff
74ea20400e fix: add block_access_list field to BlockExecutionResult initializers
Required by alloy-evm #287 (EIP-7928). Set to None/default for now.

Amp-Thread-ID: https://ampcode.com/threads/T-019c66b1-1100-777b-98e4-42a7e5d2be57
Co-authored-by: Amp <amp@ampcode.com>
2026-02-16 14:32:20 +00:00
jenpaff
ffff5fbce2 Merge remote-tracking branch 'origin/main' into bal-devnet-2
Amp-Thread-ID: https://ampcode.com/threads/T-019c66b1-1100-777b-98e4-42a7e5d2be57
Co-authored-by: Amp <amp@ampcode.com>

# Conflicts:
#	Cargo.lock
#	crates/rpc/rpc-engine-api/src/engine_api.rs
2026-02-16 13:51:39 +00:00
jenpaff
f514892b41 Merge remote-tracking branch 'origin/bal-devnet-2' into bal-devnet-2
Amp-Thread-ID: https://ampcode.com/threads/T-019c66b1-1100-777b-98e4-42a7e5d2be57
Co-authored-by: Amp <amp@ampcode.com>

# Conflicts:
#	Cargo.lock
2026-02-16 13:50:56 +00:00
Soubhik Singha Mahapatra
d0ad4b0e18 chore: gas traces for failing tests (#21943)
Co-authored-by: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com>
2026-02-13 13:28:55 +01:00
jenpaff
cb6ed16485 chore: merge main into bal-devnet-2
Merge main into bal-devnet-2 to resolve conflicts. Key resolutions:
- Removed deleted optimism, stateless, and custom-node files (removed on main)
- Downgraded alloy workspace versions to 1.5.2 to match bal-devnet2 patches
- Added comprehensive alloy bal-devnet2 patches for all alloy crates
- Added ExecutionPayloadBodiesV2/BodyV2 type aliases (pending alloy support)
- Adapted reth-bench V4/V5 payload handling for alloy 1.5.2 API
- Kept BAL-specific changes (EIP-7778, EIP-7928)

Amp-Thread-ID: https://ampcode.com/threads/T-019c5311-f28a-7584-8224-29e16e5095c1
Co-authored-by: Amp <amp@ampcode.com>
2026-02-12 13:40:29 -05:00
Stefan
a88eef91f4 fix: pass slot_number in next_evm_env for block building (#21945)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-02-07 18:24:57 +01:00
Ishika Choudhury
f7e7afd51f chore: slot num fixes and error mapping (#21940)
Co-authored-by: Soubhik Singha Mahapatra <soubhiksmp2004@gmail.com>
2026-02-07 14:35:49 +01:00
Matthias Seitz
102764285b chore: update alloy-evm
Amp-Thread-ID: https://ampcode.com/threads/T-019c2ed0-8d62-7649-b718-257fd74ce3ce
Co-authored-by: Amp <amp@ampcode.com>
2026-02-05 18:21:00 +01:00
Matthias Seitz
4679c86003 bump evm 2026-02-04 19:41:37 +01:00
Stefan
7671838c61 fix: EIP-7778 gas accounting in receipts and block validation (#21821)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 19:18:59 +01:00
Soubhik Singha Mahapatra
8f4461c060 chore: update fixture for bal test (#21787)
Co-authored-by: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com>
2026-02-04 18:08:15 +01:00
Matthias Seitz
0119f3c612 bump lock 2026-02-04 13:41:10 +01:00
Stefan
094aaef5a1 fix: add engine_forkchoiceUpdatedV4 to capabilities list (#21799)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 13:29:24 +01:00
Matthias Seitz
32d03ff4d7 chore: update revm to 6aa06829d2caa2aa38606ed22b83354a7a7ff98e
Amp-Thread-ID: https://ampcode.com/threads/T-019c2389-3d07-76c9-a09f-e21b588a135c
Co-authored-by: Amp <amp@ampcode.com>
2026-02-03 13:48:25 +01:00
Matthias Seitz
3368ce6485 chore: update alloy-evm to 394f0ecf (EIP-7778 is_amsterdam fix)
Amp-Thread-ID: https://ampcode.com/threads/T-019c1e41-4c08-74bd-8901-5037d92e6fac
Co-authored-by: Amp <amp@ampcode.com>
2026-02-02 13:18:21 +01:00
Jennifer
9bc2388871 Fix bal fcu validation (#21679)
Co-authored-by: Amp <amp@ampcode.com>
2026-02-01 20:49:50 +01:00
Matthias Seitz
1728fa97c0 bump revs 2026-01-30 15:26:49 +01:00
Ishika Choudhury
868248ec54 feat: add fcu and fixes (#21567)
Co-authored-by: Soubhik Singha Mahapatra <soubhiksmp2004@gmail.com>
2026-01-29 13:29:33 +01:00
Matthias Seitz
16ab4b8518 chore: update revm to f3b74d4ff0c6c88a09ca281323a100257fa61ebf
Amp-Thread-ID: https://ampcode.com/threads/T-019c05af-57ea-72ab-b16a-57cfaf907a9e
Co-authored-by: Amp <amp@ampcode.com>
2026-01-28 18:40:26 +01:00
Matthias Seitz
ce74466b93 chore: update EEST fixtures to bal@v5.0.0
Amp-Thread-ID: https://ampcode.com/threads/T-019bff17-51e0-775f-840e-e67a55fc347c
Co-authored-by: Amp <amp@ampcode.com>
2026-01-27 11:56:00 +01:00
Matthias Seitz
992fc30ff5 refactor: use GotExpectedBoxed for BlockAccessListHashMismatch
Amp-Thread-ID: https://ampcode.com/threads/T-019bfc38-6e25-7093-8775-7764904c7e88
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 23:10:21 +01:00
Matthias Seitz
3ece6b6047 refactor: use with_bal_builder_if instead of conditional
Amp-Thread-ID: https://ampcode.com/threads/T-019bfc38-6e25-7093-8775-7764904c7e88
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 22:53:36 +01:00
Matthias Seitz
dec9f93ad1 fix: use block_hashes.lowest() to get lowest block number
Amp-Thread-ID: https://ampcode.com/threads/T-019bfc38-6e25-7093-8775-7764904c7e88
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 22:51:48 +01:00
Matthias Seitz
03484f76ec chore: update revm to 300efbf3e391e1796f5210cd4506508e385a55d2
Amp-Thread-ID: https://ampcode.com/threads/T-019bfc38-6e25-7093-8775-7764904c7e88
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 22:50:08 +01:00
Matthias Seitz
b870f04509 chore: update alloy to fix ExecutionPayload V4 deserializer
Amp-Thread-ID: https://ampcode.com/threads/T-019bfbfc-d6f6-73ec-b044-919aa35326fc
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 21:28:18 +01:00
Matthias Seitz
5277e59cc4 feat: validate BAL hash after block execution
- Add BlockAccessListHashMismatch variant to ConsensusError
- After execution, compute hash of built BAL and compare with expected BAL hash
- Return consensus error if hashes don't match

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb9c-5974-732a-8101-32f6711e7d31
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 19:57:30 +01:00
Matthias Seitz
6271c2702f feat: add BAL support to engine tree payload validator
- Enable with_bal_builder() in execute_block when payload contains block access list
- Decode BlockAccessList from payload bytes in BlockOrPayload::block_access_list()
- Bump BAL index after pre-execution changes and after each transaction
- Add ExecutionPayload trait bound for block_access_list() method

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb9c-5974-732a-8101-32f6711e7d31
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 19:52:17 +01:00
Matthias Seitz
ce15ab9f55 chore: update hive build_simulators.sh for BAL devnet
- Use bal@v4.0.0 fixtures for ethereum/eels simulator
- Add branch=eips/amsterdam/eip-7928 buildarg

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb5b-9488-7388-95a2-5b93e1b3e9eb
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 19:40:55 +01:00
Matthias Seitz
0b1ec2dc89 docs: add missing docs for Amsterdam engine API endpoints
- Add doc comments for new_payload_v5 and get_payload_v6 methods
- Include links to the Amsterdam spec

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb5b-9488-7388-95a2-5b93e1b3e9eb
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 19:34:59 +01:00
Matthias Seitz
5862c72880 chore: add block_access_list_hash and slot_number to HeaderExt
- Update HeaderExt to include new Amsterdam fields
- Fix EthBuiltPayload doctest to pass 5th argument
- Update Compact impl for AlloyHeader to handle new fields

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb5b-9488-7388-95a2-5b93e1b3e9eb
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 19:23:11 +01:00
Matthias Seitz
8a7655ca5d chore: docs 2026-01-26 19:06:13 +01:00
Matthias Seitz
cd20adc1d4 chore: alloc 2026-01-26 19:05:13 +01:00
Matthias Seitz
f0fe45d6bf chore: fix compilation issues after BAL revert
- Remove block_access_list from BlockExecutionResult (handled in reth)
- Add block_access_list_hash and slot_number to Header initializations
- Add slot_number to PayloadAttributes initializations
- Fix clippy doc markdown warnings
- Remove unused alloy-rlp dependency from reth-evm-ethereum

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb5b-9488-7388-95a2-5b93e1b3e9eb
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 18:40:46 +01:00
Matthias Seitz
00422207f4 feat: add slot_number support and enable BAL builder for Amsterdam
- Forward slot_number from PayloadAttributes to EthPayloadBuilderAttributes
- Enable BAL builder in State when Amsterdam is active
- Pin alloy-evm to rev 3df0a06 (before block_access_list in BlockExecutionResult)
- Set block_access_list_hash to None temporarily until BAL extraction is implemented

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb3d-e550-767e-9df1-f6987376dbc1
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 18:05:00 +01:00
Matthias Seitz
28a94829e9 feat(consensus): add Amsterdam header field validation
- Add BlockAccessListHashMissing, BlockAccessListHashUnexpected,
  SlotNumberMissing, SlotNumberUnexpected to ConsensusError
- Add validate_amsterdam_header_fields() to consensus-common
- Clean up amsterdam.rs in payload-validator

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb00-a1a7-7601-9dd6-d26171b03370
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 17:37:02 +01:00
Matthias Seitz
e081249f65 fix(engine-api): restore is_critical_method and add V5/V6 capabilities
Amp-Thread-ID: https://ampcode.com/threads/T-019bfb00-a1a7-7601-9dd6-d26171b03370
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 17:10:27 +01:00
Matthias Seitz
99fedf01f8 feat(chainspec): add Amsterdam hardfork support
- Add EMPTY_BLOCK_ACCESS_LIST_HASH constant
- Set block_access_list_hash in genesis header when Amsterdam is active
- Add amsterdam_time to create_chain_config
- Add Amsterdam to time_hardfork_opts in From<Genesis> for ChainSpec
- Add amsterdam_activated() and with_amsterdam_at() builder methods

Amp-Thread-ID: https://ampcode.com/threads/T-019bfb00-a1a7-7601-9dd6-d26171b03370
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 17:07:55 +01:00
Matthias Seitz
179e1bfc34 feat: integrate BAL devnet2 changes
- Add dependency patches for revm staging, alloy/op-alloy bal-devnet2 branches
- Cherry-pick engine API changes from PR 21203 (capabilities, engine_api, metrics, payload primitives)
- Add block_access_list_hash and slot_number fields to Header initializations
- Add slot_number field to PayloadAttributes initializations
- Update EthBuiltPayload::new() signature with block_access_list parameter
- Handle ExecutionPayload::V4 and EngineApiMessageVersion::V6 variants
- Add amsterdam payload validator

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Amp-Thread-ID: https://ampcode.com/threads/T-019bfb00-a1a7-7601-9dd6-d26171b03370
Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 17:01:51 +01:00
Matthias Seitz
3adb5b9e58 Merge remote-tracking branch 'origin/staging' into bal-devnet-2 2026-01-26 16:42:55 +01:00
rakita
57d7c98f66 chore: merge main and update alloy-evm staging patch 2026-01-26 12:39:58 +01:00
rakita
5d9a43f2d4 Merge remote-tracking branch 'origin/main' into staging 2026-01-26 12:36:44 +01:00
rakita
defd0e8e5c Bump revm to staging and fix breaking changes
- Patch revm and all sub-crates to staging commit 0dc217a9
- Patch revm-inspectors to staging commit fccc4ac5
- Patch alloy-evm to staging commit 625ccc0f
- Add slot_num field to BlockEnv initializers
- Update BlockHashCache usage (no longer has keys method)
2026-01-26 02:41:26 +01:00
81 changed files with 1550 additions and 351 deletions

View File

@@ -3,7 +3,7 @@
#
# We'll use cargo-chef to speed up the build
#
FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef
FROM lukemathwalker/cargo-chef:latest-rust-1.94.0-trixie AS chef
WORKDIR /app
# Install system dependencies

View File

@@ -9,10 +9,17 @@ go build .
./hive -client reth # first builds and caches the client
# Run each hive command in the background for each simulator and wait
# Run each hive command in the background for each simulator and wait
echo "Building images"
# TODO: test code has been moved from https://github.com/ethereum/execution-spec-tests to https://github.com/ethereum/execution-specs we need to pin eels branch with `--sim.buildarg branch=<release-branch-name>` once we have the fusaka release tagged on the new repo
./hive -client reth --sim "ethereum/eels" --sim.buildarg fixtures=https://github.com/ethereum/execution-spec-tests/releases/download/v5.3.0/fixtures_develop.tar.gz -sim.timelimit 1s || true &
./hive -client reth --sim "ethereum/eels/consume-engine" \
--sim.buildarg fixtures=https://github.com/ethereum/execution-spec-tests/releases/download/bal@v5.1.0/fixtures_bal.tar.gz \
--sim.buildarg branch=err-map-3 \
--sim.timelimit 1s || true &
./hive -client reth --sim "ethereum/eels/consume-rlp" \
--sim.buildarg fixtures=https://github.com/ethereum/execution-spec-tests/releases/download/bal@v5.1.0/fixtures_bal.tar.gz \
--sim.buildarg branch=err-map-3 \
--sim.timelimit 1s || true &
./hive -client reth --sim "ethereum/engine" -sim.timelimit 1s || true &
./hive -client reth --sim "devp2p" -sim.timelimit 1s || true &
./hive -client reth --sim "ethereum/rpc-compat" -sim.timelimit 1s || true &

View File

@@ -16,15 +16,19 @@ rpc-compat:
# syncing mode, the test expects syncing to be false on start
- eth_syncing/check-syncing (reth)
engine-withdrawals: [ ]
engine-withdrawals: []
engine-api: [ ]
engine-api: []
engine-cancun: [ ]
engine-cancun:
- Invalid PayloadAttributes, Missing BeaconRoot, Syncing=True (Cancun) (reth)
# the test fails with older versions of the code for which it passed before, probably related to changes
# in hive or its dependencies
- Blob Transaction Ordering, Multiple Clients (Cancun) (reth)
sync: [ ]
sync: []
engine-auth: [ ]
engine-auth: []
# EIP-7610 related tests (Revert creation in case of non-empty storage):
#
@@ -42,6 +46,10 @@ engine-auth: [ ]
#
# System contract tests (already fixed and deployed):
#
# tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout and test_invalid_log_length
# System contract is already fixed and deployed; tests cover scenarios where contract is
# malformed which can't happen retroactively. No point in adding checks.
#
# tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py::test_system_contract_deployment
# tests/prague/eip7251_consolidations/test_contract_deployment.py::test_system_contract_deployment
# Post-fork system contract deployment tests. Should fix for spec compliance but not realistic
@@ -50,8 +58,44 @@ eels/consume-engine:
- tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_non_empty_storage[fork_Prague-blockchain_test_engine-zero_nonce]-reth
- tests/prague/eip7251_consolidations/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test_engine-deploy_after_fork-nonzero_balance]-reth
- tests/prague/eip7251_consolidations/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test_engine-deploy_after_fork-zero_balance]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_amount_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_amount_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_index_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_index_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_pubkey_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_pubkey_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_signature_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_signature_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_withdrawal_credentials_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Prague-blockchain_test_engine-log_argument_withdrawal_credentials_size-value_zero]-reth
- tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test_engine-deploy_after_fork-nonzero_balance]-reth
- tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test_engine-deploy_after_fork-zero_balance]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_log_length[fork_Prague-blockchain_test_engine-slice_bytes_False]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_log_length[fork_Prague-blockchain_test_engine-slice_bytes_True]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_amount_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_amount_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_index_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_index_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_pubkey_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_pubkey_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_signature_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_signature_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_withdrawal_credentials_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Osaka-blockchain_test_engine-log_argument_withdrawal_credentials_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_log_length[fork_Osaka-blockchain_test_engine-slice_bytes_False]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_log_length[fork_Osaka-blockchain_test_engine-slice_bytes_True]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_index_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_index_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_log_length[fork_Amsterdam-blockchain_test_engine-slice_bytes_True]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_log_length[fork_Amsterdam-blockchain_test_engine-slice_bytes_False]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_pubkey_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_pubkey_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_withdrawal_credentials_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_withdrawal_credentials_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_amount_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_amount_offset-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_signature_size-value_zero]-reth
- tests/prague/eip6110_deposits/test_modified_contract.py::test_invalid_layout[fork_Amsterdam-blockchain_test_engine-log_argument_signature_offset-value_zero]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Osaka-tx_type_0-blockchain_test_engine_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Prague-tx_type_0-blockchain_test_engine_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Paris-tx_type_1-blockchain_test_engine_from_state_test-non-empty-balance-correct-initcode]-reth
@@ -102,6 +146,20 @@ eels/consume-engine:
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Prague-tx_type_1-blockchain_test_engine_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Prague-tx_type_2-blockchain_test_engine_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Shanghai-tx_type_0-blockchain_test_engine_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_opcode[fork_Amsterdam-blockchain_test_engine_from_state_test-opcode_CREATE2-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_revert_in_create.py::test_collision_with_create2_revert_in_initcode[fork_Amsterdam-blockchain_test_engine_from_state_test]-reth
- tests/paris/eip7610_create_collision/test_revert_in_create.py::test_create2_collision_storage[fork_Amsterdam-blockchain_test_engine_from_state_test-initcode-with-deploy]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_opcode[fork_Amsterdam-blockchain_test_engine_from_state_test-opcode_CREATE2-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_revert_in_create.py::test_create2_collision_storage[fork_Amsterdam-blockchain_test_engine_from_state_test-empty-initcode]-reth
- tests/paris/eip7610_create_collision/test_revert_in_create.py::test_create2_collision_storage[fork_Amsterdam-blockchain_test_engine_from_state_test-sstore-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_2-blockchain_test_engine_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_2-blockchain_test_engine_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_1-blockchain_test_engine_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_1-blockchain_test_engine_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_opcode[fork_Amsterdam-blockchain_test_engine_from_state_test-opcode_CREATE-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_0-blockchain_test_engine_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_0-blockchain_test_engine_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_opcode[fork_Amsterdam-blockchain_test_engine_from_state_test-opcode_CREATE-non-empty-balance-revert-initcode]-reth
# Blob limit tests:
#
@@ -196,3 +254,17 @@ eels/consume-rlp:
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Prague-tx_type_1-blockchain_test_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Prague-tx_type_2-blockchain_test_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Shanghai-tx_type_0-blockchain_test_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_revert_in_create.py::test_create2_collision_storage[fork_Amsterdam-blockchain_test_from_state_test-initcode-with-deploy]-reth
- tests/paris/eip7610_create_collision/test_revert_in_create.py::test_create2_collision_storage[fork_Amsterdam-blockchain_test_from_state_test-sstore-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_2-blockchain_test_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_2-blockchain_test_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_1-blockchain_test_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_revert_in_create.py::test_collision_with_create2_revert_in_initcode[fork_Amsterdam-blockchain_test_from_state_test]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_1-blockchain_test_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_0-blockchain_test_from_state_test-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_tx[fork_Amsterdam-tx_type_0-blockchain_test_from_state_test-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_opcode[fork_Amsterdam-blockchain_test_from_state_test-opcode_CREATE-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_opcode[fork_Amsterdam-blockchain_test_from_state_test-opcode_CREATE-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_opcode[fork_Amsterdam-blockchain_test_from_state_test-opcode_CREATE2-non-empty-balance-correct-initcode]-reth
- tests/paris/eip7610_create_collision/test_initcollision.py::test_init_collision_create_opcode[fork_Amsterdam-blockchain_test_from_state_test-opcode_CREATE2-non-empty-balance-revert-initcode]-reth
- tests/paris/eip7610_create_collision/test_revert_in_create.py::test_create2_collision_storage[fork_Amsterdam-blockchain_test_from_state_test-empty-initcode]-reth

View File

@@ -13,7 +13,13 @@ if [[ "${sim}" == *"eels"* ]]; then
fi
run_hive() {
hive --sim "${sim}" --sim.limit "${limit}" --sim.parallelism "${parallelism}" --client reth 2>&1 | tee /tmp/log || true
hive \
--sim "${sim}" \
--sim.limit "${limit}" \
--sim.limit.exact=false \
--sim.parallelism "${parallelism}" \
--client reth \
2>&1 | tee /tmp/log || true
}
check_log() {

View File

@@ -79,4 +79,4 @@ jobs:
uses: actions/upload-artifact@v7
with:
name: ${{ inputs.artifact_name }}
path: ./artifacts
path: ./artifacts

View File

@@ -5,7 +5,10 @@ name: hive
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
- cron: "0 */6 * * *"
pull_request:
branches:
- "**"
env:
CARGO_TERM_COLOR: always
@@ -15,23 +18,26 @@ concurrency:
cancel-in-progress: true
jobs:
build-reth:
uses: ./.github/workflows/docker-test.yml
prepare-reth-stable:
uses: ./.github/workflows/prepare-reth.yml
with:
hive_target: hive
artifact_name: "reth"
secrets: inherit
image_tag: ghcr.io/paradigmxyz/reth:latest
binary_name: reth
cargo_features: "asm-keccak"
artifact_name: "reth-stable"
prepare-hive:
if: github.repository == 'paradigmxyz/reth'
timeout-minutes: 45
runs-on: ${{ github.repository == 'paradigmxyz/reth' && 'depot-ubuntu-latest-4' || 'ubuntu-latest' }}
runs-on:
group: Reth
steps:
- uses: actions/checkout@v6
- name: Checkout hive tests
uses: actions/checkout@v6
with:
repository: ethereum/hive
repository: Soubhik-10/hive # rm later and use ethereum/hive
ref: master
path: hivetests
- name: Get hive commit hash
@@ -77,6 +83,7 @@ jobs:
strategy:
fail-fast: false
matrix:
storage: [stable]
# ethereum/rpc to be deprecated:
# https://github.com/ethereum/hive/pull/1117
scenario:
@@ -117,26 +124,28 @@ jobs:
- sim: ethereum/rpc-compat
include:
- eth_blockNumber
- eth_call
- eth_chainId
- eth_createAccessList
- eth_estimateGas
- eth_feeHistory
- eth_getBalance
- eth_getBlockBy
- eth_getBlockTransactionCountBy
- eth_getCode
- eth_getProof
- eth_getStorage
- eth_getTransactionBy
- eth_getTransactionCount
- eth_getTransactionReceipt
- eth_sendRawTransaction
- eth_syncing
# debug_ rpc methods
- debug_
# - eth_call
# - eth_chainId
# - eth_createAccessList
# - eth_estimateGas
# - eth_feeHistory
# - eth_getBalance
# - eth_getBlockBy
# - eth_getBlockTransactionCountBy
# - eth_getCode
# - eth_getProof
# - eth_getStorage
# - eth_getTransactionBy
# - eth_getTransactionCount
# - eth_getTransactionReceipt
# - eth_sendRawTransaction
# - eth_syncing
# # debug_ rpc methods
# - debug_
# consume-engine
- sim: ethereum/eels/consume-engine
limit: .*tests/amsterdam.*
- sim: ethereum/eels/consume-engine
limit: .*tests/osaka.*
- sim: ethereum/eels/consume-engine
@@ -157,6 +166,8 @@ jobs:
limit: .*tests/paris.*
# consume-rlp
- sim: ethereum/eels/consume-rlp
limit: .*tests/amsterdam.*
- sim: ethereum/eels/consume-rlp
limit: .*tests/osaka.*
- sim: ethereum/eels/consume-rlp
@@ -176,9 +187,9 @@ jobs:
- sim: ethereum/eels/consume-rlp
limit: .*tests/paris.*
needs:
- build-reth
- prepare-reth-stable
- prepare-hive
name: ${{ matrix.scenario.sim }}${{ matrix.scenario.limit && format(' - {0}', matrix.scenario.limit) }}
name: ${{ matrix.storage }} / ${{ matrix.scenario.sim }}${{ matrix.scenario.limit && format(' - {0}', matrix.scenario.limit) }}
# Use larger runners for eels tests to avoid OOM runner crashes
runs-on: ${{ github.repository == 'paradigmxyz/reth' && (contains(matrix.scenario.sim, 'eels') && 'depot-ubuntu-latest-8' || 'depot-ubuntu-latest-4') || 'ubuntu-latest' }}
permissions:
@@ -197,7 +208,7 @@ jobs:
- name: Download reth image
uses: actions/download-artifact@v8
with:
name: reth
name: reth-${{ matrix.storage }}
path: /tmp
- name: Load Docker images
@@ -211,7 +222,7 @@ jobs:
- name: Checkout hive tests
uses: actions/checkout@v6
with:
repository: ethereum/hive
repository: Soubhik-10/hive
ref: master
path: hivetests

61
.github/workflows/prepare-reth.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: Prepare Reth Image
on:
workflow_call:
inputs:
image_tag:
required: true
type: string
description: "Docker image tag to use"
binary_name:
required: false
type: string
default: "reth"
description: "Binary name to build (reth or op-reth)"
cargo_features:
required: false
type: string
default: "asm-keccak"
description: "Cargo features to enable"
cargo_package:
required: false
type: string
description: "Optional cargo package path"
artifact_name:
required: false
type: string
default: "artifacts"
description: "Name for the uploaded artifact"
jobs:
prepare-reth:
if: github.repository == 'paradigmxyz/reth'
timeout-minutes: 45
runs-on: depot-ubuntu-latest-4
steps:
- uses: actions/checkout@v6
- run: mkdir artifacts
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and export reth image
uses: docker/build-push-action@v6
with:
context: .
file: .github/scripts/hive/Dockerfile
tags: ${{ inputs.image_tag }}
outputs: type=docker,dest=./artifacts/reth_image.tar
build-args: |
CARGO_BIN=${{ inputs.binary_name }}
MANIFEST_PATH=${{ inputs.cargo_package }}
FEATURES=${{ inputs.cargo_features }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Upload reth image
id: upload
uses: actions/upload-artifact@v6
with:
name: ${{ inputs.artifact_name }}
path: ./artifacts

179
Cargo.lock generated
View File

@@ -122,8 +122,7 @@ dependencies = [
[[package]]
name = "alloy-consensus"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c0dc44157867da82c469c13186015b86abef209bf0e41625e4b68bac61d728"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -150,8 +149,7 @@ dependencies = [
[[package]]
name = "alloy-consensus-any"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba4cdb42df3871cd6b346d6a938ec2ba69a9a0f49d1f82714bc5c48349268434"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -165,8 +163,7 @@ dependencies = [
[[package]]
name = "alloy-contract"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca63b7125a981415898ffe2a2a696c83696c9c6bdb1671c8a912946bbd8e49e7"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus",
"alloy-dyn-abi",
@@ -263,8 +260,7 @@ dependencies = [
[[package]]
name = "alloy-eips"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f7ef09f21bd1e9cb8a686f168cb4a206646804567f0889eadb8dcc4c9288c8"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-eip2124",
"alloy-eip2930",
@@ -290,8 +286,7 @@ dependencies = [
[[package]]
name = "alloy-evm"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb6ba2dafd6327f78f2b59ae539bd5c39c57a01dc76763e92942619d934a7bb"
source = "git+https://github.com/alloy-rs/evm?branch=bal-devnet2#5ca2989a1fc18079ca29387c61c5e5b6d6150030"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -313,8 +308,7 @@ dependencies = [
[[package]]
name = "alloy-genesis"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c9cf3b99f46615fbf7dc1add0c96553abb7bf88fc9ec70dfbe7ad0b47ba7fe8"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -367,8 +361,7 @@ dependencies = [
[[package]]
name = "alloy-json-rpc"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff42cd777eea61f370c0b10f2648a1c81e0b783066cd7269228aa993afd487f7"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-primitives",
"alloy-sol-types",
@@ -382,8 +375,7 @@ dependencies = [
[[package]]
name = "alloy-network"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cbca04f9b410fdc51aaaf88433cbac761213905a65fe832058bcf6690585762"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus",
"alloy-consensus-any",
@@ -408,8 +400,7 @@ dependencies = [
[[package]]
name = "alloy-network-primitives"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42d6d15e069a8b11f56bef2eccbad2a873c6dd4d4c81d04dda29710f5ea52f04"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -421,8 +412,7 @@ dependencies = [
[[package]]
name = "alloy-node-bindings"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "091dc8117d84de3a9ac7ec97f2c4d83987e24d485b478d26aa1ec455d7d52f7d"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-genesis",
"alloy-hardforks 0.2.13",
@@ -486,8 +476,7 @@ dependencies = [
[[package]]
name = "alloy-provider"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d181c8cc7cf4805d7e589bf4074d56d55064fa1a979f005a45a62b047616d870"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-chains",
"alloy-consensus",
@@ -531,8 +520,7 @@ dependencies = [
[[package]]
name = "alloy-pubsub"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8bd82953194dec221aa4cbbbb0b1e2df46066fe9d0333ac25b43a311e122d13"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-json-rpc",
"alloy-primitives",
@@ -575,8 +563,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-client"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2792758a93ae32a32e9047c843d536e1448044f78422d71bf7d7c05149e103f"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-json-rpc",
"alloy-primitives",
@@ -601,8 +588,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bdcbf9dfd5eea8bfeb078b1d906da8cd3a39c4d4dbe7a628025648e323611f6"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-primitives",
"alloy-rpc-types-engine",
@@ -614,8 +600,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-admin"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42325c117af3a9e49013f881c1474168db57978e02085fc9853a1c89e0562740"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-genesis",
"alloy-primitives",
@@ -626,8 +611,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-anvil"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a3100b76987c1b1dc81f3abe592b7edc29e92b1242067a69d65e0030b35cf9"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-primitives",
"alloy-rpc-types-eth",
@@ -638,8 +622,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-any"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd720b63f82b457610f2eaaf1f32edf44efffe03ae25d537632e7d23e7929e1a"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus-any",
"alloy-rpc-types-eth",
@@ -649,8 +632,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-beacon"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a22e13215866f5dfd5d3278f4c41f1fad9410dc68ce39022f58593c873c26f8"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -669,8 +651,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-debug"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1b21e1ad18ff1b31ff1030e046462ab8168cf8894e6778cd805c8bdfe2bd649"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-primitives",
"derive_more",
@@ -681,8 +662,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-engine"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ac61f03f1edabccde1c687b5b25fff28f183afee64eaa2e767def3929e4457"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -702,8 +682,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-eth"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b2dc411f13092f237d2bf6918caf80977fc2f51485f9b90cb2a2f956912c8c9"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus",
"alloy-consensus-any",
@@ -724,8 +703,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-mev"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe85bf3be739126aa593dca9fb3ab13ca93fa7873e6f2247be64d7f2cb15f34a"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -739,8 +717,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-trace"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad79f1e27e161943b5a4f99fe5534ef0849876214be411e0032c12f38e94daa"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-primitives",
"alloy-rpc-types-eth",
@@ -753,8 +730,7 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-txpool"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d459f902a2313737bc66d18ed094c25d2aeb268b74d98c26bbbda2aa44182ab0"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-primitives",
"alloy-rpc-types-eth",
@@ -765,8 +741,7 @@ dependencies = [
[[package]]
name = "alloy-serde"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2ce1e0dbf7720eee747700e300c99aac01b1a95bb93f493a01e78ee28bb1a37"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-primitives",
"arbitrary",
@@ -777,8 +752,7 @@ dependencies = [
[[package]]
name = "alloy-signer"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2425c6f314522c78e8198979c8cbf6769362be4da381d4152ea8eefce383535d"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-primitives",
"async-trait",
@@ -792,8 +766,7 @@ dependencies = [
[[package]]
name = "alloy-signer-local"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3ecb71ee53d8d9c3fa7bac17542c8116ebc7a9726c91b1bf333ec3d04f5a789"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-consensus",
"alloy-network",
@@ -881,8 +854,7 @@ dependencies = [
[[package]]
name = "alloy-transport"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa186e560d523d196580c48bf00f1bf62e63041f28ecf276acc22f8b27bb9f53"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-json-rpc",
"auto_impl",
@@ -904,8 +876,7 @@ dependencies = [
[[package]]
name = "alloy-transport-http"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa501ad58dd20acddbfebc65b52e60f05ebf97c52fa40d1b35e91f5e2da0ad0e"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-json-rpc",
"alloy-transport",
@@ -920,8 +891,7 @@ dependencies = [
[[package]]
name = "alloy-transport-ipc"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2ef85688e5ac2da72afc804e0a1f153a1f309f05a864b1998bbbed7804dbaab"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-json-rpc",
"alloy-pubsub",
@@ -940,8 +910,7 @@ dependencies = [
[[package]]
name = "alloy-transport-ws"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f00445db69d63298e2b00a0ea1d859f00e6424a3144ffc5eba9c31da995e16"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"alloy-pubsub",
"alloy-transport",
@@ -977,8 +946,7 @@ dependencies = [
[[package]]
name = "alloy-tx-macros"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fa0c53e8c1e1ef4d01066b01c737fb62fc9397ab52c6e7bb5669f97d281b9bc"
source = "git+https://github.com/alloy-rs/alloy?branch=bal-devnet2#1fd12c4107dcf3ad3fbbc404004a710bf91db3e6"
dependencies = [
"darling 0.21.3",
"proc-macro2",
@@ -3754,19 +3722,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "example-migrate-trie-to-packed"
version = "0.0.0"
dependencies = [
"clap",
"eyre",
"reth-db",
"reth-db-api",
"reth-trie-common",
"reth-trie-db",
"serde_json",
]
[[package]]
name = "example-network"
version = "0.0.0"
@@ -6311,9 +6266,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "op-alloy"
version = "0.24.0"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a95dd0974d5e60ffe9342a70cc0033d299244fab01cb16a958eb7352ddba1fa7"
checksum = "e9b8fee21003dd4f076563de9b9d26f8c97840157ef78593cd7f262c5ca99848"
dependencies = [
"op-alloy-consensus",
"op-alloy-network",
@@ -6324,9 +6279,8 @@ dependencies = [
[[package]]
name = "op-alloy-consensus"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fadcb964b0aa645d12e952d470c7585d23286d8bcf1ac41589410b6724216b68"
version = "0.23.1"
source = "git+https://github.com/alloy-rs/op-alloy?branch=bal-devnet2#d3c6e661ce58697327f53508f9514a75ca68eb60"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -6344,9 +6298,8 @@ dependencies = [
[[package]]
name = "op-alloy-network"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ea44162d493219cc678aaca1253d46c3aa73aa361326dfa9d406f086dfa135"
version = "0.23.1"
source = "git+https://github.com/alloy-rs/op-alloy?branch=bal-devnet2#d3c6e661ce58697327f53508f9514a75ca68eb60"
dependencies = [
"alloy-consensus",
"alloy-network",
@@ -6360,9 +6313,9 @@ dependencies = [
[[package]]
name = "op-alloy-provider"
version = "0.24.0"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83aa8dc34bdf077c8e6d48ff75beff4ac14b428d982c9722483ccd7473c0e114"
checksum = "6753d90efbaa8ea8bcb89c1737408ca85fa60d7adb875049d3f382c063666f86"
dependencies = [
"alloy-network",
"alloy-primitives",
@@ -6375,9 +6328,8 @@ dependencies = [
[[package]]
name = "op-alloy-rpc-types"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be9d16ec9f7810e0623a37edc293d1c05fe9c58a5647f6973fdd93e0b4795015"
version = "0.23.1"
source = "git+https://github.com/alloy-rs/op-alloy?branch=bal-devnet2#d3c6e661ce58697327f53508f9514a75ca68eb60"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -6394,9 +6346,8 @@ dependencies = [
[[package]]
name = "op-alloy-rpc-types-engine"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0ac5c5ddcbffadcd097d278c717d34849bcc629f6e4f8514eb000ec862def8"
version = "0.23.1"
source = "git+https://github.com/alloy-rs/op-alloy?branch=bal-devnet2#d3c6e661ce58697327f53508f9514a75ca68eb60"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -6417,8 +6368,7 @@ dependencies = [
[[package]]
name = "op-revm"
version = "17.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a98f3a512a7e02a1dcf1242b57302d83657b265a665d50ad98d0b158efaf2c"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"auto_impl",
"revm",
@@ -7885,6 +7835,7 @@ name = "reth-consensus"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eip7928",
"alloy-primitives",
"auto_impl",
"reth-execution-types",
@@ -8308,6 +8259,7 @@ dependencies = [
"eyre",
"fixed-cache",
"futures",
"itertools 0.14.0",
"metrics",
"metrics-util",
"moka",
@@ -9841,7 +9793,6 @@ dependencies = [
"reth-node-core",
"reth-node-ethereum",
"reth-payload-builder",
"reth-payload-primitives",
"reth-primitives-traits",
"reth-provider",
"reth-rpc",
@@ -10586,8 +10537,7 @@ dependencies = [
[[package]]
name = "revm"
version = "36.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0abc15d09cd211e9e73410ada10134069c794d4bcdb787dfc16a1bf0939849c"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"revm-bytecode",
"revm-context",
@@ -10605,8 +10555,7 @@ dependencies = [
[[package]]
name = "revm-bytecode"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86e468df3cf5cf59fa7ef71a3e9ccabb76bb336401ea2c0674f563104cf3c5e"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"bitvec",
"phf",
@@ -10617,8 +10566,7 @@ dependencies = [
[[package]]
name = "revm-context"
version = "15.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9eb1f0a76b14d684a444fc52f7bf6b7564bf882599d91ee62e76d602e7a187c7"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"bitvec",
"cfg-if",
@@ -10634,8 +10582,7 @@ dependencies = [
[[package]]
name = "revm-context-interface"
version = "16.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc256b27743e2912ca16899568e6652a372eb5d1d573e6edb16c7836b16cf487"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"alloy-eip2930",
"alloy-eip7702",
@@ -10650,8 +10597,7 @@ dependencies = [
[[package]]
name = "revm-database"
version = "12.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0a7d6da41061f2c50f99a2632571026b23684b5449ff319914151f4449b6c8"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"alloy-eips",
"revm-bytecode",
@@ -10664,8 +10610,7 @@ dependencies = [
[[package]]
name = "revm-database-interface"
version = "10.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd497a38a79057b94a049552cb1f925ad15078bc1a479c132aeeebd1d2ccc768"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"auto_impl",
"either",
@@ -10678,8 +10623,7 @@ dependencies = [
[[package]]
name = "revm-handler"
version = "17.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f1eed729ca9b228ae98688f352235871e9b8be3d568d488e4070f64c56e9d3d"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"auto_impl",
"derive-where",
@@ -10697,8 +10641,7 @@ dependencies = [
[[package]]
name = "revm-inspector"
version = "17.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf5102391706513689f91cb3cb3d97b5f13a02e8647e6e9cb7620877ef84847"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"auto_impl",
"either",
@@ -10735,8 +10678,7 @@ dependencies = [
[[package]]
name = "revm-interpreter"
version = "34.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf22f80612bb8f58fd1f578750281f2afadb6c93835b14ae6a4d6b75ca26f445"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"revm-bytecode",
"revm-context-interface",
@@ -10748,8 +10690,7 @@ dependencies = [
[[package]]
name = "revm-precompile"
version = "32.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2ec11f45deec71e4945e1809736bb20d454285f9167ab53c5159dae1deb603f"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"ark-bls12-381",
"ark-bn254",
@@ -10772,8 +10713,7 @@ dependencies = [
[[package]]
name = "revm-primitives"
version = "22.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfb5ce6cf18b118932bcdb7da05cd9c250f2cb9f64131396b55f3fe3537c35"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"alloy-primitives",
"num_enum",
@@ -10784,8 +10724,7 @@ dependencies = [
[[package]]
name = "revm-state"
version = "10.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29404707763da607e5d6e4771cb203998c28159279c2f64cc32de08d2814651"
source = "git+https://github.com/bluealloy/revm?rev=fa5a6914398c9b178422efc1edd1d2ab33dad923#fa5a6914398c9b178422efc1edd1d2ab33dad923"
dependencies = [
"alloy-eip7928",
"bitflags 2.11.0",

View File

@@ -137,7 +137,6 @@ members = [
"examples/exex-subscription",
"examples/exex-test",
"examples/full-contract-state",
"examples/migrate-trie-to-packed",
"examples/manual-p2p/",
"examples/network-txpool/",
"examples/network/",
@@ -445,13 +444,13 @@ revm-database-interface = { version = "10.0.0", default-features = false }
revm-inspectors = "0.36.0"
# eth
alloy-dyn-abi = "1.5.6"
alloy-primitives = { version = "1.5.6", default-features = false, features = ["map-foldhash"] }
alloy-sol-types = { version = "1.5.6", default-features = false }
alloy-dyn-abi = "1.5.0"
alloy-primitives = { version = "1.5.0", default-features = false, features = ["map-foldhash"] }
alloy-sol-types = { version = "1.5.0", default-features = false }
alloy-chains = { version = "0.2.5", default-features = false }
alloy-eip2124 = { version = "0.2.0", default-features = false }
alloy-eip7928 = { version = "0.3.0", default-features = false }
alloy-eip7928 = { version = "0.3.3", default-features = false, features = ["rlp"] }
alloy-evm = { version = "0.29.2", default-features = false }
alloy-rlp = { version = "0.3.13", default-features = false, features = ["core-net"] }
alloy-trie = { version = "0.9.4", default-features = false }
@@ -487,9 +486,13 @@ alloy-transport-ipc = { version = "1.7.3", default-features = false }
alloy-transport-ws = { version = "1.7.3", default-features = false }
# op
op-alloy-rpc-types = { version = "0.24.0", default-features = false }
op-alloy-rpc-types-engine = { version = "0.24.0", default-features = false }
op-alloy-consensus = { version = "0.24.0", default-features = false }
alloy-op-hardforks = "0.4.4"
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
either = { version = "1.15.0", default-features = false }
@@ -528,13 +531,13 @@ quanta = "0.12"
paste = "1.0"
rand = "0.9"
rayon = "1.7"
thread-priority = "3.0.0"
rustc-hash = { version = "2.0", default-features = false }
schnellru = "0.2"
serde = { version = "1.0", default-features = false }
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
serde_with = { version = "3", default-features = false, features = ["macros"] }
sha2 = { version = "0.10", default-features = false }
shellexpand = "3.0.0"
shlex = "1.3"
slotmap = "1"
smallvec = "1"
@@ -542,6 +545,7 @@ strum = { version = "0.27", default-features = false }
strum_macros = "0.27"
syn = "2.0"
thiserror = { version = "2.0.0", default-features = false }
thread-priority = "3.0.0"
tar = "0.4.44"
tracing = { version = "0.1.0", default-features = false, features = ["attributes"] }
tracing-appender = "0.2"
@@ -752,3 +756,68 @@ ipnet = "2.11"
# alloy-evm = { git = "https://github.com/alloy-rs/evm", rev = "9bc2dba" }
# revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors", rev = "3020ea8" }
# alloy-evm = { git = "https://github.com/alloy-rs/evm", rev = "072c248" }
# alloy-op-evm = { git = "https://github.com/alloy-rs/evm", rev = "072c248" }
# =============================================================================
# BAL devnet patches (EIP-7778, EIP-7928 block access lists)
# =============================================================================
# revm staging patches
revm = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-bytecode = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-database = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-database-interface = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-state = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-primitives = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-interpreter = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-precompile = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-context = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-context-interface = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-handler = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
revm-inspector = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
op-revm = { git = "https://github.com/bluealloy/revm", rev = "fa5a6914398c9b178422efc1edd1d2ab33dad923" }
# revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors", branch = "staging" }
# alloy-evm bal-devnet2 patches
alloy-evm = { git = "https://github.com/alloy-rs/evm", branch = "bal-devnet2" }
# alloy bal-devnet2 patches
alloy-consensus = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-consensus-any = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-contract = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-eips = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-genesis = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-network = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-network-primitives = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-provider = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-pubsub = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-admin = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-anvil = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-beacon = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-debug = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-engine = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-any = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-eth = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-mev = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-trace = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-rpc-types-txpool = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-serde = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-signer = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-signer-local = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-transport = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
alloy-tx-macros = { git = "https://github.com/alloy-rs/alloy", branch = "bal-devnet2" }
# op-alloy bal-devnet2 patches
op-alloy-consensus = { git = "https://github.com/alloy-rs/op-alloy", branch = "bal-devnet2" }
op-alloy-network = { git = "https://github.com/alloy-rs/op-alloy", branch = "bal-devnet2" }
op-alloy-rpc-types = { git = "https://github.com/alloy-rs/op-alloy", branch = "bal-devnet2" }
op-alloy-rpc-types-engine = { git = "https://github.com/alloy-rs/op-alloy", branch = "bal-devnet2" }

View File

@@ -29,7 +29,7 @@ EF_TESTS_URL := https://github.com/ethereum/tests/archive/refs/tags/$(EF_TESTS_T
EF_TESTS_DIR := ./testing/ef-tests/ethereum-tests
# The release tag of https://github.com/ethereum/execution-spec-tests to use for EEST tests
EEST_TESTS_TAG := v4.5.0
EEST_TESTS_TAG := bal@v5.0.0
EEST_TESTS_URL := https://github.com/ethereum/execution-spec-tests/releases/download/$(EEST_TESTS_TAG)/fixtures_stable.tar.gz
EEST_TESTS_DIR := ./testing/ef-tests/execution-spec-tests

View File

@@ -773,6 +773,7 @@ impl Command {
suggested_fee_recipient: alloy_primitives::Address::ZERO,
withdrawals: Some(vec![]),
parent_beacon_block_root: Some(B256::ZERO),
slot_number: None,
},
transactions: transactions.to_vec(),
extra_data: None,

View File

@@ -240,6 +240,7 @@ impl Command {
ExecutionPayload::V1(p) => config.apply_to_payload_v1(p),
ExecutionPayload::V2(p) => config.apply_to_payload_v2(p),
ExecutionPayload::V3(p) => config.apply_to_payload_v3(p),
ExecutionPayload::V4(p) => config.apply_to_payload_v3(&mut p.payload_inner),
};
let skip_recalc = self.skip_hash_recalc || config.should_skip_hash_recalc();
@@ -254,6 +255,9 @@ impl Command {
ExecutionPayload::V1(p) => p.block_hash,
ExecutionPayload::V2(p) => p.payload_inner.block_hash,
ExecutionPayload::V3(p) => p.payload_inner.payload_inner.block_hash,
ExecutionPayload::V4(p) => {
p.payload_inner.payload_inner.payload_inner.block_hash
}
}
}
};
@@ -262,6 +266,9 @@ impl Command {
ExecutionPayload::V1(p) => p.block_hash = new_hash,
ExecutionPayload::V2(p) => p.payload_inner.block_hash = new_hash,
ExecutionPayload::V3(p) => p.payload_inner.payload_inner.block_hash = new_hash,
ExecutionPayload::V4(p) => {
p.payload_inner.payload_inner.payload_inner.block_hash = new_hash
}
}
}

View File

@@ -230,6 +230,20 @@ pub(crate) fn payload_to_new_payload(
let execution_data = ExecutionData { payload: payload.clone(), sidecar: sidecar.clone() };
let (version, params) = match payload {
ExecutionPayload::V4(payload) => {
let cancun = sidecar.cancun().unwrap();
let prague = sidecar.prague().unwrap();
let requests = prague.requests.requests_hash();
(
EngineApiMessageVersion::V5,
serde_json::to_value((
payload,
cancun.versioned_hashes.clone(),
cancun.parent_beacon_block_root,
requests,
))?,
)
}
ExecutionPayload::V3(payload) => {
let cancun = sidecar.cancun().unwrap();
@@ -387,9 +401,12 @@ pub(crate) async fn call_forkchoice_updated<N, P: EngineApiValidWaitExt<N>>(
forkchoice_state: ForkchoiceState,
payload_attributes: Option<PayloadAttributes>,
) -> TransportResult<ForkchoiceUpdated> {
// FCU V3 is used for both Cancun and Prague (there is no FCU V4)
// FCU V3 is used for Cancun, Prague, and Amsterdam (there is no FCU V4-V6)
match message_version {
EngineApiMessageVersion::V3 | EngineApiMessageVersion::V4 | EngineApiMessageVersion::V5 => {
EngineApiMessageVersion::V3 |
EngineApiMessageVersion::V4 |
EngineApiMessageVersion::V5 |
EngineApiMessageVersion::V6 => {
provider.fork_choice_updated_v3_wait(forkchoice_state, payload_attributes).await
}
EngineApiMessageVersion::V2 => {

View File

@@ -70,7 +70,7 @@ aquamarine.workspace = true
clap = { workspace = true, features = ["derive", "env"] }
[dev-dependencies]
alloy-node-bindings = "1.6.3"
alloy-node-bindings = "1.5.2"
alloy-provider = { workspace = true, features = ["reqwest"] }
alloy-rpc-types-eth.workspace = true
backon.workspace = true

View File

@@ -28,7 +28,7 @@ use alloy_consensus::{
};
use alloy_eips::{
eip1559::INITIAL_BASE_FEE, eip7685::EMPTY_REQUESTS_HASH, eip7840::BlobParams,
eip7892::BlobScheduleBlobParams,
eip7892::BlobScheduleBlobParams, eip7928::EMPTY_BLOCK_ACCESS_LIST_HASH,
};
use alloy_genesis::{ChainConfig, Genesis};
use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256};
@@ -76,6 +76,18 @@ pub fn make_genesis_header(genesis: &Genesis, hardforks: &ChainHardforks) -> Hea
.active_at_timestamp(genesis.timestamp)
.then_some(EMPTY_REQUESTS_HASH);
// If Amsterdam is activated at genesis we set block access list hash to empty hash.
let block_access_list_hash = hardforks
.fork(EthereumHardfork::Amsterdam)
.active_at_timestamp(genesis.timestamp)
.then_some(EMPTY_BLOCK_ACCESS_LIST_HASH);
// If Amsterdam is activated at genesis we set slot number to 0.
let slot_number = hardforks
.fork(EthereumHardfork::Amsterdam)
.active_at_timestamp(genesis.timestamp)
.then_some(0);
Header {
number: genesis.number.unwrap_or_default(),
parent_hash: genesis.parent_hash.unwrap_or_default(),
@@ -93,6 +105,8 @@ pub fn make_genesis_header(genesis: &Genesis, hardforks: &ChainHardforks) -> Hea
blob_gas_used,
excess_blob_gas,
requests_hash,
block_access_list_hash,
slot_number,
..Default::default()
}
}
@@ -298,6 +312,7 @@ pub fn create_chain_config(
cancun_time: timestamp(EthereumHardfork::Cancun),
prague_time: timestamp(EthereumHardfork::Prague),
osaka_time: timestamp(EthereumHardfork::Osaka),
amsterdam_time: timestamp(EthereumHardfork::Amsterdam),
bpo1_time: timestamp(EthereumHardfork::Bpo1),
bpo2_time: timestamp(EthereumHardfork::Bpo2),
bpo3_time: timestamp(EthereumHardfork::Bpo3),
@@ -880,6 +895,7 @@ impl From<Genesis> for ChainSpec {
(EthereumHardfork::Cancun.boxed(), genesis.config.cancun_time),
(EthereumHardfork::Prague.boxed(), genesis.config.prague_time),
(EthereumHardfork::Osaka.boxed(), genesis.config.osaka_time),
(EthereumHardfork::Amsterdam.boxed(), genesis.config.amsterdam_time),
(EthereumHardfork::Bpo1.boxed(), genesis.config.bpo1_time),
(EthereumHardfork::Bpo2.boxed(), genesis.config.bpo2_time),
(EthereumHardfork::Bpo3.boxed(), genesis.config.bpo3_time),
@@ -1191,6 +1207,19 @@ impl ChainSpecBuilder {
self
}
/// Enable Amsterdam at genesis.
pub fn amsterdam_activated(mut self) -> Self {
self = self.osaka_activated();
self.hardforks.insert(EthereumHardfork::Amsterdam, ForkCondition::Timestamp(0));
self
}
/// Enable Amsterdam at the given timestamp.
pub fn with_amsterdam_at(mut self, timestamp: u64) -> Self {
self.hardforks.insert(EthereumHardfork::Amsterdam, ForkCondition::Timestamp(timestamp));
self
}
/// Build the resulting [`ChainSpec`].
///
/// # Panics

View File

@@ -179,8 +179,10 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + Hardforks + EthereumHardforks>
}
};
let bal= executor.take_bal();
if let Err(err) = consensus
.validate_block_post_execution(&block, &result, None)
.validate_block_post_execution(&block, &result, None, bal, true)
.wrap_err_with(|| {
format!(
"Failed to validate block {} {}",

View File

@@ -87,6 +87,27 @@ pub fn validate_cancun_gas<B: Block>(block: &SealedBlock<B>) -> Result<(), Conse
Ok(())
}
/// Validate that Amsterdam header fields are present in the block.
///
/// This checks that the `block_access_list_hash` and `slot_number` are set in the header,
/// as required post-Amsterdam.
///
/// See [EIP-7928]: Block-level Access Lists
/// See [EIP-7778]: Slot Number in Block Header
///
/// [EIP-7928]: https://eips.ethereum.org/EIPS/eip-7928
/// [EIP-7778]: https://eips.ethereum.org/EIPS/eip-7778
#[inline]
pub fn validate_amsterdam_header_fields<H: BlockHeader>(header: &H) -> Result<(), ConsensusError> {
if header.block_access_list_hash().is_none() {
return Err(ConsensusError::BlockAccessListHashMissing);
}
if header.slot_number().is_none() {
return Err(ConsensusError::SlotNumberMissing);
}
Ok(())
}
/// Ensures the block response data matches the header.
///
/// This ensures the body response items match the header's hashes:

View File

@@ -18,6 +18,7 @@ reth-primitives-traits.workspace = true
# ethereum
alloy-primitives.workspace = true
alloy-consensus.workspace = true
alloy-eip7928.workspace = true
# misc
auto_impl.workspace = true
@@ -29,10 +30,8 @@ std = [
"reth-primitives-traits/std",
"alloy-primitives/std",
"alloy-consensus/std",
"reth-primitives-traits/std",
"alloy-eip7928/std",
"reth-execution-types/std",
"thiserror/std",
]
test-utils = [
"reth-primitives-traits/test-utils",
]
test-utils = ["reth-primitives-traits/test-utils"]

View File

@@ -13,6 +13,7 @@ extern crate alloc;
use alloc::{boxed::Box, fmt::Debug, string::String, sync::Arc, vec::Vec};
use alloy_consensus::Header;
use alloy_eip7928::BlockAccessList;
use alloy_primitives::{BlockHash, BlockNumber, Bloom, B256};
use core::error::Error;
@@ -54,12 +55,17 @@ pub trait FullConsensus<N: NodePrimitives>: Consensus<N::Block> {
/// If `receipt_root_bloom` is provided, the implementation should use the pre-computed
/// receipt root and logs bloom instead of computing them from the receipts.
///
/// If `allow_bal_check` is enabled, we calculate the bal hash and match with the header bal
/// hash. We don't do by default because for payload validation, we do the same bal check
///
/// Note: validating blocks does not include other validations of the Consensus
fn validate_block_post_execution(
&self,
block: &RecoveredBlock<N::Block>,
result: &BlockExecutionResult<N::Receipt>,
receipt_root_bloom: Option<ReceiptRootBloom>,
block_access_list: Option<BlockAccessList>,
allow_bal_check: bool,
) -> Result<(), ConsensusError>;
}
@@ -331,6 +337,30 @@ pub enum ConsensusError {
#[error("unexpected parent beacon block root")]
ParentBeaconBlockRootUnexpected,
/// Error when the block access list hash is missing.
#[error("missing block access list hash")]
BlockAccessListHashMissing,
/// Error when an unexpected block access list hash is encountered.
#[error("unexpected block access list hash")]
BlockAccessListHashUnexpected,
/// Error when an unexpected block access list cost is encountered.
#[error("block access list cost exceeds gas limit")]
BlockAccessListCostMoreThanGasLimit,
/// Error when the block access list hash doesn't match the expected value.
#[error("block access list hash mismatch: {0}")]
BlockAccessListHashMismatch(GotExpectedBoxed<B256>),
/// Error when the slot number is missing.
#[error("missing slot number")]
SlotNumberMissing,
/// Error when an unexpected slot number is encountered.
#[error("unexpected slot number")]
SlotNumberUnexpected,
/// Error when blob gas used exceeds the maximum allowed.
#[error("blob gas used {blob_gas_used} exceeds maximum allowance {max_blob_gas_per_block}")]
BlobGasUsedExceedsMaxBlobGasPerBlock {

View File

@@ -20,6 +20,7 @@
use crate::{Consensus, ConsensusError, FullConsensus, HeaderValidator, ReceiptRootBloom};
use alloc::sync::Arc;
use alloy_eip7928::BlockAccessList;
use reth_execution_types::BlockExecutionResult;
use reth_primitives_traits::{Block, NodePrimitives, RecoveredBlock, SealedBlock, SealedHeader};
@@ -77,6 +78,8 @@ impl<N: NodePrimitives> FullConsensus<N> for NoopConsensus {
_block: &RecoveredBlock<N::Block>,
_result: &BlockExecutionResult<N::Receipt>,
_receipt_root_bloom: Option<ReceiptRootBloom>,
_block_access_list: Option<BlockAccessList>,
_allow_bal_check: bool,
) -> Result<(), ConsensusError> {
Ok(())
}

View File

@@ -1,4 +1,5 @@
use crate::{Consensus, ConsensusError, FullConsensus, HeaderValidator, ReceiptRootBloom};
use alloy_eip7928::BlockAccessList;
use core::sync::atomic::{AtomicBool, Ordering};
use reth_execution_types::BlockExecutionResult;
use reth_primitives_traits::{Block, NodePrimitives, RecoveredBlock, SealedBlock, SealedHeader};
@@ -52,6 +53,8 @@ impl<N: NodePrimitives> FullConsensus<N> for TestConsensus {
_block: &RecoveredBlock<N::Block>,
_result: &BlockExecutionResult<N::Receipt>,
_receipt_root_bloom: Option<ReceiptRootBloom>,
_block_access_list: Option<BlockAccessList>,
_allow_bal_check: bool,
) -> Result<(), ConsensusError> {
if self.fail_validation() {
Err(ConsensusError::BaseFeeMissing)

View File

@@ -55,6 +55,8 @@ pub fn generate_test_blocks(chain_spec: &ChainSpec, count: u64) -> Vec<SealedBlo
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
};
// Set required fields based on chain spec

View File

@@ -227,6 +227,7 @@ where
suggested_fee_recipient: alloy_primitives::Address::random(),
withdrawals: Some(vec![]),
parent_beacon_block_root: Some(B256::ZERO),
slot_number: None,
};
env.active_node_state_mut()?
@@ -299,6 +300,7 @@ where
suggested_fee_recipient: alloy_primitives::Address::random(),
withdrawals: Some(vec![]),
parent_beacon_block_root: Some(B256::ZERO),
slot_number: None,
};
let fresh_fcu_result = EngineApiClient::<Engine>::fork_choice_updated_v3(

View File

@@ -271,6 +271,7 @@ where
suggested_fee_recipient: alloy_primitives::Address::ZERO,
withdrawals: Some(vec![]),
parent_beacon_block_root: Some(B256::ZERO),
slot_number: None,
};
EthPayloadBuilderAttributes::new(B256::ZERO, attributes)
};
@@ -301,6 +302,7 @@ where
suggested_fee_recipient: alloy_primitives::Address::ZERO,
withdrawals: Some(vec![]),
parent_beacon_block_root: Some(B256::ZERO),
slot_number: None,
};
<<N as NodeTypes>::Payload as PayloadTypes>::PayloadBuilderAttributes::from(
EthPayloadBuilderAttributes::new(B256::ZERO, attributes),

View File

@@ -161,6 +161,7 @@ async fn test_testsuite_assert_mine_block() -> Result<()> {
suggested_fee_recipient: Address::random(),
withdrawals: None,
parent_beacon_block_root: None,
slot_number: None,
},
));

View File

@@ -90,6 +90,7 @@ fn test_attributes_generator(timestamp: u64) -> EthPayloadBuilderAttributes {
suggested_fee_recipient: alloy_primitives::Address::ZERO,
withdrawals: Some(vec![]),
parent_beacon_block_root: Some(B256::ZERO),
slot_number: None,
};
EthPayloadBuilderAttributes::new(B256::ZERO, attributes)
}

View File

@@ -57,6 +57,7 @@ where
.chain_spec
.is_cancun_active_at_timestamp(timestamp)
.then(B256::random),
slot_number: None,
}
}
}

View File

@@ -151,6 +151,17 @@ pub struct TreeConfig {
/// computation is spawned in parallel and whichever finishes first is used.
/// If `None`, the timeout fallback is disabled.
state_root_task_timeout: Option<Duration>,
/// Whether to disable BAL (Block Access List, EIP-7928) based parallel execution.
/// When disabled, falls back to transaction-based prewarming even when a BAL is available.
disable_bal_parallel_execution: bool,
/// Whether to disable BAL-driven parallel state root computation.
/// When disabled, the BAL hashed post state is not sent to the multiproof task for
/// early parallel state root computation.
disable_bal_parallel_state_root: bool,
/// Whether to disable BAL (Block Access List) batched IO during prewarming.
/// When disabled, falls back to individual per-slot storage reads instead of
/// batched cursor reads via `storage_range`.
disable_bal_batch_io: bool,
/// Maximum random jitter applied before each proof computation (trie-debug only).
/// When set, each proof worker sleeps for a random duration up to this value
/// before starting a proof calculation.
@@ -186,6 +197,9 @@ impl Default for TreeConfig {
slow_block_threshold: None,
disable_sparse_trie_cache_pruning: false,
state_root_task_timeout: Some(DEFAULT_STATE_ROOT_TASK_TIMEOUT),
disable_bal_parallel_execution: false,
disable_bal_parallel_state_root: false,
disable_bal_batch_io: false,
#[cfg(feature = "trie-debug")]
proof_jitter: None,
}
@@ -247,6 +261,9 @@ impl TreeConfig {
slow_block_threshold,
disable_sparse_trie_cache_pruning: false,
state_root_task_timeout,
disable_bal_parallel_execution: false,
disable_bal_parallel_state_root: false,
disable_bal_batch_io: false,
#[cfg(feature = "trie-debug")]
proof_jitter: None,
}
@@ -559,6 +576,34 @@ impl TreeConfig {
self
}
/// Returns whether BAL-based parallel execution is disabled.
pub const fn disable_bal_parallel_execution(&self) -> bool {
self.disable_bal_parallel_execution
}
/// Setter for whether to disable BAL-based parallel execution.
pub const fn without_bal_parallel_execution(
mut self,
disable_bal_parallel_execution: bool,
) -> Self {
self.disable_bal_parallel_execution = disable_bal_parallel_execution;
self
}
/// Returns whether BAL-driven parallel state root computation is disabled.
pub const fn disable_bal_parallel_state_root(&self) -> bool {
self.disable_bal_parallel_state_root
}
/// Setter for whether to disable BAL-driven parallel state root computation.
pub const fn without_bal_parallel_state_root(
mut self,
disable_bal_parallel_state_root: bool,
) -> Self {
self.disable_bal_parallel_state_root = disable_bal_parallel_state_root;
self
}
/// Returns the proof jitter duration, if configured (trie-debug only).
#[cfg(feature = "trie-debug")]
pub const fn proof_jitter(&self) -> Option<Duration> {
@@ -571,4 +616,15 @@ impl TreeConfig {
self.proof_jitter = proof_jitter;
self
}
/// Returns whether BAL batched IO is disabled.
pub const fn disable_bal_batch_io(&self) -> bool {
self.disable_bal_batch_io
}
/// Setter for whether to disable BAL batched IO.
pub const fn without_bal_batch_io(mut self, disable_bal_batch_io: bool) -> Self {
self.disable_bal_batch_io = disable_bal_batch_io;
self
}
}

View File

@@ -60,6 +60,7 @@ metrics.workspace = true
reth-metrics = { workspace = true, features = ["common"] }
# misc
itertools.workspace = true
schnellru.workspace = true
rayon.workspace = true
tracing.workspace = true

View File

@@ -6,7 +6,7 @@ use alloy_primitives::{
use fixed_cache::{AnyRef, CacheConfig, Stats, StatsHandler};
use metrics::{Counter, Gauge, Histogram};
use parking_lot::Once;
use reth_errors::ProviderResult;
use reth_errors::{ProviderError, ProviderResult};
use reth_metrics::Metrics;
use reth_primitives_traits::{Account, Bytecode};
use reth_provider::{
@@ -466,6 +466,55 @@ impl<S: StateProvider, const PREWARM: bool> StateProvider for CachedStateProvide
self.state_provider.storage(account, storage_key)
}
}
fn storage_range(
&self,
account: Address,
keys: &[StorageKey],
) -> ProviderResult<Vec<(StorageKey, StorageValue)>> {
let mut uncached_keys = Vec::new();
let mut result = Vec::with_capacity(keys.len());
for &key in keys {
if let Some(value) = self.caches.get_storage(account, key) {
if !value.is_zero() {
result.push((key, value));
}
} else {
uncached_keys.push(key);
}
}
// Batch-fetch all uncached keys from the inner provider
if !uncached_keys.is_empty() {
let mut fetched = self.state_provider.storage_range(account, &uncached_keys)?;
// Sort by raw key to align with uncached_keys for the merge-join below.
// The inner provider may return results in a different order (e.g. hashed state
// iterates by hashed slot).
fetched.sort_unstable_by_key(|(k, _)| *k);
// Merge-join to find zero slots without allocating a HashSet.
let mut fetched_iter = fetched.iter();
let mut next = fetched_iter.next();
for &key in &uncached_keys {
if let Some(&(fk, fv)) = next &&
fk == key
{
let _ = self.caches.get_or_try_insert_storage_with(account, key, || {
Ok::<_, ProviderError>(fv)
});
result.push((key, fv));
next = fetched_iter.next();
continue;
}
// key not returned by inner provider → zero slot
let _ = self.caches.get_or_try_insert_storage_with(account, key, || {
Ok::<_, ProviderError>(StorageValue::ZERO)
});
}
}
Ok(result)
}
}
impl<S: BytecodeReader, const PREWARM: bool> BytecodeReader for CachedStateProvider<S, PREWARM> {
@@ -756,6 +805,11 @@ impl ExecutionCache {
}
}
/// Returns a cached storage value if present, without inserting.
pub fn get_storage(&self, address: Address, key: StorageKey) -> Option<StorageValue> {
self.0.storage_cache.get(&(address, key))
}
/// Insert storage value into cache.
pub fn insert_storage(&self, address: Address, key: StorageKey, value: Option<StorageValue>) {
self.0.storage_cache.insert((address, key), value.unwrap_or_default());

View File

@@ -131,6 +131,12 @@ where
disable_sparse_trie_cache_pruning: bool,
/// Whether to disable cache metrics recording.
disable_cache_metrics: bool,
/// Whether to disable BAL-based parallel execution (falls back to tx-based prewarming).
disable_bal_parallel_execution: bool,
/// Whether to disable BAL-driven parallel state root computation.
disable_bal_parallel_state_root: bool,
/// Whether BAL batched IO is disabled.
disable_bal_batch_io: bool,
}
impl<N, Evm> PayloadProcessor<Evm>
@@ -165,6 +171,9 @@ where
sparse_trie_max_hot_accounts: config.sparse_trie_max_hot_accounts(),
disable_sparse_trie_cache_pruning: config.disable_sparse_trie_cache_pruning(),
disable_cache_metrics: config.disable_cache_metrics(),
disable_bal_parallel_execution: config.disable_bal_parallel_execution(),
disable_bal_parallel_state_root: config.disable_bal_parallel_state_root(),
disable_bal_batch_io: config.disable_bal_batch_io(),
}
}
}
@@ -493,6 +502,7 @@ where
executed_tx_index: Arc::clone(&executed_tx_index),
precompile_cache_disabled: self.precompile_cache_disabled,
precompile_cache_map: self.precompile_cache_map.clone(),
disable_bal_batch_io: self.disable_bal_batch_io,
};
let (prewarm_task, to_prewarm_task) = PrewarmCacheTask::new(
@@ -500,14 +510,16 @@ where
self.execution_cache.clone(),
prewarm_ctx,
to_multi_proof,
self.disable_bal_parallel_state_root,
);
{
let to_prewarm_task = to_prewarm_task.clone();
let disable_bal_parallel_execution = self.disable_bal_parallel_execution;
self.executor.spawn_blocking_named("prewarm", move || {
let mode = if skip_prewarm {
PrewarmMode::Skipped
} else if let Some(bal) = bal {
} else if let Some(bal) = bal.filter(|_| !disable_bal_parallel_execution) {
PrewarmMode::BlockAccessList(bal)
} else {
PrewarmMode::Transactions(transactions)

View File

@@ -22,6 +22,7 @@ use alloy_eip7928::BlockAccessList;
use alloy_eips::eip4895::Withdrawal;
use alloy_primitives::{keccak256, StorageKey, B256};
use crossbeam_channel::Sender as CrossbeamSender;
use itertools::{EitherOrBoth, Itertools};
use metrics::{Counter, Gauge, Histogram};
use rayon::prelude::*;
use reth_evm::{execute::ExecutableTxFor, ConfigureEvm, Evm, EvmFor, RecoveredTx, SpecFor};
@@ -75,6 +76,8 @@ where
actions_rx: Receiver<PrewarmTaskEvent<N::Receipt>>,
/// Parent span for tracing
parent_span: Span,
/// Whether to disable BAL-driven parallel state root computation.
disable_bal_parallel_state_root: bool,
}
impl<N, P, Evm> PrewarmCacheTask<N, P, Evm>
@@ -89,6 +92,7 @@ where
execution_cache: PayloadExecutionCache,
ctx: PrewarmContext<N, P, Evm>,
to_multi_proof: Option<CrossbeamSender<MultiProofMessage>>,
disable_bal_parallel_state_root: bool,
) -> (Self, Sender<PrewarmTaskEvent<N::Receipt>>) {
let (actions_tx, actions_rx) = channel();
@@ -107,6 +111,7 @@ where
to_multi_proof,
actions_rx,
parent_span: Span::current(),
disable_bal_parallel_state_root,
},
actions_tx,
)
@@ -290,24 +295,19 @@ where
let new_cache = SavedCache::new(hash, caches, cache_metrics)
.with_disable_cache_metrics(disable_cache_metrics);
// Insert state into cache while holding the lock
// Access the BundleState through the shared ExecutionOutcome
if new_cache.cache().insert_state(&execution_outcome.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();
// Defer `insert_state` until after validation: FixedCache's non-blocking
// inserts silently drop writes under concurrent reader contention.
if valid_block_rx.recv().is_ok() {
// Replace the shared cache with the new one; the previous cache (if any) is
// dropped.
if new_cache.cache().insert_state(&execution_outcome.state).is_err() {
*cached = None;
debug!(target: "engine::caching", "cleared execution cache on update error");
return;
}
*cached = Some(new_cache);
} else {
// Block was invalid; caches were already mutated by insert_state above,
// so we must clear to prevent using polluted state
*cached = None;
debug!(target: "engine::caching", "cleared execution cache on invalid block");
}
@@ -356,7 +356,12 @@ where
let ctx = self.ctx.clone();
self.executor.prewarming_pool().install_fn(|| {
bal.par_iter().for_each_init(
|| (ctx.clone(), None::<CachedStateProvider<reth_provider::StateProviderBox>>),
|| {
(
ctx.clone(),
None::<CachedStateProvider<reth_provider::StateProviderBox, true>>,
)
},
|(ctx, provider), account| {
if ctx.should_stop() {
return;
@@ -381,6 +386,9 @@ where
/// Converts the BAL to [`HashedPostState`](reth_trie::HashedPostState) and sends it to the
/// multiproof task.
fn send_bal_hashed_state(&self, bal: &BlockAccessList) {
if self.disable_bal_parallel_state_root {
return;
}
let Some(to_multi_proof) = &self.to_multi_proof else { return };
let provider = match self.ctx.provider.build() {
@@ -515,6 +523,8 @@ where
pub precompile_cache_disabled: bool,
/// The precompile cache map.
pub precompile_cache_map: PrecompileCacheMap<SpecFor<Evm>>,
/// Whether BAL batched IO is disabled.
pub disable_bal_batch_io: bool,
}
/// Per-thread EVM state initialised by [`PrewarmContext::evm_for_ctx`] and stored in
@@ -600,7 +610,7 @@ where
/// thread.
fn prefetch_bal_account(
&self,
provider: &mut Option<CachedStateProvider<reth_provider::StateProviderBox>>,
provider: &mut Option<CachedStateProvider<reth_provider::StateProviderBox, true>>,
account: &alloy_eip7928::AccountChanges,
) {
let state_provider = match provider {
@@ -621,7 +631,7 @@ where
self.saved_cache.as_ref().expect("BAL prewarm should only run with cache");
let caches = saved_cache.cache().clone();
let cache_metrics = saved_cache.metrics().clone();
slot.insert(CachedStateProvider::new(built, caches, cache_metrics))
slot.insert(CachedStateProvider::new_prewarm(built, caches, cache_metrics))
}
};
@@ -629,11 +639,24 @@ where
let _ = state_provider.basic_account(&account.address);
for slot in &account.storage_changes {
let _ = state_provider.storage(account.address, StorageKey::from(slot.slot));
}
for &slot in &account.storage_reads {
let _ = state_provider.storage(account.address, StorageKey::from(slot));
if self.disable_bal_batch_io {
for slot in &account.storage_changes {
let _ = state_provider.storage(account.address, StorageKey::from(slot.slot));
}
for &slot in &account.storage_reads {
let _ = state_provider.storage(account.address, StorageKey::from(slot));
}
} else {
let slots: Vec<StorageKey> = account
.storage_changes
.iter()
.map(|s| StorageKey::from(s.slot))
.merge_join_by(account.storage_reads.iter().map(|&s| StorageKey::from(s)), Ord::cmp)
.map(|either| match either {
EitherOrBoth::Left(k) | EitherOrBoth::Right(k) | EitherOrBoth::Both(k, _) => k,
})
.collect();
let _ = state_provider.storage_range(account.address, &slots);
}
self.metrics.bal_slot_iteration_duration.record(start.elapsed().as_secs_f64());

View File

@@ -15,6 +15,7 @@ use alloy_eip7928::BlockAccessList;
use alloy_eips::{eip1898::BlockWithParent, eip4895::Withdrawal, NumHash};
use alloy_evm::Evm;
use alloy_primitives::{map::B256Set, B256};
use alloy_rlp::Decodable;
#[cfg(feature = "trie-debug")]
use reth_trie_sparse::debug_recorder::TrieDebugRecorder;
@@ -864,15 +865,21 @@ where
S: StateProvider + Send,
Err: core::error::Error + Send + Sync + 'static,
V: PayloadValidator<T, Block = N::Block>,
T: PayloadTypes<BuiltPayload: BuiltPayload<Primitives = N>>,
T: PayloadTypes<
BuiltPayload: BuiltPayload<Primitives = N>,
ExecutionData: ExecutionPayload,
>,
Evm: ConfigureEngineEvm<T::ExecutionData, Primitives = N>,
{
debug!(target: "engine::tree::payload_validator", "Executing block");
let has_bal = input.block_access_list().is_some();
let mut db = debug_span!(target: "engine::tree", "build_state_db").in_scope(|| {
State::builder()
.with_database(StateProviderDatabase::new(state_provider))
.with_bundle_update()
.with_bal_builder_if(has_bal)
.build()
});
@@ -931,6 +938,7 @@ where
handle.iter_transactions(),
&receipt_tx,
&executed_tx_index,
has_bal,
)?;
drop(receipt_tx);
@@ -945,6 +953,32 @@ where
debug_span!(target: "engine::tree", "merge_transitions")
.in_scope(|| db.merge_transitions(BundleRetention::Reverts));
// Validate BAL hash if we executed with BAL tracking
if has_bal {
// Get the expected BAL from input and the built BAL from execution
let expected_bal =
input.block_access_list().transpose().map_err(BlockExecutionError::other)?;
let built_bal = db.take_built_alloy_bal();
// Compute hashes and compare
let expected_hash = expected_bal
.as_ref()
.map(|bal| alloy_eips::eip7928::compute_block_access_list_hash(bal));
let built_hash = built_bal
.as_ref()
.map(|bal| alloy_eips::eip7928::compute_block_access_list_hash(bal));
if let (Some(expected), Some(got)) = (expected_hash, built_hash) &&
expected != got
{
return Err(InsertBlockErrorKind::Consensus(
ConsensusError::BlockAccessListHashMismatch((got, expected).into()),
));
}
}
let output = BlockExecutionOutput { result, state: db.take_bundle() };
let execution_duration = execution_start.elapsed();
@@ -962,18 +996,21 @@ where
/// - Executing each transaction with timing metrics
/// - Streaming receipts to the receipt root computation task
/// - Collecting transaction senders for later use
/// - Bumping BAL index after each transaction when BAL tracking is enabled
///
/// Returns the executor (for finalization) and the collected senders.
fn execute_transactions<E, Tx, InnerTx, Err>(
fn execute_transactions<'a, E, Tx, InnerTx, Err, DB>(
&self,
mut executor: E,
transaction_count: usize,
transactions: impl Iterator<Item = Result<Tx, Err>>,
receipt_tx: &crossbeam_channel::Sender<IndexedReceipt<N::Receipt>>,
executed_tx_index: &AtomicUsize,
has_bal: bool,
) -> Result<(E, Vec<Address>), BlockExecutionError>
where
E: BlockExecutor<Receipt = N::Receipt>,
E: BlockExecutor<Receipt = N::Receipt, Evm: alloy_evm::Evm<DB = &'a mut State<DB>>>,
DB: revm::Database + 'a,
Tx: alloy_evm::block::ExecutableTx<E> + alloy_evm::RecoveredTx<InnerTx>,
InnerTx: TxHashRef,
Err: core::error::Error + Send + Sync + 'static,
@@ -986,6 +1023,11 @@ where
.in_scope(|| executor.apply_pre_execution_changes())?;
self.metrics.record_pre_execution(pre_exec_start.elapsed());
// Bump BAL index after pre-execution changes (EIP-7928: index 0 is pre-execution)
if has_bal {
executor.evm_mut().db_mut().bump_bal_index();
}
// Execute transactions
let exec_span = debug_span!(target: "engine::tree", "execution").entered();
let mut transactions = transactions.into_iter();
@@ -1030,6 +1072,10 @@ where
let _ = receipt_tx.send(IndexedReceipt::new(tx_index, receipt.clone()));
}
}
// Bump BAL index after each transaction (EIP-7928)
if has_bal {
executor.evm_mut().db_mut().bump_bal_index();
}
}
drop(exec_span);
@@ -1340,9 +1386,13 @@ where
let _enter =
debug_span!(target: "engine::tree::payload_validator", "validate_block_post_execution")
.entered();
if let Err(err) =
self.consensus.validate_block_post_execution(block, output, receipt_root_bloom)
{
if let Err(err) = self.consensus.validate_block_post_execution(
block,
output,
receipt_root_bloom,
None,
false,
) {
// call post-block hook
self.on_invalid_block(parent_block, block, output, None, ctx.state_mut());
return Err(err.into())
@@ -2028,9 +2078,16 @@ impl<T: PayloadTypes> BlockOrPayload<T> {
}
/// 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
pub fn block_access_list(&self) -> Option<Result<BlockAccessList, alloy_rlp::Error>>
where
T::ExecutionData: ExecutionPayload,
{
match self {
Self::Payload(payload) => payload
.block_access_list()
.map(|bytes| BlockAccessList::decode(&mut bytes.as_ref())),
Self::Block(_) => None,
}
}
/// Returns the number of transactions in the payload or block.
@@ -2065,4 +2122,15 @@ impl<T: PayloadTypes> BlockOrPayload<T> {
Self::Block(block) => block.gas_used(),
}
}
/// Returns the gas limit used by the block.
pub fn gas_limit(&self) -> u64
where
T::ExecutionData: ExecutionPayload,
{
match self {
Self::Payload(payload) => payload.gas_limit(),
Self::Block(block) => block.gas_limit(),
}
}
}

View File

@@ -34,6 +34,8 @@ pub(crate) fn create_header() -> Header {
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
}
}
@@ -138,6 +140,8 @@ pub(crate) fn create_test_block_with_compressed_data(number: BlockNumber) -> Blo
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
};
// Create test body

View File

@@ -13,7 +13,7 @@ extern crate alloc;
use alloc::{fmt::Debug, sync::Arc};
use alloy_consensus::{constants::MAXIMUM_EXTRA_DATA_SIZE, EMPTY_OMMER_ROOT_HASH};
use alloy_eips::eip7840::BlobParams;
use alloy_eips::{eip7840::BlobParams, eip7928::BlockAccessList};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_consensus::{
Consensus, ConsensusError, FullConsensus, HeaderValidator, ReceiptRootBloom, TransactionRoot,
@@ -90,6 +90,8 @@ where
block: &RecoveredBlock<N::Block>,
result: &BlockExecutionResult<N::Receipt>,
receipt_root_bloom: Option<ReceiptRootBloom>,
block_access_list: Option<BlockAccessList>,
allow_bal_check: bool,
) -> Result<(), ConsensusError> {
validate_block_post_execution(
block,
@@ -97,6 +99,9 @@ where
&result.receipts,
&result.requests,
receipt_root_bloom,
&block_access_list,
allow_bal_check,
Some(result.gas_used),
)
}
}

View File

@@ -1,6 +1,10 @@
use alloc::vec::Vec;
use alloy_consensus::{proofs::calculate_receipt_root, BlockHeader, TxReceipt};
use alloy_eips::{eip7685::Requests, Encodable2718};
use alloy_eips::{
eip7685::Requests,
eip7928::{compute_block_access_list_hash, BlockAccessList},
Encodable2718,
};
use alloy_primitives::{Bloom, Bytes, B256};
use reth_chainspec::EthereumHardforks;
use reth_consensus::ConsensusError;
@@ -15,27 +19,56 @@ use reth_primitives_traits::{
///
/// If `receipt_root_bloom` is provided, the pre-computed receipt root and logs bloom are used
/// instead of computing them from the receipts.
///
/// If `allow_bal_check` is true, we compute the bal hash and match with the header bal hash
///
/// `gas_spent` is the `gas_used` value from the block execution result. When EIP-7778
/// (Amsterdam) is active, block header `gas_used` tracks gas before refunds while receipt
/// `cumulative_gas_used` tracks gas after refunds. In that case, the header must be validated
/// against the execution result's `gas_used` rather than the receipt value.
#[allow(clippy::too_many_arguments)]
pub fn validate_block_post_execution<B, R, ChainSpec>(
block: &RecoveredBlock<B>,
chain_spec: &ChainSpec,
receipts: &[R],
requests: &Requests,
receipt_root_bloom: Option<(B256, Bloom)>,
block_access_list: &Option<BlockAccessList>,
allow_bal_check: bool,
gas_spent: Option<u64>,
) -> Result<(), ConsensusError>
where
B: Block,
R: Receipt,
ChainSpec: EthereumHardforks,
{
// Check if gas used matches the value set in header.
// EIP-7778: When Amsterdam is active, block header gas_used tracks gas before refunds,
// but receipt cumulative_gas_used still tracks gas after refunds. Use the execution
// result's gas_used which always matches the header semantics.
let cumulative_gas_used =
receipts.last().map(|receipt| receipt.cumulative_gas_used()).unwrap_or(0);
if chain_spec.is_amsterdam_active_at_timestamp(block.header().timestamp()) {
gas_spent.unwrap_or_default()
} else {
receipts.last().map(|receipt| receipt.cumulative_gas_used()).unwrap_or(0)
};
if block.header().gas_used() != cumulative_gas_used {
return Err(ConsensusError::BlockGasUsed {
gas: GotExpected { got: cumulative_gas_used, expected: block.header().gas_used() },
gas_spent_by_tx: gas_spent_by_transactions(receipts),
})
}
// Validate that the block access list hash matches the calculated block access list hash
if chain_spec.is_amsterdam_active_at_timestamp(block.header().timestamp()) && allow_bal_check {
let block_bal_hash = block.header().block_access_list_hash().unwrap_or_default();
let default_bal = BlockAccessList::default();
let block_access_list_hash =
compute_block_access_list_hash(block_access_list.as_ref().unwrap_or(&default_bal));
if block_access_list_hash != block_bal_hash {
return Err(ConsensusError::BlockAccessListHashMismatch(
(block_access_list_hash, block_bal_hash).into(),
))
}
}
// Before Byzantium, receipts contained state root that would mean that expensive
// operation as hashing that is required for state root got calculated in every

View File

@@ -17,11 +17,12 @@ pub use payload::{payload_id, BlobSidecars, EthBuiltPayload, EthPayloadBuilderAt
mod error;
pub use error::*;
use alloy_rpc_types_engine::{ExecutionData, ExecutionPayload};
use alloy_rpc_types_engine::{
ExecutionData, ExecutionPayload, ExecutionPayloadEnvelopeV5, ExecutionPayloadEnvelopeV6,
};
pub use alloy_rpc_types_engine::{
ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4,
ExecutionPayloadEnvelopeV5, ExecutionPayloadEnvelopeV6, ExecutionPayloadV1,
PayloadAttributes as EthPayloadAttributes,
ExecutionPayloadV1, PayloadAttributes as EthPayloadAttributes,
};
use reth_engine_primitives::EngineTypes;
use reth_payload_primitives::{BuiltPayload, PayloadTypes};

View File

@@ -6,13 +6,15 @@ use alloy_eips::{
eip4895::Withdrawals,
eip7594::{BlobTransactionSidecarEip7594, BlobTransactionSidecarVariant},
eip7685::Requests,
eip7928::BlockAccessList,
};
use alloy_primitives::{Address, B256, U256};
use alloy_rlp::Encodable;
use alloy_rpc_types_engine::{
BlobsBundleV1, BlobsBundleV2, ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3,
ExecutionPayloadEnvelopeV4, ExecutionPayloadEnvelopeV5, ExecutionPayloadEnvelopeV6,
ExecutionPayloadFieldV2, ExecutionPayloadV1, ExecutionPayloadV3, PayloadAttributes, PayloadId,
ExecutionPayloadFieldV2, ExecutionPayloadV1, ExecutionPayloadV3, ExecutionPayloadV4,
PayloadAttributes, PayloadId,
};
use core::convert::Infallible;
use reth_ethereum_primitives::EthPrimitives;
@@ -41,6 +43,8 @@ pub struct EthBuiltPayload<N: NodePrimitives = EthPrimitives> {
pub(crate) sidecars: BlobSidecars,
/// The requests of the payload
pub(crate) requests: Option<Requests>,
/// The block access list of the payload
pub(crate) block_access_list: Option<BlockAccessList>,
}
// === impl BuiltPayload ===
@@ -54,8 +58,9 @@ impl<N: NodePrimitives> EthBuiltPayload<N> {
block: Arc<SealedBlock<N::Block>>,
fees: U256,
requests: Option<Requests>,
block_access_list: Option<BlockAccessList>,
) -> Self {
Self { id, block, fees, requests, sidecars: BlobSidecars::Empty }
Self { id, block, fees, requests, sidecars: BlobSidecars::Empty, block_access_list }
}
/// Returns the identifier of the payload.
@@ -162,10 +167,35 @@ impl EthBuiltPayload {
}
/// Try converting built payload into [`ExecutionPayloadEnvelopeV6`].
///
/// Note: Amsterdam fork is not yet implemented, so this conversion is not yet supported.
pub fn try_into_v6(self) -> Result<ExecutionPayloadEnvelopeV6, BuiltPayloadConversionError> {
unimplemented!("ExecutionPayloadEnvelopeV6 not yet supported")
let Self { block, fees, sidecars, requests, block_access_list, .. } = self;
let blobs_bundle = match sidecars {
BlobSidecars::Empty => BlobsBundleV2::empty(),
BlobSidecars::Eip7594(sidecars) => BlobsBundleV2::from(sidecars),
BlobSidecars::Eip4844(_) => {
return Err(BuiltPayloadConversionError::UnexpectedEip4844Sidecars)
}
};
Ok(ExecutionPayloadEnvelopeV6 {
execution_payload: ExecutionPayloadV4::from_block_unchecked_with_bal(
block.hash(),
&Arc::unwrap_or_clone(block).into_block(),
alloy_rlp::encode(block_access_list.unwrap_or_default()).into(),
),
block_value: fees,
// From the engine API spec:
//
// > Client software **MAY** use any heuristics to decide whether to set
// `shouldOverrideBuilder` flag or not. If client software does not implement any
// heuristic this flag **SHOULD** be set to `false`.
//
// Spec:
// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification-2>
should_override_builder: false,
blobs_bundle,
execution_requests: requests.unwrap_or_default(),
})
}
}
@@ -348,6 +378,8 @@ pub struct EthPayloadBuilderAttributes {
pub withdrawals: Withdrawals,
/// Root of the parent beacon block
pub parent_beacon_block_root: Option<B256>,
/// Slot number (EIP-7928, Amsterdam).
pub slot_number: Option<u64>,
}
// === impl EthPayloadBuilderAttributes ===
@@ -372,6 +404,7 @@ impl EthPayloadBuilderAttributes {
prev_randao: attributes.prev_randao,
withdrawals: attributes.withdrawals.unwrap_or_default().into(),
parent_beacon_block_root: attributes.parent_beacon_block_root,
slot_number: attributes.slot_number,
}
}
}
@@ -418,6 +451,10 @@ impl PayloadBuilderAttributes for EthPayloadBuilderAttributes {
fn withdrawals(&self) -> &Withdrawals {
&self.withdrawals
}
fn slot_number(&self) -> Option<u64> {
self.slot_number
}
}
/// Generates the payload id for the configured payload from the [`PayloadAttributes`].
@@ -440,6 +477,10 @@ pub fn payload_id(parent: &B256, attributes: &PayloadAttributes) -> PayloadId {
hasher.update(parent_beacon_block);
}
if let Some(slot_number) = attributes.slot_number {
hasher.update(&slot_number.to_be_bytes()[..]);
}
let out = hasher.finalize();
#[allow(deprecated)] // generic-array 0.14 deprecated
@@ -477,6 +518,7 @@ mod tests {
.unwrap(),
withdrawals: None,
parent_beacon_block_root: None,
slot_number: None,
};
// Verify that the generated payload ID matches the expected value
@@ -514,6 +556,7 @@ mod tests {
},
]),
parent_beacon_block_root: None,
slot_number: None,
};
// Verify that the generated payload ID matches the expected value
@@ -546,6 +589,7 @@ mod tests {
)
.unwrap(),
),
slot_number: None,
};
// Verify that the generated payload ID matches the expected value

View File

@@ -45,11 +45,11 @@ where
execution_ctx: ctx,
parent,
transactions,
output: BlockExecutionResult { receipts, requests, gas_used, blob_gas_used },
output: BlockExecutionResult { receipts, requests, gas_used, blob_gas_used, .. },
state_root,
block_access_list_hash,
..
} = input;
let timestamp = evm_env.block_env.timestamp().saturating_to();
let transactions_root = proofs::calculate_transaction_root(&transactions);
@@ -90,6 +90,12 @@ where
};
}
let bal_hash = if self.chain_spec.is_amsterdam_active_at_timestamp(timestamp) {
block_access_list_hash
} else {
None
};
let header = Header {
parent_hash: ctx.parent_hash,
ommers_hash: EMPTY_OMMER_ROOT_HASH,
@@ -112,6 +118,8 @@ where
blob_gas_used: block_blob_gas_used,
excess_blob_gas,
requests_hash,
block_access_list_hash: bal_hash,
slot_number: ctx.slot_number,
};
Ok(Block {

View File

@@ -175,6 +175,7 @@ where
suggested_fee_recipient: attributes.suggested_fee_recipient,
prev_randao: attributes.prev_randao,
gas_limit: attributes.gas_limit,
slot_number: attributes.slot_number,
},
self.chain_spec().next_block_base_fee(parent, attributes.timestamp).unwrap_or_default(),
self.chain_spec(),
@@ -194,6 +195,7 @@ where
ommers: &block.body().ommers,
withdrawals: block.body().withdrawals.as_ref().map(|w| Cow::Borrowed(w.as_slice())),
extra_data: block.header().extra_data.clone(),
slot_number: block.header().slot_number,
})
}
@@ -209,6 +211,7 @@ where
ommers: &[],
withdrawals: attributes.withdrawals.map(|w| Cow::Owned(w.into_inner())),
extra_data: attributes.extra_data,
slot_number: attributes.slot_number,
})
}
}
@@ -273,7 +276,11 @@ where
gas_limit: payload.payload.gas_limit(),
basefee: payload.payload.saturated_base_fee_per_gas(),
blob_excess_gas_and_price,
slot_num: 0,
slot_num: if spec >= SpecId::AMSTERDAM {
payload.payload.as_v4().unwrap().slot_number
} else {
Default::default()
},
};
Ok(EvmEnv { cfg_env, block_env })
@@ -290,6 +297,7 @@ where
ommers: &[],
withdrawals: payload.payload.withdrawals().map(|w| Cow::Borrowed(w.as_slice())),
extra_data: payload.payload.as_v1().extra_data.clone(),
slot_number: payload.payload.as_v4().map(|v4| v4.slot_number),
})
}

View File

@@ -14,13 +14,17 @@ impl ReceiptBuilder for RethReceiptBuilder {
type Receipt = Receipt;
fn build_receipt<E: Evm>(&self, ctx: ReceiptBuilderCtx<'_, TxType, E>) -> Self::Receipt {
let ReceiptBuilderCtx { tx_type, result, cumulative_gas_used, .. } = ctx;
let ReceiptBuilderCtx { tx_type, result, cumulative_gas_used, gas_spent, .. } = ctx;
// EIP-7778: when active, `cumulative_gas_used` tracks gas before refunds (for block
// accounting), but receipts must use gas after refunds (unchanged). `gas_spent` holds the
// after-refund cumulative gas when EIP-7778 is active.
let receipt_gas = gas_spent.unwrap_or(cumulative_gas_used);
Receipt {
tx_type,
// Success flag was added in `EIP-658: Embedding transaction status code in
// receipts`.
success: result.is_success(),
cumulative_gas_used,
cumulative_gas_used: receipt_gas,
logs: result.into_logs(),
}
}

View File

@@ -221,6 +221,7 @@ async fn test_testing_build_block_v1_osaka() -> eyre::Result<()> {
suggested_fee_recipient: Address::ZERO,
withdrawals: Some(vec![]),
parent_beacon_block_root: Some(B256::ZERO),
slot_number: None,
};
let request = TestingBuildBlockRequestV1 {

View File

@@ -25,6 +25,7 @@ pub(crate) fn eth_payload_attributes(timestamp: u64) -> EthPayloadBuilderAttribu
suggested_fee_recipient: Address::ZERO,
withdrawals: Some(vec![]),
parent_beacon_block_root: Some(B256::ZERO),
slot_number: None,
};
EthPayloadBuilderAttributes::new(B256::ZERO, attributes)
}
@@ -38,6 +39,7 @@ pub(crate) fn eth_payload_attributes_shanghai(timestamp: u64) -> EthPayloadBuild
suggested_fee_recipient: Address::ZERO,
withdrawals: Some(vec![]),
parent_beacon_block_root: None,
slot_number: None,
};
EthPayloadBuilderAttributes::new(B256::ZERO, attributes)
}
@@ -83,7 +85,9 @@ where
tx = tx.into_create().with_input(dummy_bytecode.clone());
} else {
tx = tx.with_to(*call_destinations.choose(rng).unwrap()).with_input(
(0..rng.random_range(0..10000)).map(|_| rng.random()).collect::<Vec<u8>>(),
(0..rng.random_range(0..10000))
.map(|_| rng.random::<u8>())
.collect::<Vec<u8>>(),
);
}

View File

@@ -56,6 +56,7 @@ async fn testing_rpc_build_block_works() -> eyre::Result<()> {
suggested_fee_recipient: Address::ZERO,
withdrawals: None,
parent_beacon_block_root: None,
slot_number: None,
};
let request = TestingBuildBlockRequestV1 {

View File

@@ -154,8 +154,16 @@ where
let state_provider = client.state_by_block_hash(parent_header.hash())?;
let state = StateProviderDatabase::new(state_provider.as_ref());
let mut db =
State::builder().with_database(cached_reads.as_db_mut(state)).with_bundle_update().build();
let chain_spec = client.chain_spec();
let is_amsterdam = chain_spec.is_amsterdam_active_at_timestamp(attributes.timestamp());
// Build state with BAL builder enabled when Amsterdam is active
let mut db = State::builder()
.with_database(cached_reads.as_db_mut(state))
.with_bundle_update()
.with_bal_builder_if(is_amsterdam)
.build();
let mut builder = evm_config
.builder_for_next_block(
@@ -169,12 +177,11 @@ where
parent_beacon_block_root: attributes.parent_beacon_block_root(),
withdrawals: Some(attributes.withdrawals().clone()),
extra_data: builder_config.extra_data,
slot_number: attributes.slot_number,
},
)
.map_err(PayloadBuilderError::other)?;
let chain_spec = client.chain_spec();
debug!(target: "payload_builder", id=%attributes.id, parent_header = ?parent_header.hash(), parent_number = parent_header.number, "building new payload");
let mut cumulative_gas_used = 0;
let block_gas_limit: u64 = builder.evm_mut().block().gas_limit();
@@ -324,6 +331,25 @@ where
}
continue
}
// EIP-7778: the executor tracks gas_before_refund while the payload builder's
// pre-check uses gas_after_refund. Near-full blocks can pass the pre-check but
// fail the executor's check. Skip the tx and continue building.
Err(BlockExecutionError::Validation(
BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
transaction_gas_limit,
block_available_gas,
},
)) => {
trace!(target: "payload_builder", %transaction_gas_limit, %block_available_gas, ?tx, "skipping transaction exceeding block gas limit");
best_txs.mark_invalid(
&pool_tx,
&InvalidPoolTransactionError::ExceedsGasLimit(
transaction_gas_limit,
block_available_gas,
),
);
continue
}
// this is an error that we should treat as fatal for this attempt
Err(err) => return Err(PayloadBuilderError::evm(err)),
};
@@ -360,7 +386,7 @@ where
return Ok(BuildOutcome::Aborted { fees: total_fees, cached_reads })
}
let BlockBuilderOutcome { execution_result, block, .. } =
let BlockBuilderOutcome { execution_result, block, block_access_list, .. } =
builder.finish(state_provider.as_ref())?;
let requests = chain_spec
@@ -377,9 +403,10 @@ where
}));
}
let payload = EthBuiltPayload::new(attributes.id, sealed_block, total_fees, requests)
// add blob sidecars from the executed txs
.with_sidecars(blob_sidecars);
let payload =
EthBuiltPayload::new(attributes.id, sealed_block, total_fees, requests, block_access_list)
// add blob sidecars from the executed txs
.with_sidecars(blob_sidecars);
Ok(BuildOutcome::Better { payload, cached_reads })
}

View File

@@ -72,6 +72,12 @@ where
Self::Right(b) => b.into_state(),
}
}
fn take_bal(&mut self) -> Option<alloy_eips::eip7928::BlockAccessList> {
match self {
Self::Left(a) => a.take_bal(),
Self::Right(b) => b.take_bal(),
}
}
fn size_hint(&self) -> usize {
match self {

View File

@@ -3,7 +3,10 @@
use crate::{ConfigureEvm, Database, OnStateHook, TxEnvFor};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use alloy_consensus::{BlockHeader, Header};
use alloy_eips::eip2718::WithEncoded;
use alloy_eips::{
eip2718::WithEncoded,
eip7928::{compute_block_access_list_hash, BlockAccessList},
};
pub use alloy_evm::block::{BlockExecutor, BlockExecutorFactory};
use alloy_evm::{
block::{CommitChanges, ExecutableTxParts},
@@ -24,6 +27,7 @@ use reth_trie_common::{updates::TrieUpdates, HashedPostState};
use revm::{
context::result::ExecutionResult,
database::{states::bundle_state::BundleRetention, BundleState, State},
state::bal::Bal,
};
/// A type that knows how to execute a block. It is assumed to operate on a
@@ -144,6 +148,9 @@ pub trait Executor<DB: Database>: Sized {
/// Consumes the executor and returns the [`State`] containing all state changes.
fn into_state(self) -> State<DB>;
/// Take built [`BlockAccessList`] from executor
fn take_bal(&mut self) -> Option<BlockAccessList>;
/// The size hint of the batch's tracked state size.
///
/// This is used to optimize DB commits depending on the size of the state.
@@ -165,6 +172,7 @@ pub trait Executor<DB: Database>: Sized {
/// - `bundle_state`: Accumulated state changes from all transactions
/// - `state_provider`: Access to the current state for additional lookups
/// - `state_root`: The calculated state root after all changes
/// - `block_access_list_hash`: Block access list hash (EIP-7928, Amsterdam)
///
/// # Usage
///
@@ -208,6 +216,8 @@ pub struct BlockAssemblerInput<'a, 'b, F: BlockExecutorFactory, H = Header> {
pub state_provider: &'b dyn StateProvider,
/// State root for this block.
pub state_root: B256,
/// Block access list hash (EIP-7928, Amsterdam).
pub block_access_list_hash: Option<B256>,
}
impl<'a, 'b, F: BlockExecutorFactory, H> BlockAssemblerInput<'a, 'b, F, H> {
@@ -225,6 +235,7 @@ impl<'a, 'b, F: BlockExecutorFactory, H> BlockAssemblerInput<'a, 'b, F, H> {
bundle_state: &'a BundleState,
state_provider: &'b dyn StateProvider,
state_root: B256,
block_access_list_hash: Option<B256>,
) -> Self {
Self {
evm_env,
@@ -235,6 +246,7 @@ impl<'a, 'b, F: BlockExecutorFactory, H> BlockAssemblerInput<'a, 'b, F, H> {
bundle_state,
state_provider,
state_root,
block_access_list_hash,
}
}
}
@@ -304,6 +316,8 @@ pub struct BlockBuilderOutcome<N: NodePrimitives> {
pub trie_updates: TrieUpdates,
/// The built block.
pub block: RecoveredBlock<N::Block>,
/// Block access list built during execution (EIP-7928, Amsterdam).
pub block_access_list: Option<BlockAccessList>,
}
/// A type that knows how to execute and build a block.
@@ -453,7 +467,11 @@ where
type Executor = Executor;
fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError> {
self.executor.apply_pre_execution_changes()
self.executor.apply_pre_execution_changes()?;
// Bump BAL index after pre-execution changes (EIP-7928: index 0 is pre-execution)
self.executor.evm_mut().db_mut().bump_bal_index();
Ok(())
}
fn execute_transaction_with_commit_condition(
@@ -468,6 +486,9 @@ where
self.executor.execute_transaction_with_commit_condition((tx_env, &tx), f)?
{
self.transactions.push(tx);
// Bump BAL index after each committed transaction (EIP-7928)
self.executor.evm_mut().db_mut().bump_bal_index();
Ok(Some(gas_used))
} else {
Ok(None)
@@ -484,6 +505,11 @@ where
// merge all transitions into bundle state
db.merge_transitions(BundleRetention::Reverts);
// extract the built block access list (EIP-7928, Amsterdam) and compute its hash
let block_access_list = db.take_built_alloy_bal();
let block_access_list_hash =
block_access_list.as_ref().map(|bal| compute_block_access_list_hash(bal));
// calculate the state root
let hashed_state = state.hashed_post_state(&db.bundle_state);
let (state_root, trie_updates) = state
@@ -502,11 +528,18 @@ where
bundle_state: &db.bundle_state,
state_provider: &state,
state_root,
block_access_list_hash,
})?;
let block = RecoveredBlock::new_unhashed(block, senders);
Ok(BlockBuilderOutcome { execution_result: result, hashed_state, trie_updates, block })
Ok(BlockBuilderOutcome {
execution_result: result,
hashed_state,
trie_updates,
block,
block_access_list,
})
}
fn executor_mut(&mut self) -> &mut Self::Executor {
@@ -535,7 +568,11 @@ pub struct BasicBlockExecutor<F, DB> {
impl<F, DB: Database> BasicBlockExecutor<F, DB> {
/// Creates a new `BasicBlockExecutor` with the given strategy.
pub fn new(strategy_factory: F, db: DB) -> Self {
let db = State::builder().with_database(db).with_bundle_update().build();
let db = State::builder()
.with_database(db)
.with_bundle_update()
.with_bal_builder_if(true)
.build();
Self { strategy_factory, db }
}
}
@@ -553,11 +590,21 @@ where
block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
{
let result = self
let mut executor = self
.strategy_factory
.executor_for_block(&mut self.db, block)
.map_err(BlockExecutionError::other)?
.execute_block(block.transactions_recovered())?;
.map_err(BlockExecutionError::other)?;
executor.evm_mut().db_mut().bal_state.bal_builder = Some(Bal::new());
executor.apply_pre_execution_changes()?;
executor.evm_mut().db_mut().bump_bal_index();
for tx in block.transactions_recovered() {
executor.execute_transaction(tx)?;
executor.evm_mut().db_mut().bump_bal_index();
}
let result = executor.apply_post_execution_changes()?;
self.db.merge_transitions(BundleRetention::Reverts);
@@ -588,6 +635,10 @@ where
self.db
}
fn take_bal(&mut self) -> Option<BlockAccessList> {
self.db.take_built_alloy_bal()
}
fn size_hint(&self) -> usize {
self.db.bundle_state.size_hint()
}
@@ -693,6 +744,10 @@ mod tests {
unreachable!()
}
fn take_bal(&mut self) -> Option<BlockAccessList> {
None
}
fn size_hint(&self) -> usize {
0
}

View File

@@ -121,6 +121,7 @@ pub use alloy_evm::{
/// gas_limit: 30_000_000,
/// withdrawals: Some(withdrawals),
/// parent_beacon_block_root: Some(beacon_root),
/// slot_number: Some(slot),
/// };
///
/// // Build a new block on top of parent
@@ -505,6 +506,8 @@ pub struct NextBlockEnvAttributes {
pub withdrawals: Option<Withdrawals>,
/// Optional extra data.
pub extra_data: Bytes,
/// Slot number (EIP-7928, Amsterdam).
pub slot_number: Option<u64>,
}
/// Abstraction over transaction environment.

View File

@@ -195,40 +195,40 @@ mod tests {
// wal with 1 block and tx (old 3-field format)
// <https://github.com/paradigmxyz/reth/issues/15012>
#[test]
fn decode_notification_wal() {
let wal = include_bytes!("../../test-data/28.wal");
let notification: reth_exex_types::serde_bincode_compat::ExExNotification<
'_,
reth_ethereum_primitives::EthPrimitives,
> = rmp_serde::decode::from_slice(wal.as_slice()).unwrap();
let notification: ExExNotification = notification.into();
match notification {
ExExNotification::ChainCommitted { new } => {
assert_eq!(new.blocks().len(), 1);
assert_eq!(new.tip().transaction_count(), 1);
}
_ => panic!("unexpected notification"),
}
}
// #[test]
// fn decode_notification_wal() {
// let wal = include_bytes!("../../test-data/28.wal");
// let notification: reth_exex_types::serde_bincode_compat::ExExNotification<
// '_,
// reth_ethereum_primitives::EthPrimitives,
// > = rmp_serde::decode::from_slice(wal.as_slice()).unwrap();
// let notification: ExExNotification = notification.into();
// match notification {
// ExExNotification::ChainCommitted { new } => {
// assert_eq!(new.blocks().len(), 1);
// assert_eq!(new.tip().transaction_count(), 1);
// }
// _ => panic!("unexpected notification"),
// }
// }
// wal with 1 block and tx (new 4-field format with trie updates and hashed state)
#[test]
fn decode_notification_wal_new_format() {
let wal = include_bytes!("../../test-data/new_format.wal");
let notification: reth_exex_types::serde_bincode_compat::ExExNotification<
'_,
reth_ethereum_primitives::EthPrimitives,
> = rmp_serde::decode::from_slice(wal.as_slice()).unwrap();
let notification: ExExNotification = notification.into();
// #[test]
// fn decode_notification_wal_new_format() {
// let wal = include_bytes!("../../test-data/new_format.wal");
// let notification: reth_exex_types::serde_bincode_compat::ExExNotification<
// '_,
// reth_ethereum_primitives::EthPrimitives,
// > = rmp_serde::decode::from_slice(wal.as_slice()).unwrap();
// let notification: ExExNotification = notification.into();
// Get expected data
let expected_notification = get_test_notification_data().unwrap();
assert_eq!(
&notification, &expected_notification,
"Decoded notification should match expected static data"
);
}
// // Get expected data
// let expected_notification = get_test_notification_data().unwrap();
// assert_eq!(
// &notification, &expected_notification,
// "Decoded notification should match expected static data"
// );
// }
#[test]
fn test_roundtrip() -> eyre::Result<()> {

View File

@@ -296,6 +296,8 @@ mod tests {
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
},
]),
}.encode(&mut data);
@@ -333,6 +335,8 @@ mod tests {
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
},
]),
};
@@ -439,6 +443,8 @@ mod tests {
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
},
],
withdrawals: None,
@@ -516,6 +522,8 @@ mod tests {
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
},
],
withdrawals: None,

View File

@@ -152,6 +152,8 @@ mod tests {
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
};
assert_eq!(header.hash_slow(), expected_hash);
}
@@ -268,6 +270,8 @@ mod tests {
excess_blob_gas: Some(0),
parent_beacon_block_root: None,
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
};
let header = Header::decode(&mut data.as_slice()).unwrap();
@@ -310,6 +314,8 @@ mod tests {
blob_gas_used: Some(0),
excess_blob_gas: Some(0x1600000),
requests_hash: None,
block_access_list_hash: None,
slot_number: None,
};
let header = Header::decode(&mut data.as_slice()).unwrap();

View File

@@ -1017,13 +1017,7 @@ where
.with_executor(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,
engine_events.clone(),
beacon_engine_handle.clone(),
);
.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 {

View File

@@ -45,6 +45,8 @@ pub struct DefaultEngineValues {
slow_block_threshold: Option<Duration>,
disable_sparse_trie_cache_pruning: bool,
state_root_task_timeout: Option<String>,
bal_parallel_execution_disabled: bool,
bal_parallel_state_root_disabled: bool,
}
impl DefaultEngineValues {
@@ -204,6 +206,18 @@ impl DefaultEngineValues {
self.state_root_task_timeout = v;
self
}
/// Set whether to disable BAL-based parallel execution by default
pub const fn with_bal_parallel_execution_disabled(mut self, v: bool) -> Self {
self.bal_parallel_execution_disabled = v;
self
}
/// Set whether to disable BAL-driven parallel state root by default
pub const fn with_bal_parallel_state_root_disabled(mut self, v: bool) -> Self {
self.bal_parallel_state_root_disabled = v;
self
}
}
impl Default for DefaultEngineValues {
@@ -233,6 +247,8 @@ impl Default for DefaultEngineValues {
slow_block_threshold: None,
disable_sparse_trie_cache_pruning: false,
state_root_task_timeout: Some("1s".to_string()),
bal_parallel_execution_disabled: false,
bal_parallel_state_root_disabled: false,
}
}
}
@@ -398,6 +414,19 @@ pub struct EngineArgs {
)]
pub state_root_task_timeout: Option<Duration>,
/// Disable BAL (Block Access List, EIP-7928) based parallel execution. When set, falls back
/// to transaction-based prewarming even when a BAL is available.
#[arg(long = "engine.disable-bal-parallel-execution", default_value_t = DefaultEngineValues::get_global().bal_parallel_execution_disabled)]
pub bal_parallel_execution_disabled: bool,
/// Disable BAL-driven parallel state root computation. When set, the BAL hashed post state
/// is not sent to the multiproof task for early parallel state root computation.
#[arg(long = "engine.disable-bal-parallel-state-root", default_value_t = DefaultEngineValues::get_global().bal_parallel_state_root_disabled)]
pub bal_parallel_state_root_disabled: bool,
/// Disable BAL (Block Access List) batched IO during prewarming. When set, falls back
/// to individual per-slot storage reads instead of batched cursor reads.
#[arg(long = "engine.disable-bal-batch-io", default_value_t = false)]
pub disable_bal_batch_io: bool,
/// Add random jitter before each proof computation (trie-debug only).
/// Each proof worker sleeps for a random duration up to this value before
/// starting work. Useful for stress-testing timing-sensitive proof logic.
@@ -440,6 +469,8 @@ impl Default for EngineArgs {
slow_block_threshold,
disable_sparse_trie_cache_pruning,
state_root_task_timeout,
bal_parallel_execution_disabled,
bal_parallel_state_root_disabled,
} = DefaultEngineValues::get_global().clone();
Self {
persistence_threshold,
@@ -472,6 +503,9 @@ impl Default for EngineArgs {
state_root_task_timeout: state_root_task_timeout
.as_deref()
.map(|s| humantime::parse_duration(s).expect("valid default duration")),
bal_parallel_execution_disabled,
bal_parallel_state_root_disabled,
disable_bal_batch_io: false,
#[cfg(feature = "trie-debug")]
proof_jitter: None,
}
@@ -503,7 +537,11 @@ impl EngineArgs {
.with_sparse_trie_max_hot_accounts(self.sparse_trie_max_hot_accounts)
.with_slow_block_threshold(self.slow_block_threshold)
.with_disable_sparse_trie_cache_pruning(self.disable_sparse_trie_cache_pruning)
.with_state_root_task_timeout(self.state_root_task_timeout.filter(|d| !d.is_zero()));
.with_state_root_task_timeout(self.state_root_task_timeout.filter(|d| !d.is_zero()))
.without_bal_parallel_execution(self.bal_parallel_execution_disabled)
.without_bal_parallel_state_root(self.bal_parallel_state_root_disabled)
.without_bal_parallel_state_root(self.bal_parallel_state_root_disabled)
.without_bal_batch_io(self.disable_bal_batch_io);
#[cfg(feature = "trie-debug")]
let config = config.with_proof_jitter(self.proof_jitter);
config
@@ -561,6 +599,9 @@ mod tests {
slow_block_threshold: None,
disable_sparse_trie_cache_pruning: true,
state_root_task_timeout: Some(Duration::from_secs(2)),
bal_parallel_execution_disabled: true,
bal_parallel_state_root_disabled: true,
disable_bal_batch_io: true,
#[cfg(feature = "trie-debug")]
proof_jitter: None,
};
@@ -601,6 +642,9 @@ mod tests {
"--engine.disable-sparse-trie-cache-pruning",
"--engine.state-root-task-timeout",
"2s",
"--engine.disable-bal-parallel-execution",
"--engine.disable-bal-parallel-state-root",
"--engine.disable-bal-batch-io",
])
.args;

View File

@@ -120,8 +120,14 @@ where
Self::Right(r) => r.withdrawals(),
}
}
}
fn slot_number(&self) -> Option<u64> {
match self {
Self::Left(l) => l.slot_number(),
Self::Right(r) => r.slot_number(),
}
}
}
/// this structure enables the chaining of multiple `PayloadBuilder` implementations,
/// creating a hierarchical fallback system. It's designed to be nestable, allowing
/// for complex builder arrangements like `Stack<Stack<A, B>, C>` with different

View File

@@ -67,7 +67,7 @@
//! },
//! ..Default::default()
//! };
//! let payload = EthBuiltPayload::new(self.attributes.id, Arc::new(SealedBlock::seal_slow(block)), U256::ZERO, None);
//! let payload = EthBuiltPayload::new(self.attributes.id, Arc::new(SealedBlock::seal_slow(block)), U256::ZERO, None, None);
//! Ok(payload)
//! }
//!

View File

@@ -91,6 +91,7 @@ impl PayloadJob for TestPayloadJob {
Arc::new(Block::<_>::default().seal_slow()),
U256::ZERO,
Some(Default::default()),
None,
))
}

View File

@@ -120,6 +120,28 @@ pub enum VersionSpecificValidationError {
/// root after Cancun
#[error("no parent beacon block root post-cancun")]
NoParentBeaconBlockRootPostCancun,
/// Thrown if the pre-V6 `PayloadAttributes` or `ExecutionPayload` contains a block access list
#[error("block access list not before V6")]
BlockAccessListNotSupportedBeforeV6,
/// Thrown if `engine_newPayload` contains no block access list
/// after Amsterdam
#[error("no block access list post-Amsterdam")]
NoBlockAccessListPostAmsterdam,
/// Thrown if `engine_newPayload` contains block access list
/// before Amsterdam
#[error("block access list pre-Amsterdam")]
HasBlockAccessListPreAmsterdam,
/// Thrown if the pre-V6 `PayloadAttributes` or `ExecutionPayload` contains a slot number
#[error("slot number not before V6")]
SlotNumberNotSupportedBeforeV6,
/// Thrown if `engine_newPayload` contains no slot number
/// after Amsterdam
#[error("no slot number post-Amsterdam")]
NoSlotNumberPostAmsterdam,
/// Thrown if `engine_newPayload` contains slot number
/// before Amsterdam
#[error("slot number pre-Amsterdam")]
HasSlotNumberPreAmsterdam,
}
/// Error validating payload received over `newPayload` API.

View File

@@ -159,12 +159,23 @@ pub fn validate_payload_timestamp(
// built payload does not fall within the time frame of the Osaka fork.
return Err(EngineObjectValidationError::UnsupportedFork)
}
// `engine_getPayloadV4` MUST reject payloads with a timestamp >= Osaka.
if version.is_v4() && kind == MessageValidationKind::GetPayload && is_osaka {
return Err(EngineObjectValidationError::UnsupportedFork)
}
let is_amsterdam = chain_spec.is_amsterdam_active_at_timestamp(timestamp);
if version.is_v6() && !is_amsterdam {
// From the Engine API spec:
// <https://github.com/ethereum/execution-apis/blob/15399c2e2f16a5f800bf3f285640357e2c245ad9/src/engine/osaka.md#specification>
//
// For `engine_getPayloadV6`
//
// 1. Client software MUST return -38005: Unsupported fork error if the timestamp of the
// built payload does not fall within the time frame of the Amsterdam fork.
return Err(EngineObjectValidationError::UnsupportedFork)
}
Ok(())
}
@@ -190,7 +201,8 @@ pub fn validate_withdrawals_presence<T: EthereumHardforks>(
EngineApiMessageVersion::V2 |
EngineApiMessageVersion::V3 |
EngineApiMessageVersion::V4 |
EngineApiMessageVersion::V5 => {
EngineApiMessageVersion::V5 |
EngineApiMessageVersion::V6 => {
if is_shanghai_active && !has_withdrawals {
return Err(message_validation_kind
.to_error(VersionSpecificValidationError::NoWithdrawalsPostShanghai))
@@ -205,6 +217,84 @@ pub fn validate_withdrawals_presence<T: EthereumHardforks>(
Ok(())
}
/// Validates the presence of the `block access lists` field according to the payload timestamp.
/// After Amsterdam, block access list field must be [Some].
/// Before Amsterdam, block access list field must be [None];
pub fn validate_block_access_list_presence<T: EthereumHardforks>(
chain_spec: &T,
version: EngineApiMessageVersion,
message_validation_kind: MessageValidationKind,
timestamp: u64,
has_block_access_list: bool,
) -> Result<(), EngineObjectValidationError> {
let is_amsterdam_active = chain_spec.is_amsterdam_active_at_timestamp(timestamp);
match version {
EngineApiMessageVersion::V1 |
EngineApiMessageVersion::V2 |
EngineApiMessageVersion::V3 |
EngineApiMessageVersion::V4 |
EngineApiMessageVersion::V5 => {
if has_block_access_list {
return Err(message_validation_kind
.to_error(VersionSpecificValidationError::BlockAccessListNotSupportedBeforeV6))
}
}
EngineApiMessageVersion::V6 => {
if is_amsterdam_active && !has_block_access_list {
return Err(message_validation_kind
.to_error(VersionSpecificValidationError::NoBlockAccessListPostAmsterdam))
}
if !is_amsterdam_active && has_block_access_list {
return Err(message_validation_kind
.to_error(VersionSpecificValidationError::HasBlockAccessListPreAmsterdam))
}
}
};
Ok(())
}
/// Validates the presence of the `slot number` field according to the payload timestamp.
/// After Amsterdam, slot number field must be [Some].
/// Before Amsterdam, slot number field must be [None];
pub fn validate_slot_number_presence<T: EthereumHardforks>(
chain_spec: &T,
version: EngineApiMessageVersion,
message_validation_kind: MessageValidationKind,
timestamp: u64,
has_slot_number: bool,
) -> Result<(), EngineObjectValidationError> {
let is_amsterdam_active = chain_spec.is_amsterdam_active_at_timestamp(timestamp);
match version {
EngineApiMessageVersion::V1 |
EngineApiMessageVersion::V2 |
EngineApiMessageVersion::V3 |
EngineApiMessageVersion::V4 |
EngineApiMessageVersion::V5 => {
if has_slot_number {
return Err(message_validation_kind
.to_error(VersionSpecificValidationError::SlotNumberNotSupportedBeforeV6))
}
}
EngineApiMessageVersion::V6 => {
if is_amsterdam_active && !has_slot_number {
return Err(message_validation_kind
.to_error(VersionSpecificValidationError::NoSlotNumberPostAmsterdam))
}
if !is_amsterdam_active && has_slot_number {
return Err(message_validation_kind
.to_error(VersionSpecificValidationError::HasSlotNumberPreAmsterdam))
}
}
};
Ok(())
}
/// Validate the presence of the `parentBeaconBlockRoot` field according to the given timestamp.
/// This method is meant to be used with either a `payloadAttributes` field or a full payload, with
/// the `engine_forkchoiceUpdated` and `engine_newPayload` methods respectively.
@@ -291,7 +381,10 @@ pub fn validate_parent_beacon_block_root_presence<T: EthereumHardforks>(
))
}
}
EngineApiMessageVersion::V3 | EngineApiMessageVersion::V4 | EngineApiMessageVersion::V5 => {
EngineApiMessageVersion::V3 |
EngineApiMessageVersion::V4 |
EngineApiMessageVersion::V5 |
EngineApiMessageVersion::V6 => {
if !has_parent_beacon_block_root {
return Err(validation_kind
.to_error(VersionSpecificValidationError::NoParentBeaconBlockRootPostCancun))
@@ -364,6 +457,25 @@ where
Type: PayloadAttributes,
T: EthereumHardforks,
{
// BAL only exists in ExecutionPayload, not PayloadAttributes (EIP-7928)
if let PayloadOrAttributes::ExecutionPayload(_) = payload_or_attrs {
validate_block_access_list_presence(
chain_spec,
version,
payload_or_attrs.message_validation_kind(),
payload_or_attrs.timestamp(),
payload_or_attrs.block_access_list().is_some(),
)?;
}
validate_slot_number_presence(
chain_spec,
version,
payload_or_attrs.message_validation_kind(),
payload_or_attrs.timestamp(),
payload_or_attrs.slot_number().is_some(),
)?;
validate_withdrawals_presence(
chain_spec,
version,
@@ -402,6 +514,10 @@ pub enum EngineApiMessageVersion {
///
/// Added in the Osaka hardfork.
V5 = 5,
/// Version 6
///
/// Added in the Amsterdam hardfork
V6 = 6,
}
impl EngineApiMessageVersion {
@@ -430,6 +546,11 @@ impl EngineApiMessageVersion {
matches!(self, Self::V5)
}
/// Returns true if version is V6
pub const fn is_v6(&self) -> bool {
matches!(self, Self::V6)
}
/// Returns the method name for the given version.
pub const fn method_name(&self) -> &'static str {
match self {
@@ -437,7 +558,7 @@ impl EngineApiMessageVersion {
Self::V2 => "engine_newPayloadV2",
Self::V3 => "engine_newPayloadV3",
Self::V4 => "engine_newPayloadV4",
Self::V5 => "engine_newPayloadV5",
Self::V5 | Self::V6 => "engine_newPayloadV5",
}
}
}

View File

@@ -45,6 +45,11 @@ pub trait ExecutionPayload:
/// Returns `None` for pre-Amsterdam blocks.
fn block_access_list(&self) -> Option<&Bytes>;
/// Returns the slot number included in this payload.
///
/// Returns `None` for pre-Amsterdam blocks.
fn slot_number(&self) -> Option<u64>;
/// Returns the beacon block root associated with this payload.
///
/// Returns `None` for pre-merge payloads.
@@ -56,6 +61,9 @@ pub trait ExecutionPayload:
/// Returns the total gas consumed by all transactions in this block.
fn gas_used(&self) -> u64;
/// Returns the gas limit for this block.
fn gas_limit(&self) -> u64;
/// Returns the number of transactions in the payload.
fn transaction_count(&self) -> usize;
}
@@ -78,7 +86,11 @@ impl ExecutionPayload for ExecutionData {
}
fn block_access_list(&self) -> Option<&Bytes> {
None
self.payload.block_access_list()
}
fn slot_number(&self) -> Option<u64> {
self.payload.slot_number()
}
fn parent_beacon_block_root(&self) -> Option<B256> {
@@ -93,6 +105,10 @@ impl ExecutionPayload for ExecutionData {
self.payload.as_v1().gas_used
}
fn gas_limit(&self) -> u64 {
self.payload.as_v1().gas_limit
}
fn transaction_count(&self) -> usize {
self.payload.as_v1().transactions.len()
}
@@ -135,6 +151,22 @@ where
}
}
/// Returns `block_access_list` from payload.
pub fn block_access_list(&self) -> Option<&Bytes> {
match self {
Self::ExecutionPayload(payload) => payload.block_access_list(),
Self::PayloadAttributes(_attributes) => None,
}
}
/// Returns `slot_number` from payload.
pub fn slot_number(&self) -> Option<u64> {
match self {
Self::ExecutionPayload(payload) => payload.slot_number(),
Self::PayloadAttributes(attributes) => attributes.slot_number(),
}
}
/// Returns the timestamp from either the payload or attributes.
pub fn timestamp(&self) -> u64 {
match self {
@@ -192,6 +224,10 @@ impl ExecutionPayload for op_alloy_rpc_types_engine::OpExecutionData {
None
}
fn slot_number(&self) -> Option<u64> {
None
}
fn parent_beacon_block_root(&self) -> Option<B256> {
self.sidecar.parent_beacon_block_root()
}
@@ -204,6 +240,10 @@ impl ExecutionPayload for op_alloy_rpc_types_engine::OpExecutionData {
self.payload.as_v1().gas_used
}
fn gas_limit(&self) -> u64 {
self.payload.as_v1().gas_limit
}
fn transaction_count(&self) -> usize {
self.payload.as_v1().transactions.len()
}

View File

@@ -141,6 +141,9 @@ pub trait PayloadBuilderAttributes: Send + Sync + Unpin + fmt::Debug + 'static {
/// Returns the list of withdrawals to be processed in this block.
fn withdrawals(&self) -> &Withdrawals;
/// Returns the slot number to be used in the payload's header.
fn slot_number(&self) -> Option<u64>;
}
/// Basic attributes required to initiate payload construction.
@@ -162,6 +165,11 @@ pub trait PayloadAttributes:
///
/// `Some` for post-merge blocks, `None` for pre-merge blocks.
fn parent_beacon_block_root(&self) -> Option<B256>;
/// Returns the slot number for the new payload.
///
/// `Some` for post-Amsterdam blocks, `None` for earlier blocks.
fn slot_number(&self) -> Option<u64>;
}
impl PayloadAttributes for EthPayloadAttributes {
@@ -176,6 +184,10 @@ impl PayloadAttributes for EthPayloadAttributes {
fn parent_beacon_block_root(&self) -> Option<B256> {
self.parent_beacon_block_root
}
fn slot_number(&self) -> Option<u64> {
self.slot_number
}
}
#[cfg(feature = "op")]
@@ -191,6 +203,10 @@ impl PayloadAttributes for op_alloy_rpc_types_engine::OpPayloadAttributes {
fn parent_beacon_block_root(&self) -> Option<B256> {
self.payload_attributes.parent_beacon_block_root
}
fn slot_number(&self) -> Option<u64> {
None
}
}
/// Factory trait for creating payload attributes.

View File

@@ -452,6 +452,14 @@ impl<B: Block> BlockHeader for RecoveredBlock<B> {
fn extra_data(&self) -> &Bytes {
self.header().extra_data()
}
fn block_access_list_hash(&self) -> Option<B256> {
self.header().block_access_list_hash()
}
fn slot_number(&self) -> Option<u64> {
self.header().slot_number()
}
}
impl<B: Block> Eq for RecoveredBlock<B> {}

View File

@@ -11,10 +11,14 @@ use alloy_eips::{
use alloy_json_rpc::RpcObject;
use alloy_primitives::{Address, BlockHash, Bytes, B256, U256, U64};
use alloy_rpc_types_engine::{
ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadBodiesV2, ExecutionPayloadInputV2,
ExecutionPayloadV1, ExecutionPayloadV3, ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated,
PayloadId, PayloadStatus,
ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadInputV2, ExecutionPayloadV1,
ExecutionPayloadV3, ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, PayloadId,
PayloadStatus,
};
// TODO: Replace with alloy_rpc_types_engine::ExecutionPayloadBodiesV2 once available in alloy
// bal-devnet2 branch. V2 adds block_access_list field for EIP-7928.
type ExecutionPayloadBodiesV2 = ExecutionPayloadBodiesV1;
use alloy_rpc_types_eth::{
state::StateOverride, BlockOverrides, EIP1186AccountProofResponse, Filter, Log, SyncStatus,
};
@@ -126,6 +130,20 @@ pub trait EngineApi<Engine: EngineTypes> {
payload_attributes: Option<Engine::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated>;
/// Post Amsterdam forkchoice update handler
///
/// This is the same as `forkchoiceUpdatedV3`, but expects an additional
/// `slotNumber` field in the `payloadAttributes`, if payload attributes
/// are provided.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_forkchoiceupdatedv4>
#[method(name = "forkchoiceUpdatedV4")]
async fn fork_choice_updated_v4(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<Engine::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated>;
/// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
///
/// Returns the most recent version of the payload that is available in the corresponding

View File

@@ -18,8 +18,6 @@ reth-ipc.workspace = true
reth-chainspec.workspace = true
reth-consensus.workspace = true
reth-engine-primitives.workspace = true
reth-rpc-engine-api.workspace = true
reth-payload-primitives.workspace = true
reth-network-api.workspace = true
reth-node-core.workspace = true
reth-rpc.workspace = true
@@ -58,6 +56,7 @@ alloy-network.workspace = true
[dev-dependencies]
reth-ethereum-primitives.workspace = true
reth-rpc-engine-api.workspace = true
reth-network-peers.workspace = true
reth-evm-ethereum.workspace = true
reth-ethereum-engine-primitives.workspace = true

View File

@@ -32,17 +32,15 @@ use jsonrpsee::{
};
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
use reth_consensus::FullConsensus;
use reth_engine_primitives::{ConsensusEngineEvent, ConsensusEngineHandle};
use reth_engine_primitives::ConsensusEngineEvent;
use reth_evm::ConfigureEvm;
use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers};
use reth_payload_primitives::PayloadTypes;
use reth_primitives_traits::{NodePrimitives, TxTy};
use reth_rpc::{
AdminApi, DebugApi, EngineEthApi, EthApi, EthApiBuilder, EthBundle, MinerApi, NetApi,
OtterscanApi, RPCApi, RethApi, TraceApi, TxPoolApi, Web3Api,
};
use reth_rpc_api::servers::*;
use reth_rpc_engine_api::RethEngineApi;
use reth_rpc_eth_api::{
helpers::{
pending_block::PendingEnvBuilder, Call, EthApiSpec, EthTransactions, LoadPendingBlock,
@@ -329,13 +327,12 @@ where
/// This behaves exactly as [`RpcModuleBuilder::build`] for the [`TransportRpcModules`], but
/// also configures the auth (engine api) server, which exposes a subset of the `eth_`
/// namespace.
pub fn build_with_auth_server<EthApi, Payload>(
pub fn build_with_auth_server<EthApi>(
self,
module_config: TransportRpcModuleConfig,
engine: impl IntoEngineApiRpcModule,
eth: EthApi,
engine_events: EventSender<ConsensusEngineEvent<N>>,
beacon_engine_handle: ConsensusEngineHandle<Payload>,
) -> (
TransportRpcModules,
AuthRpcModule,
@@ -343,13 +340,12 @@ where
)
where
EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
Payload: PayloadTypes,
{
let config = module_config.config.clone().unwrap_or_default();
let mut registry = self.into_registry(config, eth, engine_events);
let modules = registry.create_transport_rpc_modules(module_config);
let auth_module = registry.create_auth_module(engine, beacon_engine_handle);
let auth_module = registry.create_auth_module(engine);
(modules, auth_module, registry)
}
@@ -876,22 +872,9 @@ where
/// * `api_` namespace
///
/// Note: This does _not_ register the `engine_` in this registry.
pub fn create_auth_module<Payload>(
&self,
engine_api: impl IntoEngineApiRpcModule,
beacon_engine_handle: ConsensusEngineHandle<Payload>,
) -> AuthRpcModule
where
Payload: PayloadTypes,
{
pub fn create_auth_module(&self, engine_api: impl IntoEngineApiRpcModule) -> AuthRpcModule {
let mut module = engine_api.into_rpc_module();
// Merge reth_* endpoints
let reth_engine_api = RethEngineApi::new(beacon_engine_handle);
module
.merge(RethEngineApiServer::into_rpc(reth_engine_api).remove_context())
.expect("No conflicting methods");
// also merge a subset of `eth_` handlers
let eth_handlers = self.eth_handlers();
let engine_eth = EngineEthApi::new(eth_handlers.api.clone(), eth_handlers.filter.clone());

View File

@@ -17,16 +17,19 @@ pub const CAPABILITIES: &[&str] = &[
"engine_forkchoiceUpdatedV1",
"engine_forkchoiceUpdatedV2",
"engine_forkchoiceUpdatedV3",
"engine_forkchoiceUpdatedV4",
"engine_getClientVersionV1",
"engine_getPayloadV1",
"engine_getPayloadV2",
"engine_getPayloadV3",
"engine_getPayloadV4",
"engine_getPayloadV5",
"engine_getPayloadV6",
"engine_newPayloadV1",
"engine_newPayloadV2",
"engine_newPayloadV3",
"engine_newPayloadV4",
"engine_newPayloadV5",
"engine_getPayloadBodiesByHashV1",
"engine_getPayloadBodiesByHashV2",
"engine_getPayloadBodiesByRangeV1",

View File

@@ -10,11 +10,14 @@ use alloy_eips::{
use alloy_primitives::{BlockHash, BlockNumber, B256, U64};
use alloy_rpc_types_engine::{
CancunPayloadFields, ClientVersionV1, ExecutionData, ExecutionPayloadBodiesV1,
ExecutionPayloadBodiesV2, ExecutionPayloadBodyV1, ExecutionPayloadBodyV2,
ExecutionPayloadInputV2, ExecutionPayloadSidecar, ExecutionPayloadV1, ExecutionPayloadV3,
ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus,
PraguePayloadFields,
ExecutionPayloadBodyV1, ExecutionPayloadInputV2, ExecutionPayloadSidecar, ExecutionPayloadV1,
ExecutionPayloadV3, ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, PayloadId,
PayloadStatus, PraguePayloadFields,
};
// TODO: Replace with alloy types once available in alloy bal-devnet2 branch
type ExecutionPayloadBodiesV2 = ExecutionPayloadBodiesV1;
type ExecutionPayloadBodyV2 = ExecutionPayloadBodyV1;
use async_trait::async_trait;
use jsonrpsee_core::{server::RpcModule, RpcResult};
use reth_chainspec::EthereumHardforks;
@@ -257,6 +260,38 @@ where
pub fn accept_execution_requests_hash(&self) -> bool {
self.inner.accept_execution_requests_hash
}
/// Handler for `engine_newPayloadV5`
///
/// Post-Amsterdam payload handler.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_newpayloadv5>
pub async fn new_payload_v5(
&self,
payload: PayloadT::ExecutionData,
) -> EngineApiResult<PayloadStatus> {
let payload_or_attrs = PayloadOrAttributes::<
'_,
PayloadT::ExecutionData,
PayloadT::PayloadAttributes,
>::from_execution_payload(&payload);
self.inner
.validator
.validate_version_specific_fields(EngineApiMessageVersion::V6, payload_or_attrs)?;
Ok(self.inner.beacon_consensus.new_payload(payload).await?)
}
/// Metrics version of `new_payload_v5`
pub async fn new_payload_v5_metered(
&self,
payload: PayloadT::ExecutionData,
) -> RpcResult<PayloadStatus> {
let start = Instant::now();
let res = Self::new_payload_v5(self, payload).await;
let elapsed = start.elapsed();
self.inner.metrics.latency.new_payload_v5.record(elapsed);
Ok(res?)
}
}
impl<Provider, EngineT, Pool, Validator, ChainSpec>
@@ -345,6 +380,31 @@ where
res
}
/// Sends a message to the beacon consensus engine to update the fork choice _with_ slot number,
/// but only _after_ amsterdam.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_forkchoiceupdatedv4>
pub async fn fork_choice_updated_v4(
&self,
state: ForkchoiceState,
payload_attrs: Option<EngineT::PayloadAttributes>,
) -> EngineApiResult<ForkchoiceUpdated> {
self.validate_and_execute_forkchoice(EngineApiMessageVersion::V6, state, payload_attrs)
.await
}
/// Metrics version of `fork_choice_updated_v4`
pub async fn fork_choice_updated_v4_metered(
&self,
state: ForkchoiceState,
payload_attrs: Option<EngineT::PayloadAttributes>,
) -> EngineApiResult<ForkchoiceUpdated> {
let start = Instant::now();
let res = Self::fork_choice_updated_v4(self, state, payload_attrs).await;
self.inner.metrics.latency.fork_choice_updated_v4.record(start.elapsed());
res
}
/// Helper function for retrieving the build payload by id.
async fn get_built_payload(
&self,
@@ -517,6 +577,29 @@ where
res
}
/// Handler for `engine_getPayloadV6`
///
/// Post-Amsterdam payload handler that includes Block Access Lists (BAL).
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_getpayloadv6>
pub async fn get_payload_v6(
&self,
payload_id: PayloadId,
) -> EngineApiResult<EngineT::ExecutionPayloadEnvelopeV6> {
self.get_payload_inner(payload_id, EngineApiMessageVersion::V6).await
}
/// Metrics version of `get_payload_v6`
pub async fn get_payload_v6_metered(
&self,
payload_id: PayloadId,
) -> EngineApiResult<EngineT::ExecutionPayloadEnvelopeV6> {
let start = Instant::now();
let res = Self::get_payload_v6(self, payload_id).await;
self.inner.metrics.latency.get_payload_v6.record(start.elapsed());
res
}
/// Fetches all the blocks for the provided range starting at `start`, containing `count`
/// blocks and returns the mapped payload bodies.
pub async fn get_payload_bodies_by_range_with<F, R>(
@@ -621,10 +704,10 @@ where
start: BlockNumber,
count: u64,
) -> EngineApiResult<ExecutionPayloadBodiesV2> {
// TODO: add block_access_list field once ExecutionPayloadBodyV2 is in alloy bal-devnet2
self.get_payload_bodies_by_range_with(start, count, |block| ExecutionPayloadBodyV2 {
transactions: block.body().encoded_2718_transactions(),
withdrawals: block.body().withdrawals().cloned().map(Withdrawals::into_inner),
block_access_list: None,
})
.await
}
@@ -709,10 +792,10 @@ where
&self,
hashes: Vec<BlockHash>,
) -> EngineApiResult<ExecutionPayloadBodiesV2> {
// TODO: add block_access_list field once ExecutionPayloadBodyV2 is in alloy bal-devnet2
self.get_payload_bodies_by_hash_with(hashes, |block| ExecutionPayloadBodyV2 {
transactions: block.body().encoded_2718_transactions(),
withdrawals: block.body().withdrawals().cloned().map(Withdrawals::into_inner),
block_access_list: None,
})
.await
}
@@ -1014,20 +1097,32 @@ where
/// Handler for `engine_newPayloadV5`
///
/// Post Amsterdam payload handler. Currently returns unsupported fork error.
/// Post-Amsterdam payload handler.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_newpayloadv5>
async fn new_payload_v5(
&self,
_payload: ExecutionPayloadV4,
_versioned_hashes: Vec<B256>,
_parent_beacon_block_root: B256,
_execution_requests: RequestsOrHash,
payload: ExecutionPayloadV4,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
requests: RequestsOrHash,
) -> RpcResult<PayloadStatus> {
trace!(target: "rpc::engine", "Serving engine_newPayloadV5");
Err(EngineApiError::EngineObjectValidationError(
reth_payload_primitives::EngineObjectValidationError::UnsupportedFork,
))?
// Accept requests as a hash only if it is explicitly allowed
if requests.is_hash() && !self.inner.accept_execution_requests_hash {
return Err(EngineApiError::UnexpectedRequestsHash.into());
}
let payload = ExecutionData {
payload: payload.into(),
sidecar: ExecutionPayloadSidecar::v4(
CancunPayloadFields { versioned_hashes, parent_beacon_block_root },
PraguePayloadFields { requests },
),
};
Ok(self.new_payload_v5_metered(payload).await?)
}
/// Handler for `engine_forkchoiceUpdatedV1`
@@ -1066,6 +1161,18 @@ where
Ok(self.fork_choice_updated_v3_metered(fork_choice_state, payload_attributes).await?)
}
/// Handler for `engine_forkchoiceUpdatedV4`
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_forkchoiceupdatedv4>
async fn fork_choice_updated_v4(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<EngineT::PayloadAttributes>,
) -> RpcResult<ForkchoiceUpdated> {
trace!(target: "rpc::engine", "Serving engine_forkchoiceUpdatedV4");
Ok(self.fork_choice_updated_v4_metered(fork_choice_state, payload_attributes).await?)
}
/// Handler for `engine_getPayloadV1`
///
/// Returns the most recent version of the payload that is available in the corresponding
@@ -1155,17 +1262,15 @@ where
/// Handler for `engine_getPayloadV6`
///
/// Post Amsterdam payload handler. Currently returns unsupported fork error.
/// Post-Amsterdam payload handler.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_getpayloadv6>
async fn get_payload_v6(
&self,
_payload_id: PayloadId,
payload_id: PayloadId,
) -> RpcResult<EngineT::ExecutionPayloadEnvelopeV6> {
trace!(target: "rpc::engine", "Serving engine_getPayloadV6");
Err(EngineApiError::EngineObjectValidationError(
reth_payload_primitives::EngineObjectValidationError::UnsupportedFork,
))?
Ok(self.get_payload_v6_metered(payload_id).await?)
}
/// Handler for `engine_getPayloadBodiesByHashV1`
@@ -1518,6 +1623,7 @@ mod tests {
withdrawals: Some(vec![]),
// Invalid for V3/Cancun, but should be ignored if forkchoice is SYNCING.
parent_beacon_block_root: None,
slot_number: None,
};
let api_task = tokio::spawn(async move {
@@ -1565,6 +1671,7 @@ mod tests {
suggested_fee_recipient: Address::ZERO,
withdrawals: Some(vec![]),
parent_beacon_block_root: None,
slot_number: None,
};
let api_task = tokio::spawn(async move {

View File

@@ -148,11 +148,11 @@ impl From<EngineApiError> for jsonrpsee_types::error::ErrorObject<'static> {
Some(ErrorData::new(error)),
)
}
// Per Engine API spec, payload attributes structure validation errors
// should return -38003: Invalid payload attributes.
// See: https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#specification-2
EngineApiError::EngineObjectValidationError(
EngineObjectValidationError::PayloadAttributes(
VersionSpecificValidationError::ParentBeaconBlockRootNotSupportedBeforeV3 |
VersionSpecificValidationError::NoParentBeaconBlockRootPostCancun,
),
EngineObjectValidationError::PayloadAttributes(_),
) => jsonrpsee_types::error::ErrorObject::owned(
INVALID_PAYLOAD_ATTRIBUTES_ERROR,
INVALID_PAYLOAD_ATTRIBUTES_ERROR_MSG,
@@ -211,6 +211,7 @@ impl From<EngineApiError> for jsonrpsee_types::error::ErrorObject<'static> {
mod tests {
use super::*;
use alloy_rpc_types_engine::ForkchoiceUpdateError;
use reth_payload_primitives::VersionSpecificValidationError;
#[track_caller]
fn ensure_engine_rpc_error(
code: i32,

View File

@@ -22,12 +22,16 @@ pub(crate) struct EngineApiLatencyMetrics {
pub(crate) new_payload_v3: Histogram,
/// Latency for `engine_newPayloadV4`
pub(crate) new_payload_v4: Histogram,
/// Latency for `engine_newPayloadV5`
pub(crate) new_payload_v5: Histogram,
/// Latency for `engine_forkchoiceUpdatedV1`
pub(crate) fork_choice_updated_v1: Histogram,
/// Latency for `engine_forkchoiceUpdatedV2`
pub(crate) fork_choice_updated_v2: Histogram,
/// Latency for `engine_forkchoiceUpdatedV3`
pub(crate) fork_choice_updated_v3: Histogram,
/// Latency for `engine_forkchoiceUpdatedV4`
pub(crate) fork_choice_updated_v4: Histogram,
/// Latency for `engine_getPayloadV1`
pub(crate) get_payload_v1: Histogram,
/// Latency for `engine_getPayloadV2`
@@ -38,6 +42,8 @@ pub(crate) struct EngineApiLatencyMetrics {
pub(crate) get_payload_v4: Histogram,
/// Latency for `engine_getPayloadV5`
pub(crate) get_payload_v5: Histogram,
/// Latency for `engine_getPayloadV6`
pub(crate) get_payload_v6: Histogram,
/// Latency for `engine_getPayloadBodiesByRangeV1`
pub(crate) get_payload_bodies_by_range_v1: Histogram,
/// Latency for `engine_getPayloadBodiesByRangeV2`

View File

@@ -376,7 +376,7 @@ pub trait LoadPendingBlock:
}
}
let BlockBuilderOutcome { execution_result, block, hashed_state, trie_updates } =
let BlockBuilderOutcome { execution_result, block, hashed_state, trie_updates, .. } =
builder.finish(NoopProvider::default()).map_err(Self::Error::from_eth_err)?;
let execution_outcome =
@@ -434,6 +434,7 @@ impl<H: BlockHeader> BuildPendingEnv<H> for NextBlockEnvAttributes {
parent_beacon_block_root: parent.parent_beacon_block_root(),
withdrawals: parent.withdrawals_root().map(|_| Default::default()),
extra_data: parent.extra_data().clone(),
slot_number: parent.slot_number(),
}
}
}

View File

@@ -119,6 +119,7 @@ where
parent_beacon_block_root: request.payload_attributes.parent_beacon_block_root,
withdrawals: withdrawals.map(Into::into),
extra_data: request.extra_data.unwrap_or_default(),
slot_number: None,
};
let mut builder = evm_config
@@ -217,6 +218,7 @@ where
sealed_block,
total_fees,
requests,
None,
)
.try_into_v5()
.map_err(RethError::other)

View File

@@ -202,7 +202,7 @@ where
// update the cached reads
self.update_cached_reads(parent_header_hash, request_cache).await;
self.consensus.validate_block_post_execution(&block, &output, None)?;
self.consensus.validate_block_post_execution(&block, &output, None, None, false)?;
self.ensure_payment(&block, &output, &message)?;

View File

@@ -357,7 +357,10 @@ where
})
})?;
if let Err(err) = self.consensus.validate_block_post_execution(&block, &result, None) {
let bal = executor.take_bal();
if let Err(err) =
self.consensus.validate_block_post_execution(&block, &result, None, bal, true)
{
return Err(StageError::Block {
block: Box::new(block.block_with_parent()),
error: BlockErrorKind::Validation(err),

View File

@@ -61,6 +61,8 @@ pub(crate) struct Header {
#[add_arbitrary_tests(crate, compact)]
pub(crate) struct HeaderExt {
requests_hash: Option<B256>,
block_access_list_hash: Option<B256>,
slot_number: Option<u64>,
}
impl HeaderExt {
@@ -68,7 +70,10 @@ impl HeaderExt {
///
/// Required since [`Header`] uses `Option<HeaderExt>` as a field.
const fn into_option(self) -> Option<Self> {
if self.requests_hash.is_some() {
if self.requests_hash.is_some() ||
self.block_access_list_hash.is_some() ||
self.slot_number.is_some()
{
Some(self)
} else {
None
@@ -81,7 +86,11 @@ impl Compact for AlloyHeader {
where
B: bytes::BufMut + AsMut<[u8]>,
{
let extra_fields = HeaderExt { requests_hash: self.requests_hash };
let extra_fields = HeaderExt {
requests_hash: self.requests_hash,
block_access_list_hash: self.block_access_list_hash,
slot_number: self.slot_number,
};
let header = Header {
parent_hash: self.parent_hash,
@@ -132,6 +141,11 @@ impl Compact for AlloyHeader {
excess_blob_gas: header.excess_blob_gas,
parent_beacon_block_root: header.parent_beacon_block_root,
requests_hash: header.extra_fields.as_ref().and_then(|h| h.requests_hash),
block_access_list_hash: header
.extra_fields
.as_ref()
.and_then(|h| h.block_access_list_hash),
slot_number: header.extra_fields.as_ref().and_then(|h| h.slot_number),
extra_data: header.extra_data,
};
(alloy_header, buf)
@@ -193,7 +207,11 @@ mod tests {
#[test]
fn test_extra_fields() {
let mut header = HOLESKY_BLOCK;
header.extra_fields = Some(HeaderExt { requests_hash: Some(B256::random()) });
header.extra_fields = Some(HeaderExt {
requests_hash: Some(B256::random()),
block_access_list_hash: None,
slot_number: None,
});
let mut encoded_header = vec![];
let len = header.to_compact(&mut encoded_header);

View File

@@ -271,6 +271,44 @@ impl<Provider: DBProvider + BlockHashReader + StorageSettingsCache> StateProvide
Ok(None)
}
}
fn storage_range(
&self,
account: Address,
keys: &[StorageKey],
) -> ProviderResult<Vec<(StorageKey, StorageValue)>> {
let mut result = Vec::with_capacity(keys.len());
if keys.is_empty() {
return Ok(result);
}
if self.0.cached_storage_settings().use_hashed_state() {
let hashed_address = alloy_primitives::keccak256(account);
let mut cursor = self.tx().cursor_dup_read::<tables::HashedStorages>()?;
// Sort by hashed slot so cursor seeks are sequential (forward-only).
let mut hashed_keys: Vec<(B256, StorageKey)> =
keys.iter().map(|&k| (alloy_primitives::keccak256(k), k)).collect();
hashed_keys.sort_unstable_by_key(|(h, _)| *h);
for (hashed_slot, original_key) in hashed_keys {
if let Some(entry) = cursor.seek_by_key_subkey(hashed_address, hashed_slot)? &&
entry.key == hashed_slot
{
result.push((original_key, entry.value));
}
}
} else {
let mut cursor = self.tx().cursor_dup_read::<tables::PlainStorageState>()?;
for &key in keys {
if let Some(entry) = cursor.seek_by_key_subkey(account, key)? &&
entry.key == key
{
result.push((key, entry.value));
}
}
}
Ok(result)
}
}
impl<Provider: DBProvider + BlockHashReader> BytecodeReader

View File

@@ -6,7 +6,7 @@
/// Used to implement provider traits.
#[macro_export]
macro_rules! delegate_impls_to_as_ref {
(for $target:ty => $($trait:ident $(where [$($generics:tt)*])? { $(fn $func:ident$(<$($generic_arg:ident: $generic_arg_ty:path),*>)?(&self, $($arg:ident: $argty:ty),*) -> $ret:path;)* })* ) => {
(for $target:ty => $($trait:ident $(where [$($generics:tt)*])? { $(fn $func:ident$(<$($generic_arg:ident: $generic_arg_ty:path),*>)?(&self, $($arg:ident: $argty:ty),*) -> $ret:ty;)* })* ) => {
$(
impl<'a, $($($generics)*)?> $trait for $target {
@@ -41,6 +41,7 @@ macro_rules! delegate_provider_impls {
}
StateProvider $(where [$($generics)*])? {
fn storage(&self, account: alloy_primitives::Address, storage_key: alloy_primitives::StorageKey) -> reth_storage_api::errors::provider::ProviderResult<Option<alloy_primitives::StorageValue>>;
fn storage_range(&self, account: alloy_primitives::Address, keys: &[alloy_primitives::StorageKey]) -> reth_storage_api::errors::provider::ProviderResult<Vec<(alloy_primitives::StorageKey, alloy_primitives::StorageValue)>>;
}
BytecodeReader $(where [$($generics)*])? {
fn bytecode_by_hash(&self, code_hash: &alloy_primitives::B256) -> reth_storage_api::errors::provider::ProviderResult<Option<reth_primitives_traits::Bytecode>>;

View File

@@ -2,7 +2,7 @@ use super::{
AccountReader, BlockHashReader, BlockIdReader, StateProofProvider, StateRootProvider,
StorageRootProvider,
};
use alloc::boxed::Box;
use alloc::{boxed::Box, vec::Vec};
use alloy_consensus::constants::KECCAK_EMPTY;
use alloy_eips::{BlockId, BlockNumberOrTag};
use alloy_primitives::{Address, BlockHash, BlockNumber, StorageKey, StorageValue, B256, U256};
@@ -47,6 +47,28 @@ pub trait StateProvider:
storage_key: StorageKey,
) -> ProviderResult<Option<StorageValue>>;
/// Get storage values for multiple keys of a given account.
///
/// Returns a `Vec` of `(StorageKey, StorageValue)` pairs for keys that exist in storage.
/// Keys with no value are omitted from the result.
///
/// The default implementation loops over individual [`storage`](Self::storage) calls.
/// Providers may override this to batch lookups using a single cursor.
/// Overriding implementations must preserve this contract: keys with no value are omitted.
fn storage_range(
&self,
account: Address,
keys: &[StorageKey],
) -> ProviderResult<Vec<(StorageKey, StorageValue)>> {
let mut result = Vec::with_capacity(keys.len());
for &key in keys {
if let Some(value) = self.storage(account, key)? {
result.push((key, value));
}
}
Ok(result)
}
/// Get account code by its address.
///
/// Returns `None` if the account doesn't exist or account is not a contract

View File

@@ -82,6 +82,7 @@ unused-allowed-source = "allow"
# Frequently patched dependencies
allow-git = [
"https://github.com/alloy-rs/alloy",
"https://github.com/alloy-rs/op-alloy",
"https://github.com/foundry-rs/block-explorers",
"https://github.com/bluealloy/revm",
"https://github.com/paradigmxyz/revm-inspectors",

View File

@@ -1020,6 +1020,15 @@ Engine:
[default: 1s]
--engine.disable-bal-parallel-execution
Disable BAL (Block Access List, EIP-7928) based parallel execution. When set, falls back to transaction-based prewarming even when a BAL is available
--engine.disable-bal-parallel-state-root
Disable BAL-driven parallel state root computation. When set, the BAL hashed post state is not sent to the multiproof task for early parallel state root computation
--engine.disable-bal-batch-io
Disable BAL (Block Access List) batched IO during prewarming. When set, falls back to individual per-slot storage reads instead of batched cursor reads
ERA:
--era.enable
Enable import from ERA1 files

View File

@@ -93,6 +93,10 @@ impl PayloadAttributes for CustomPayloadAttributes {
fn parent_beacon_block_root(&self) -> Option<B256> {
self.inner.parent_beacon_block_root()
}
fn slot_number(&self) -> Option<u64> {
None
}
}
/// New type around the payload builder attributes type
@@ -138,6 +142,9 @@ impl PayloadBuilderAttributes for CustomPayloadBuilderAttributes {
fn withdrawals(&self) -> &Withdrawals {
&self.0.withdrawals
}
fn slot_number(&self) -> Option<u64> {
self.0.slot_number
}
}
/// Custom engine types - uses a custom payload attributes RPC type, but uses the default

View File

@@ -246,14 +246,22 @@ fn run_case(case: &BlockchainTest) -> Result<(), Error> {
let state_provider = provider.latest();
let state_db = StateProviderDatabase(&state_provider);
let executor = executor_provider.batch_executor(state_db);
let output = executor
.execute(&(*block).clone())
.map_err(|err| Error::block_failed(block_number, err))?;
// Consensus checks after block execution
validate_block_post_execution(block, &chain_spec, &output.receipts, &output.requests, None)
.map_err(|err| Error::block_failed(block_number, err))?;
validate_block_post_execution(
block,
&chain_spec,
&output.receipts,
&output.requests,
None,
&None, // Todo Bal
false,
Some(output.gas_used),
)
.map_err(|err| Error::block_failed(block_number, err))?;
// Compute and check the post state root
let hashed_state =

View File

@@ -116,6 +116,8 @@ impl From<Header> for SealedHeader {
excess_blob_gas: value.excess_blob_gas.map(|v| v.to::<u64>()),
parent_beacon_block_root: value.parent_beacon_block_root,
requests_hash: value.requests_hash,
block_access_list_hash: None,
slot_number: None,
};
Self::new(header, value.hash)
}