|
| 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