|
| 1 | +# Blockchain Engine Sync Tests <!-- markdownlint-disable MD051 (MD051=link-fragments "Link fragments should be valid") --> |
| 2 | + |
| 3 | +The Blockchain Engine Sync Test fixture format tests are included in the fixtures subdirectory `blockchain_tests_sync`, and use Engine API directives to test client synchronization capabilities after fixtures are executed with valid payloads. |
| 4 | + |
| 5 | +These are produced by the `BlockchainTest` test spec when `verify_sync=True` is specified. |
| 6 | + |
| 7 | +## Description |
| 8 | + |
| 9 | +The Blockchain Engine Sync Test fixture format is used to test execution client synchronization between peers. It validates that clients can correctly sync state and blocks from another client using the Engine API and P2P networking. |
| 10 | + |
| 11 | +The test works by: |
| 12 | +1. Setting up a client under test, defining a pre-execution state, a series of `engine_newPayloadVX` directives, and a post-execution state, as in Blockchain Engine Test fixture formats. |
| 13 | +2. Starting a sync client with the same genesis and pre-execution state. |
| 14 | +3. Having the sync client synchronize from the client under test. |
| 15 | +4. Verifying that both clients reach the same final state. |
| 16 | + |
| 17 | +A single JSON fixture file is composed of a JSON object where each key-value pair is a different [`SyncFixture`](#syncfixture) 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, as well as a `{client under test}::sync_{sync client}` identifier. |
| 20 | + |
| 21 | +## Consumption |
| 22 | + |
| 23 | +For each [`HiveFixture`](#hivefixture) test object in the JSON fixture file, perform the following steps: |
| 24 | + |
| 25 | +### Client Under Test Setup |
| 26 | + |
| 27 | +1. Start the client under test using: |
| 28 | + - [`network`](#-network-fork) to configure the execution fork schedule according to the [`Fork`](./common_types.md#fork) type definition. |
| 29 | + - [`pre`](#-pre-alloc) as the starting state allocation of the execution environment for the test and calculate the genesis state root. |
| 30 | + - [`genesisBlockHeader`](#-genesisblockheader-fixtureheader) as the genesis block header. |
| 31 | + |
| 32 | +2. Verify the head of the chain is the genesis block, and the state root matches the one calculated on step 1, otherwise fail the test. |
| 33 | + |
| 34 | +3. Process all [`FixtureEngineNewPayload`](#fixtureenginenewpayload) objects in [`engineNewPayloads`](#-enginenewpayloads-listfixtureenginenewpayload) to build the complete chain on the client under test. |
| 35 | + |
| 36 | +### Sync Client Setup and Synchronization |
| 37 | + |
| 38 | +4. Start a sync client using the same genesis configuration: |
| 39 | + - Use the same [`network`](#-network-fork), [`pre`](#-pre-alloc), and [`genesisBlockHeader`](#-genesisblockheader-fixtureheader). |
| 40 | + |
| 41 | +5. Establish P2P connection between the clients: |
| 42 | + - Get the enode URL from the client under test |
| 43 | + - Use `admin_addPeer` to connect the sync client to the client under test |
| 44 | + |
| 45 | +6. Trigger synchronization on the sync client: |
| 46 | + - Send the [`syncPayload`](#-syncpayload-fixtureenginenewpayload) using `engine_newPayloadVX` |
| 47 | + - Send `engine_forkchoiceUpdatedVX` pointing to the last block hash |
| 48 | + |
| 49 | +7. Monitor and verify synchronization: |
| 50 | + - Wait for the sync client to reach the [`lastblockhash`](#-lastblockhash-hash) |
| 51 | + - Verify the final state root matches between both clients |
| 52 | + - If [`post`](#-post-alloc) is provided, verify the final state matches |
| 53 | + |
| 54 | +## Structures |
| 55 | + |
| 56 | +### `HiveFixture` |
| 57 | + |
| 58 | +#### - `network`: [`Fork`](./common_types.md#fork) |
| 59 | + |
| 60 | +##### TO BE DEPRECATED |
| 61 | + |
| 62 | +Fork configuration for the test. |
| 63 | + |
| 64 | +This field is going to be replaced by the value contained in `config.network`. |
| 65 | + |
| 66 | +#### - `genesisBlockHeader`: [`FixtureHeader`](./blockchain_test.md#fixtureheader) |
| 67 | + |
| 68 | +Genesis block header. |
| 69 | + |
| 70 | +#### - `engineNewPayloads`: [`List`](./common_types.md#list)`[`[`FixtureEngineNewPayload`](#fixtureenginenewpayload)`]` |
| 71 | + |
| 72 | +List of `engine_newPayloadVX` directives to be processed by the client under test to build the complete chain. |
| 73 | + |
| 74 | +#### - `syncPayload`: [`FixtureEngineNewPayload`](#fixtureenginenewpayload) |
| 75 | + |
| 76 | +The final payload to be sent to the sync client to trigger synchronization. This is typically an empty block built on top of the last test block. |
| 77 | + |
| 78 | +#### - `engineFcuVersion`: [`Number`](./common_types.md#number) |
| 79 | + |
| 80 | +Version of the `engine_forkchoiceUpdatedVX` directive to use to set the head of the chain. |
| 81 | + |
| 82 | +#### - `pre`: [`Alloc`](./common_types.md#alloc-mappingaddressaccount) |
| 83 | + |
| 84 | +Starting account allocation for the test. State root calculated from this allocation must match the one in the genesis block. |
| 85 | + |
| 86 | +#### - `lastblockhash`: [`Hash`](./common_types.md#hash) |
| 87 | + |
| 88 | +Hash of the last valid block that the sync client should reach after successful synchronization. |
| 89 | + |
| 90 | +#### - `post`: [`Alloc`](./common_types.md#alloc-mappingaddressaccount) |
| 91 | + |
| 92 | +Account allocation for verification after synchronization is complete. |
| 93 | + |
| 94 | +#### - `postStateHash`: [`Optional`](./common_types.md#optional)`[`[`Hash`](./common_types.md#hash)`]` |
| 95 | + |
| 96 | +Optional state root hash for verification after synchronization is complete. Used when full post-state is not included. |
| 97 | + |
| 98 | +#### - `config`: [`FixtureConfig`](#fixtureconfig) |
| 99 | + |
| 100 | +Chain configuration object to be applied to both clients running the blockchain sync test. |
| 101 | + |
| 102 | +### `FixtureConfig` |
| 103 | + |
| 104 | +#### - `network`: [`Fork`](./common_types.md#fork) |
| 105 | + |
| 106 | +Fork configuration for the test. It is guaranteed that this field contains the same value as the root field `network`. |
| 107 | + |
| 108 | +#### - `chainId`: [`Number`](./common_types.md#number) |
| 109 | + |
| 110 | +Chain ID configuration for the test network. |
| 111 | + |
| 112 | +#### - `blobSchedule`: [`BlobSchedule`](./common_types.md#blobschedule-mappingforkforkblobschedule) |
| 113 | + |
| 114 | +Optional; present from Cancun on. Maps forks to their blob schedule configurations as defined by [EIP-7840](https://eips.ethereum.org/EIPS/eip-7840). |
| 115 | + |
| 116 | +### `FixtureEngineNewPayload` |
| 117 | + |
| 118 | +#### - `executionPayload`: [`FixtureExecutionPayload`](#fixtureexecutionpayload) |
| 119 | + |
| 120 | +Execution payload. |
| 121 | + |
| 122 | +#### - `blob_versioned_hashes`: [`Optional`](./common_types.md#optional)`[`[`List`](./common_types.md#list)`[`[`Hash`](./common_types.md#hash)`]]` `(fork: Cancun)` |
| 123 | + |
| 124 | +List of hashes of the versioned blobs that are part of the execution payload. |
| 125 | + |
| 126 | +#### - `parentBeaconBlockRoot`: [`Optional`](./common_types.md#optional)`[`[`Hash`](./common_types.md#hash)`]` `(fork: Cancun)` |
| 127 | + |
| 128 | +Hash of the parent beacon block root. |
| 129 | + |
| 130 | +#### - `validationError`: [`Optional`](./common_types.md#optional)`[`[`TransactionException`](../../library/ethereum_test_exceptions.md#ethereum_test_exceptions.TransactionException)` | `[`BlockException`](../../library/ethereum_test_exceptions.md#ethereum_test_exceptions.BlockException)`]` |
| 131 | + |
| 132 | +For sync tests, this field should not be present as sync tests only work with valid chains. Invalid blocks cannot be synced. |
| 133 | + |
| 134 | +#### - `version`: [`Number`](./common_types.md#number) |
| 135 | + |
| 136 | +Version of the `engine_newPayloadVX` directive to use to deliver the payload. |
| 137 | + |
| 138 | +### `FixtureExecutionPayload` |
| 139 | + |
| 140 | +#### - `parentHash`: [`Hash`](./common_types.md#hash) |
| 141 | + |
| 142 | +Hash of the parent block. |
| 143 | + |
| 144 | +#### - `feeRecipient`: [`Address`](./common_types.md#address) |
| 145 | + |
| 146 | +Address of the account that will receive the rewards for building the block. |
| 147 | + |
| 148 | +#### - `stateRoot`: [`Hash`](./common_types.md#hash) |
| 149 | + |
| 150 | +Root hash of the state trie. |
| 151 | + |
| 152 | +#### - `receiptsRoot`: [`Hash`](./common_types.md#hash) |
| 153 | + |
| 154 | +Root hash of the receipts trie. |
| 155 | + |
| 156 | +#### - `logsBloom`: [`Bloom`](./common_types.md#bloom) |
| 157 | + |
| 158 | +Bloom filter composed of the logs of all the transactions in the block. |
| 159 | + |
| 160 | +#### - `blockNumber`: [`HexNumber`](./common_types.md#hexnumber) |
| 161 | + |
| 162 | +Number of the block. |
| 163 | + |
| 164 | +#### - `gasLimit`: [`HexNumber`](./common_types.md#hexnumber) |
| 165 | + |
| 166 | +Total gas limit of the block. |
| 167 | + |
| 168 | +#### - `gasUsed`: [`HexNumber`](./common_types.md#hexnumber) |
| 169 | + |
| 170 | +Total gas used by all the transactions in the block. |
| 171 | + |
| 172 | +#### - `timestamp`: [`HexNumber`](./common_types.md#hexnumber) |
| 173 | + |
| 174 | +Timestamp of the block. |
| 175 | + |
| 176 | +#### - `extraData`: [`Bytes`](./common_types.md#bytes) |
| 177 | + |
| 178 | +Extra data of the block. |
| 179 | + |
| 180 | +#### - `prevRandao`: [`Hash`](./common_types.md#hash) |
| 181 | + |
| 182 | +PrevRandao of the block. |
| 183 | + |
| 184 | +#### - `blockHash`: [`Hash`](./common_types.md#hash) |
| 185 | + |
| 186 | +Hash of the block. |
| 187 | + |
| 188 | +#### - `transactions`: [`List`](./common_types.md#list)`[`[`Bytes`](./common_types.md#bytes)`]` |
| 189 | + |
| 190 | +List of transactions in the block, in serialized format. |
| 191 | + |
| 192 | +#### - `withdrawals`: [`List`](./common_types.md#list)`[`[`FixtureWithdrawal`](#fixturewithdrawal)`]` |
| 193 | + |
| 194 | +List of withdrawals in the block. |
| 195 | + |
| 196 | +#### - `baseFeePerGas`: [`HexNumber`](./common_types.md#hexnumber) `(fork: London)` |
| 197 | + |
| 198 | +Base fee per gas of the block. |
| 199 | + |
| 200 | +#### - `blobGasUsed`: [`HexNumber`](./common_types.md#hexnumber) `(fork: Cancun)` |
| 201 | + |
| 202 | +Total blob gas used by all the transactions in the block. |
| 203 | + |
| 204 | +#### - `excessBlobGas`: [`HexNumber`](./common_types.md#hexnumber) `(fork: Cancun)` |
| 205 | + |
| 206 | +Excess blob gas of the block used to calculate the blob fee per gas for this block. |
| 207 | + |
| 208 | +### `FixtureWithdrawal` |
| 209 | + |
| 210 | +#### - `index`: [`HexNumber`](./common_types.md#hexnumber) |
| 211 | + |
| 212 | +Index of the withdrawal |
| 213 | + |
| 214 | +#### - `validatorIndex`: [`HexNumber`](./common_types.md#hexnumber) |
| 215 | + |
| 216 | +Withdrawing validator index |
| 217 | + |
| 218 | +#### - `address`: [`Address`](./common_types.md#address) |
| 219 | + |
| 220 | +Address to withdraw to |
| 221 | + |
| 222 | +#### - `amount`: [`HexNumber`](./common_types.md#hexnumber) |
| 223 | + |
| 224 | +Amount of the withdrawal |
| 225 | + |
| 226 | +## Differences from Blockchain Engine Tests |
| 227 | + |
| 228 | +While the Blockchain Sync Test format is similar to the Blockchain Engine Test format, there are key differences: |
| 229 | + |
| 230 | +1. **`syncPayload` field**: Contains the final block used to trigger synchronization on the sync client. |
| 231 | +2. **Multi-client testing**: Tests involve two clients (client under test and sync client) rather than a single client. |
| 232 | +3. **P2P networking**: Tests require P2P connection establishment between clients. |
| 233 | +4. **No invalid blocks**: Sync tests only work with valid chains as invalid blocks cannot be synced. |
| 234 | +5. **`postStateHash` field**: Optional field for state verification when full post-state is not included. |
| 235 | + |
| 236 | +## Fork Support |
| 237 | + |
| 238 | +Blockchain Sync Tests are only supported for post-merge forks (Paris and later) as they rely on the Engine API for synchronization triggering. |
0 commit comments