Skip to content

Commit 2ab9fc4

Browse files
feat(fill): enable shared pre-allocation groups and add BlockchainEngineReorgFixture (ethereum#1706)
* feat(fill): enable interface for two-phase shared alloc filling * feat(fixtures,types): add shared pre-allocation data models - Add `SharedPreStateGroup` and `SharedPreState` models. - Support grouping tests by (fork, environment) hash. - Enable serialization for phase 1/2 coordination. * feat(fixtures): add `BlockchainEngineReorgFixture` and common base class - Add `BlockchainEngineFixtureCommon` base class for shared functionality. - Add `BlockchainEngineReorgFixture` with `post_state_diff` field. - Remove unnecessary backwards compatibility validator from common class. - Update `test_collect_only` framework test for new fixture. * feat(fixtures): export new fixture classes and shared models - Export `BlockchainEngineReorgFixture` and `BlockchainEngineFixtureCommon`. - Export `SharedPreState` and `SharedPreStateGroup` models. - Enable imports for shared pre-allocation functionality. * feat(specs): add shared pre-allocation support to `BaseTest` - Add `update_shared_pre_state()` and `compute_shared_pre_alloc_hash()`. - Add `get_genesis_environment()` for polymorphic environment access. - Support both `StateTest` and `BlockchainTest` formats. * feat(fill): implement shared pre-allocation (`fill` pytest hooks) - Add `pytest_sessionstart` and `pytest_sessionfinish` for phase coordination. - Add `calculate_post_state_diff()` for memory-efficient storage. - Add custom terminal summary with group statistics. - Load/save shared pre-allocation state. * feat(fixtures): enable global address allocation and shared pre-alloc path - Add `shared_prealloc_path` property to `FixtureOutput`. - Extend global address iterators to all test formats. - Make the fixture scope of address iterators dynamic: session-scoped for shared pre-alloc generation, function-scoped for regular pre-alloc. - Update and improve `pre_alloc` tests. * feat(specs): add `BlockchainEngineReorgFixture` generation support - Support generating reorg fixtures from blockchain tests. - Enable shared pre-allocation integration with blockchain specs. * feat(fixtures): add `pre_hash` field to test case index - Support pre-allocation hash tracking in index files. - Enable fixture consumption with shared pre-allocation metadata. * chore(fill): only generate engine_reorg fixtures w/shared-alloc flags * feat(fill): add a new pytest mark for custom prealloc group control * chore(tests): apply `prealloc_group` to system contract & requests tests * fix(tests): prevent iterator state persistence in beacon root tests during two-phase execution The beacon root tests were failing when run with two-phase shared pre-allocation because they used `itertools.count()` objects directly in pytest parametrization. These iterator objects maintain internal state that persists across test phases when run in the same Python process. Changes: - Replace direct `count()` objects with factory functions that return fresh iterators. - Update `beacon_roots` fixture to create new iterator instances on each invocation. - Modify test parametrization to use `timestamps_factory` instead of `timestamps`. This bug only manifested in two-phase execution because: 1. In regular single-phase filling, each test gets its own fresh Python process. 2. In two-phase execution within one process, the same parametrized iterator. objects are reused, causing timestamps to continue from where phase 1 left off. 3. The second phase would see timestamps like 21000 instead of starting at 1000. The fix ensures each test invocation gets fresh iterators with reset state, preventing cross-phase contamination while maintaining the same test behavior. * chore(cli): add `groupstats` script to analyze shared pre-allocation groups Add a new CLI tool that provides comprehensive analysis of shared pre-allocation groups generated by the test framework. The tool helps identify optimization opportunities for client teams by analyzing group distributions, test coverage, and identifying problematic test functions that create multiple size-1 groups. Key features: - Display overall statistics (groups, tests, accounts) - Show distribution by fork with average tests per group - Analyze group size frequency distribution - Calculate test coverage impact by group size - List test modules by execution complexity (group count) - Identify split test functions with Groups/Fork ratio analysis - Progressive disclosure with -v and -vv verbosity levels The Groups/Fork ratio metric distinguishes between necessary multi-fork coverage and problematic parameter-heavy tests, enabling targeted optimization strategies for CI workflows. * docs(consume): add `BlockchainEngineReorgFixture` docs * refactor(all): standardize shared pre-allocation naming conventions - CLI flags: `--generate-shared-alloc` → `--generate-shared-pre` - CLI flags: `--use-shared-alloc` → `--use-shared-pre` - Property: `shared_prealloc_path` → `shared_pre_alloc_path` - Pytest marker: `prealloc_group` → `pre_alloc_group` - Entry point: `show_pre_alloc_groups` → `groupstats` * docs: update changelog * fix(fixtures/filler): Pydantic fixes * feat(filler): pre_alloc.json is now a folder * fix(cli): groupstats * fix: tox * feat: Use deterministic addresses in pre-alloc * fix: xdist * feat: genesis header in pre_alloc files * fix: tox * fix: move pre --------- Co-authored-by: Mario Vega <[email protected]>
1 parent f77cb56 commit 2ab9fc4

File tree

3 files changed

+147
-0
lines changed

3 files changed

+147
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Users can select any of the artifacts depending on their testing needs for their
3131

3232
- ✨ Add the `ported_from` test marker to track Python test cases that were converted from static fillers in [ethereum/tests](https://github.com/ethereum/tests) repository [#1590](https://github.com/ethereum/execution-spec-tests/pull/1590).
3333
- ✨ Add a new pytest plugin, `ported_tests`, that lists the static fillers and PRs from `ported_from` markers for use in the coverage Github Workflow [#1634](https://github.com/ethereum/execution-spec-tests/pull/1634).
34+
- ✨ Enable two-phase filling of fixtures with shared pre-allocation groups and add a `BlockchainEngineReorgFixture` format [#1606](https://github.com/ethereum/execution-spec-tests/pull/1706).
3435
- 🔀 Refactor: Encapsulate `fill`'s fixture output options (`--output`, `--flat-output`, `--single-fixture-per-file`) into a `FixtureOutput` class ([#1471](https://github.com/ethereum/execution-spec-tests/pull/1471),[#1612](https://github.com/ethereum/execution-spec-tests/pull/1612)).
3536
- ✨ Don't warn about a "high Transaction gas_limit" for `zkevm` tests ([#1598](https://github.com/ethereum/execution-spec-tests/pull/1598)).
3637
- 🐞 `fill` no longer writes generated fixtures into an existing, non-empty output directory; it must now be empty or `--clean` must be used to delete it first ([#1608](https://github.com/ethereum/execution-spec-tests/pull/1608)).

navigation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* [State Tests](running_tests/test_formats/state_test.md)
4242
* [Blockchain Tests](running_tests/test_formats/blockchain_test.md)
4343
* [Blockchain Engine Tests](running_tests/test_formats/blockchain_test_engine.md)
44+
* [Blockchain Engine Reorg Tests](running_tests/test_formats/blockchain_test_engine_reorg.md)
4445
* [EOF Tests](running_tests/test_formats/eof_test.md)
4546
* [Transaction Tests](running_tests/test_formats/transaction_test.md)
4647
* [Common Types](running_tests/test_formats/common_types.md)
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# Blockchain Engine Reorg Tests <!-- markdownlint-disable MD051 (MD051=link-fragments "Link fragments should be valid") -->
2+
3+
The Blockchain Engine Reorg Test fixture format tests are included in the fixtures subdirectory `blockchain_tests_engine_reorg`, and use Engine API directives with optimized shared pre-allocation for improved execution performance.
4+
5+
These are produced by the `StateTest` and `BlockchainTest` test specs when using the `--generate-shared-pre` and `--use-shared-pre` flags.
6+
7+
## Description
8+
9+
The Blockchain Engine Reorg Test fixture format is an optimized variant of the [Blockchain Engine Test](./blockchain_test_engine.md) format designed for large-scale test execution with performance optimizations.
10+
11+
It uses the Engine API to test block validation and consensus rules while leveraging **shared pre-allocation state** to significantly reduce test execution time and resource usage. Tests are grouped by their initial state (fork + environment + pre-allocation) and share common genesis states through blockchain reorganization.
12+
13+
The key optimization is that **clients need only be started once per group** instead of once per test (as in the original engine fixture format), dramatically improving execution performance for large test suites.
14+
15+
Instead of including large pre-allocation state in each test fixture, this format references a shared pre-allocation folder (`pre_alloc`) which includes all different pre-allocation combinations used for any test fixture group.
16+
17+
A single JSON fixture file is composed of a JSON object where each key-value pair is a different [`ReorgFixture`](#reorgfixture) test object, with the key string representing the test name.
18+
19+
The JSON file path plus the test name are used as the unique test identifier.
20+
21+
## Shared Pre-Allocation File
22+
23+
The `blockchain_tests_engine_reorg` directory contains a special directory `pre_alloc` that stores shared pre-allocation state file used by all tests in this format, one per pre-allocation group with the name of the pre-alloc hash. This folder is essential for test execution and must be present alongside the test fixtures.
24+
25+
### Pre-Allocation File Structure
26+
27+
Each file in the `pre_alloc` folder corresponds to a pre-allocation hash to shared state groups:
28+
29+
```json
30+
{
31+
"test_count": 88,
32+
"pre_account_count": 174,
33+
"testIds": ["test1", "test2", ...],
34+
"network": "Prague",
35+
"environment": { ... },
36+
"pre": { ... }
37+
}
38+
```
39+
40+
#### SharedPreStateGroup Fields
41+
42+
- **`test_count`**: Number of tests sharing this pre-allocation group
43+
- **`pre_account_count`**: Number of accounts in the shared pre-allocation state
44+
- **`testIds`**: Array of test identifiers that use this shared state
45+
- **`network`**: Fork name (e.g., "Prague", "Cancun")
46+
- **`environment`**: Complete [`Environment`](./common_types.md#environment) object with execution context
47+
- **`pre`**: Shared [`Alloc`](./common_types.md#alloc-mappingaddressaccount) object containing initial account states
48+
49+
## Consumption
50+
51+
For each [`ReorgFixture`](#reorgfixture) test object in the JSON fixture file, perform the following steps:
52+
53+
1. **Load Shared Pre-Allocation**:
54+
- Read the appropriate file from the `pre_alloc` folder in the same directory
55+
- Locate the shared state group using [`preHash`](#-prehash-string)
56+
- Extract the `pre` allocation and `environment` from the shared group
57+
58+
2. **Initialize Client**:
59+
- Use [`network`](#-network-fork) to configure the execution fork schedule
60+
- Use the shared `pre` allocation as the starting state
61+
- Use the shared `environment` as the execution context
62+
- Use [`genesisBlockHeader`](#-genesisblockheader-fixtureheader) as the genesis block header
63+
64+
3. **Execute Engine API Sequence**:
65+
- For each [`FixtureEngineNewPayload`](#fixtureenginenewpayload) in [`engineNewPayloads`](#-enginenewpayloads-listfixtureenginenewpayload):
66+
1. Deliver the payload using `engine_newPayloadVX`
67+
2. Validate the response according to the payload's expected status
68+
- If [`syncPayload`](#-syncpayload-optionalfixtureenginenewpayload) is present, execute it for chain synchronization
69+
70+
4. **Verify Final State**:
71+
- Compare the final chain head against [`lastblockhash`](#-lastblockhash-hash)
72+
- If [`postStateDiff`](#-poststatediff-optionalalloc) is present:
73+
- Apply the state differences to the shared pre-allocation
74+
- Verify the resulting state matches the client's final state
75+
- If `post` field were present (not typical), verify it directly
76+
77+
## Structures
78+
79+
### `ReorgFixture`
80+
81+
#### - `network`: [`Fork`](./common_types.md#fork)
82+
83+
##### TO BE DEPRECATED
84+
85+
Fork configuration for the test.
86+
87+
This field is going to be replaced by the value contained in `config.network`.
88+
89+
#### - `preHash`: `string`
90+
91+
Hash identifier referencing a shared pre-allocation group in the `pre_alloc` folder. This hash uniquely identifies the combination of fork, environment, and pre-allocation state shared by multiple tests.
92+
93+
#### - `genesisBlockHeader`: [`FixtureHeader`](./blockchain_test.md#fixtureheader)
94+
95+
Genesis block header. The state root in this header must match the state root calculated from the shared pre-allocation referenced by [`preHash`](#-prehash-string).
96+
97+
#### - `engineNewPayloads`: [`List`](./common_types.md#list)`[`[`FixtureEngineNewPayload`](#fixtureenginenewpayload)`]`
98+
99+
List of `engine_newPayloadVX` directives to be processed after the genesis block. These define the sequence of blocks to be executed via the Engine API.
100+
101+
#### - `syncPayload`: [`Optional`](./common_types.md#optional)`[`[`FixtureEngineNewPayload`](#fixtureenginenewpayload)`]`
102+
103+
Optional synchronization payload used for blockchain reorganization scenarios. When present, this payload is typically used to sync the chain to a specific state before or after the main payload sequence.
104+
105+
#### - `lastblockhash`: [`Hash`](./common_types.md#hash)
106+
107+
Hash of the last valid block after all payloads have been processed, or the genesis block hash if all payloads are invalid.
108+
109+
#### - `postStateDiff`: [`Optional`](./common_types.md#optional)`[`[`Alloc`](./common_types.md#alloc-mappingaddressaccount)`]`
110+
111+
State differences from the shared pre-allocation state after test execution. This optimization stores only the accounts that changed, were created, or were deleted during test execution, rather than the complete final state.
112+
113+
To reconstruct the final state:
114+
115+
1. Start with the shared pre-allocation from the `pre_alloc` folder
116+
2. Apply the changes in `postStateDiff`:
117+
- **Modified accounts**: Replace existing accounts with new values
118+
- **New accounts**: Add accounts not present in pre-allocation
119+
- **Deleted accounts**: Remove accounts (represented as `null` values)
120+
121+
#### - `config`: [`FixtureConfig`](#fixtureconfig)
122+
123+
Chain configuration object to be applied to the client running the blockchain engine reorg test.
124+
125+
### `FixtureConfig`
126+
127+
#### - `network`: [`Fork`](./common_types.md#fork)
128+
129+
Fork configuration for the test. It is guaranteed that this field contains the same value as the root field `network`.
130+
131+
#### - `blobSchedule`: [`BlobSchedule`](./common_types.md#blobschedule-mappingforkforkblobschedule)
132+
133+
Optional; present from Cancun on. Maps forks to their blob schedule configurations as defined by [EIP-7840](https://eips.ethereum.org/EIPS/eip-7840).
134+
135+
### `FixtureEngineNewPayload`
136+
137+
Engine API payload structure identical to the one defined in [Blockchain Engine Tests](./blockchain_test_engine.md#fixtureenginenewpayload). Includes execution payload, versioned hashes, parent beacon block root, validation errors, version, and error codes.
138+
139+
## Usage Notes
140+
141+
- This format is only generated when using `--generate-shared-pre` and `--use-shared-pre` flags
142+
- The `pre_alloc` folder is essential and must be distributed with the test fixtures
143+
- Tests are grouped by identical (fork + environment + pre-allocation) combinations
144+
- The format is optimized for Engine API testing (post-Paris forks)
145+
- Reorganization scenarios are supported through the `forkChoiceUpdate` mechanism

0 commit comments

Comments
 (0)