|
| 1 | +--- |
| 2 | +eip: 8159 |
| 3 | +title: eth/71 - Block Access List Exchange |
| 4 | +description: Adds peer-to-peer exchange of block-level access lists to the eth protocol |
| 5 | +author: Toni Wahrstätter (@nerolation) |
| 6 | +discussions-to: https://ethereum-magicians.org/t/eip-8159-eth-71-block-access-list-exchange/27725 |
| 7 | +status: Draft |
| 8 | +type: Standards Track |
| 9 | +category: Networking |
| 10 | +created: 2026-02-12 |
| 11 | +requires: 7928, 7975 |
| 12 | +--- |
| 13 | + |
| 14 | +## Abstract |
| 15 | + |
| 16 | +This EIP modifies the 'eth' p2p protocol to support Block-level Access Lists (BALs). It adds two new messages, `GetBlockAccessLists` (0x12) and `BlockAccessLists` (0x13), enabling peers to request and serve BALs for synchronization and parallel execution. |
| 17 | + |
| 18 | +## Motivation |
| 19 | + |
| 20 | +[EIP-7928](./eip-7928.md) introduces block-level access lists that record all state locations accessed during block execution. These lists enable parallel disk reads, parallel transaction execution, and executionless state updates. |
| 21 | + |
| 22 | +For syncing clients to leverage these capabilities, BALs must be obtainable from peers. The Engine API provides BALs from the consensus layer during normal operation, but historical BALs and peer-based sync require wire protocol support. |
| 23 | + |
| 24 | +## Specification |
| 25 | + |
| 26 | +### Block Header Extension |
| 27 | + |
| 28 | +The block header is extended with a new field after `requests-hash`: |
| 29 | + |
| 30 | +``` |
| 31 | +block-header = [ |
| 32 | + ... |
| 33 | + requests-hash: B_32, |
| 34 | + block-access-list-hash: B_32, |
| 35 | +] |
| 36 | +``` |
| 37 | + |
| 38 | +The `block-access-list-hash` field contains `keccak256(rlp.encode(block-access-list))` as defined in [EIP-7928](./eip-7928.md). This field MUST be present in headers after the Amsterdam fork and absent for earlier blocks. |
| 39 | + |
| 40 | +### Block Access List Encoding |
| 41 | + |
| 42 | +BALs are RLP-encoded as a list of account changes, sorted lexicographically by address: |
| 43 | + |
| 44 | +``` |
| 45 | +block-access-list = [account-changes₁, account-changes₂, ...] |
| 46 | +
|
| 47 | +account-changes = [ |
| 48 | + address: B_20, |
| 49 | + storage-changes, |
| 50 | + storage-reads, |
| 51 | + balance-changes, |
| 52 | + nonce-changes, |
| 53 | + code-changes, |
| 54 | +] |
| 55 | +
|
| 56 | +storage-changes = [slot-changes₁, slot-changes₂, ...] |
| 57 | +slot-changes = [slot: B_32, [storage-change₁, storage-change₂, ...]] |
| 58 | +storage-change = [block-access-index: P, value: B_32] |
| 59 | +
|
| 60 | +storage-reads = [slot₁: B_32, slot₂: B_32, ...] |
| 61 | +
|
| 62 | +balance-changes = [balance-change₁, balance-change₂, ...] |
| 63 | +balance-change = [block-access-index: P, balance: P] |
| 64 | +
|
| 65 | +nonce-changes = [nonce-change₁, nonce-change₂, ...] |
| 66 | +nonce-change = [block-access-index: P, nonce: P] |
| 67 | +
|
| 68 | +code-changes = [code-change₁, code-change₂, ...] |
| 69 | +code-change = [block-access-index: P, code: B] |
| 70 | +``` |
| 71 | + |
| 72 | +`storage-changes` MUST be sorted lexicographically by slot. Changes within each slot MUST be sorted by `block-access-index` ascending. `storage-reads` MUST be sorted lexicographically by slot. |
| 73 | + |
| 74 | +Where `block-access-index` indicates when the change occurred: |
| 75 | + |
| 76 | +- `0` for pre-execution system contract calls |
| 77 | +- `1...n` for transactions (in block order) |
| 78 | +- `n+1` for post-execution system contract calls and withdrawals |
| 79 | + |
| 80 | +See [EIP-7928](./eip-7928.md) for complete BAL generation rules and inclusion semantics. |
| 81 | + |
| 82 | +### New Protocol Messages |
| 83 | + |
| 84 | +#### GetBlockAccessLists (0x12) |
| 85 | + |
| 86 | +``` |
| 87 | +[request-id: P, [blockhash₁: B_32, blockhash₂: B_32, ...]] |
| 88 | +``` |
| 89 | + |
| 90 | +Request BALs for the given block hashes. The number of BALs that can be requested in a single message is subject to implementation-defined limits. |
| 91 | + |
| 92 | +BALs are only available for blocks after [EIP-7928](./eip-7928.md) activation and within the retention period defined therein. Requests for unavailable BALs return empty entries. |
| 93 | + |
| 94 | +#### BlockAccessLists (0x13) |
| 95 | + |
| 96 | +``` |
| 97 | +[request-id: P, [block-access-list₁, block-access-list₂, ...]] |
| 98 | +``` |
| 99 | + |
| 100 | +Response to `GetBlockAccessLists`. Each element corresponds to a block hash from the request, in order. Empty BALs (RLP-encoded empty list `0xc0`) are returned for blocks where the BAL is unavailable. |
| 101 | + |
| 102 | +The recommended soft limit for `BlockAccessLists` responses is 10 MiB. |
| 103 | + |
| 104 | +### Validation |
| 105 | + |
| 106 | +When a BAL is received, clients MUST validate it by computing `keccak256(rlp.encode(bal))` and comparing against the `block-access-list-hash` in the corresponding block header. |
| 107 | + |
| 108 | +## Rationale |
| 109 | + |
| 110 | +### Separate Messages vs. Block Body Extension |
| 111 | + |
| 112 | +BALs are transmitted via dedicated messages rather than extending block bodies because: |
| 113 | + |
| 114 | +1. **Size**: BALs average ~70 KiB, significantly increasing block propagation overhead if bundled. |
| 115 | +2. **Optional retrieval**: Not all sync strategies require BALs. Snap sync can reconstruct state without them. |
| 116 | +3. **Retention policy**: BALs may be pruned per [EIP-7928](./eip-7928.md), while block bodies are retained longer. |
| 117 | + |
| 118 | +### Message IDs |
| 119 | + |
| 120 | +Message IDs 0x12 and 0x13 follow sequentially from the existing eth/69 messages (BlockRangeUpdate is 0x11). |
| 121 | + |
| 122 | +### Response Size Limit |
| 123 | + |
| 124 | +The 10 MiB soft limit aligns with existing protocol conventions and accommodates multiple BALs per response while remaining within typical message size constraints. |
| 125 | + |
| 126 | +## Backwards Compatibility |
| 127 | + |
| 128 | +This EIP changes the eth protocol and requires rolling out a new version, eth/71. Supporting multiple protocol versions is standard practice. Rolling out eth/71 does not break older clients, as they can continue using eth/69 or eth/70. |
| 129 | + |
| 130 | +This EIP requires the Amsterdam hard fork for the header field extension. The new messages are only meaningful for post-Amsterdam blocks. |
| 131 | + |
| 132 | +## Security Considerations |
| 133 | + |
| 134 | +### Validation Cost |
| 135 | + |
| 136 | +BAL validation requires computing a keccak256 hash of the RLP-encoded list. For typical BALs (~70 KiB), this is negligible. For worst-case BALs at high gas limits, validation remains bounded by the block gas limit. |
| 137 | + |
| 138 | +### Amplification |
| 139 | + |
| 140 | +A `GetBlockAccessLists` request can trigger responses larger than the request. Implementations SHOULD apply rate limiting and respect the soft response size limit to prevent amplification attacks. |
| 141 | + |
| 142 | +### Unavailable Data |
| 143 | + |
| 144 | +Clients MUST handle empty responses gracefully. A peer returning empty entries for available blocks may be misbehaving but could also have pruned the data legitimately. |
| 145 | + |
| 146 | +## Copyright |
| 147 | + |
| 148 | +Copyright and related rights waived via [CC0](../LICENSE.md). |
0 commit comments