--- eip: 8497 title: FOCIL Omission Witnesses for Frame Txs description: Carry claimed indices and signed inclusion lists in the payload envelope to judge omitted frame transactions. author: Daniil Ankushin (@AnkushinDaniil) discussions-to: https://ethereum-magicians.org/t/focil-omission-witnesses-for-frame-transactions/0 status: Draft type: Standards Track category: Core created: 2026-11-12 requires: 7732, 7805, 7843, 7928, 8141, 8250, 8272, 8369 --- ## Abstract This EIP defines when a builder may omit an [EIP-8141](./eip-8141.md) frame transaction that an inclusion list (IL) lists under [EIP-7805](./eip-7805.md). It specifies the enforcement that [EIP-8369](./eip-8369.md) leaves open, and adds one restriction. As in EIP-8369, the builder claims one index per omitted transaction, and the transaction is judged at the state after that index. This EIP puts the claims in the payload envelope and commits to them in the bid. The restriction is the writer rule: a claim counts only if every block transaction up to the claimed index that writes the validation state of the omitted transaction is listed in signed ILs that the envelope carries (witnesses), in at least as many of them as the number of ILs that list the omitted transaction in the node's view. Nodes read the writers from the block access list. The verdict depends on the block, the envelope and the node's frozen IL view, as in EIP-7805, and on no other node-local input. The EIP also adds per-transaction and per-IL gas caps for IL transactions. The writer rule is a separate layer: without it, this EIP specifies the claimed index of EIP-8369. ## Motivation EIP-7805 checks an omitted transaction at the end of the payload. That check is cheap and complete when validity depends only on nonce and balance. Frame transaction validity can also depend on keyed nonces, payer state, low storage slots of the sender and payer, and the code of accounts that validation reaches. Another transaction in the block can change that state. Two IL transactions that share a payer can make each other invalid, so the end-of-payload check can call an honest block non-compliant or let a builder excuse an omission with a transaction of its choosing. [EIP-8369](./eip-8369.md) defines a validation surface (Profile 2) and a per-IL `VERIFY` budget for frame transactions. It evaluates an omitted transaction at an index that the builder claims. EIP-8369 is Informational and leaves the claims field, the bound on claims, and the way to carry claims to the execution layer to an enforcing EIP. With a claimed index alone, any transaction before the index can excuse the omission, including a builder transaction that was never public. The Heze consensus specification already has a per-member commitment in the bid: [`inclusion_list_bits`](https://github.com/ethereum/consensus-specs/blob/e3e2d0128458c2f56092bd459d3c5a85cdf80fcd/specs/heze/inclusion-list.md). A bid is ignored on gossip unless its bits cover every timely, non-equivocating IL that the node has seen (`is_inclusion_list_bits_inclusive`). The bits say which members the builder heard from. They do not carry IL content, so a node cannot tell from the block which transactions were IL-listed in the builder's view. They do not say which block transactions were listed. This EIP specifies the claims and adds IL content to the block. A write can excuse the omission of `T` only if the writer is in at least as many carried ILs as the number of ILs that list `T`. A write by any other transaction cannot. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. ### Constants Values marked TBD require benchmarks of the full reconstruction and replay pipeline against the payload validation deadline. | Name | Value | |---|---| | `AA_VOPS_SLOT_COUNT` | TBD (candidate range 2 to 4) | | `MAX_VERIFY_GAS_PER_IL` | TBD (candidate `2**20`) | | `MAX_VERIFY_GAS_PER_TX` | TBD, at most `MAX_VERIFY_GAS_PER_IL` | | `MAX_VERIFY_CODE_BYTES` | TBD | | `MAX_GAS_PER_IL_TX` | TBD | | `MAX_GAS_PER_IL` | TBD | | `MAX_IL_CLAIMS` | TBD (candidate `2**10`) | | `MAX_IL_WITNESSES` | `2 * INCLUSION_LIST_COMMITTEE_SIZE` | ### Definitions - Slot `N` is the slot of the ILs. Slot `N+1` is the slot of the bid and payload. - An *occurrence* is one transaction entry in one IL. - `tx_gas(tx)` is `max_gas` as defined in EIP-8141 for a frame transaction, and the signed gas limit otherwise. - *IL members* are the slot `N` IL committee members that are not known equivocators in the node's frozen EIP-7805 IL view. *IL occurrences* are the occurrences in the frozen-view ILs of IL members, in committee order and then IL order. - An *enforced* transaction is a transaction with at least one *admitted* IL occurrence under the fill below. Transactions are identified by exact [EIP-2718](./eip-2718.md) envelope bytes. - `listings(T)` is the number of IL members, proven equivocators excluded (see [Claims and witnesses](#claims-and-witnesses)), whose frozen-view IL has an admitted occurrence of `T`. - A *Profile 1* transaction is a legacy, [EIP-2930](./eip-2930.md), [EIP-1559](./eip-1559.md) or [EIP-7702](./eip-7702.md) transaction. - A *Profile 2 candidate* is an EIP-8141 frame transaction that, from the transaction alone: is statically valid under EIP-8141; has an empty `blob_versioned_hashes` list; ignoring the optional expiry verifier frame and an optional [EIP-8272](./eip-8272.md) recent root verifier frame at the position EIP-8272 allows, matches one of the prefix shapes `self_verify`, `deploy | self_verify`, `only_verify | pay` or `deploy | only_verify | pay` by modes, flags and targets; has no frame in the validation prefix with `ATOMIC_BATCH_FLAG` set; and has no frame after the validation prefix with mode `VERIFY`. - [EIP-4844](./eip-4844.md) transactions and frame transactions with a non-empty `blob_versioned_hashes` list are neither. Their omission is always justified. ### Fee validity For a frame transaction, `fee_valid(tx, block)` holds if and only if `tx.fees.max_fee >= required_max_fee`, with `required_max_fee` computed as in EIP-8141 at the block's base fee and blob base fee. For any other transaction, `fee_valid` is the EIP-8369 fee rule. ### Profile 2 eligibility `is_profile2_eligible(T, S)` holds if and only if, on state `S`, `T` passes every EIP-8141 and [EIP-8250](./eip-8250.md) nonce and keyed nonce check made before the first frame, and a replay of the validation prefix of `T` meets all of the following: 1. The prefix follows the EIP-8141 validation trace rules, except that item 3 replaces the EIP-8141 storage read rule, and the EIP-8272 recent root verifier frame keeps its `SLOTNUM` and `SLOAD` permissions. The EIP-8141 public mempool `MAX_VERIFY_GAS` limit and other mempool-only policies do not apply; replay gas is bounded by `MAX_VERIFY_GAS_PER_TX` as below. The prefix is the frames up to and including the first frame whose `APPROVE` sets the payer. 2. If present, the first non-expiry frame is a deploy frame that installs code or an EIP-7702 delegation indicator at `T.sender`. 3. The prefix reads state only from the Profile 2 surface: `nonce`, `balance` and code of `T.sender` and of the payer; storage slots `0` to `AA_VOPS_SLOT_COUNT - 1` of `T.sender` and of the payer; the EIP-8250 `NONCE_MANAGER` entries for `(T.sender, key)` for every nonzero key in `T.nonce_keys`; the EIP-8272 `RECENT_ROOT_ADDRESS` storage keys derived from the tuples of the recent root verifier frame of `T`; and the code of any other account that the prefix calls or delegates to. 4. The total size of distinct code bodies the prefix loads is at most `MAX_VERIFY_CODE_BYTES`. 5. The recent root verifier frame of `T`, if present, succeeds. 6. The prefix succeeds and sets the payer through `APPROVE_PAYMENT` or `APPROVE_EXECUTION_AND_PAYMENT`, and the payer can pay `max_cost` as defined in EIP-8141. The payer is `T.sender` for the `self_verify` shapes and the EIP-8141 `resolved_target` of the `pay` frame otherwise. Replay uses the fork rules, timestamp, base fee and blob base fee of the block, `current_slot` from the block's [EIP-7843](./eip-7843.md) `slotNumber` field, and a warm set holding only the addresses and keys that EIP-8141 warms at transaction start. Gas used by replay counts against `MAX_VERIFY_GAS_PER_TX`. A replay that exceeds it fails. ### Admission fill Each node runs this fill over IL occurrences, independently per IL, before deduplication. Each IL starts with `MAX_GAS_PER_IL` gas and `MAX_VERIFY_GAS_PER_IL` `VERIFY` gas. For each occurrence, in IL order: 1. If the bytes do not decode to a valid transaction, skip it. Nothing is deducted. 2. If `tx_gas(tx) > MAX_GAS_PER_IL_TX` or `tx_gas(tx)` exceeds the gas left in the IL, skip it. Nothing is deducted. 3. If `tx` is a Profile 2 candidate, run the EIP-8369 static `VERIFY` budget fill step for this occurrence: compute signature and prefix cost, skip with no debit if their sum exceeds `MAX_VERIFY_GAS_PER_TX` or the `VERIFY` gas left, deduct the signature cost, verify signatures, and deduct the prefix cost only if the signatures pass. If the signatures fail, skip it and keep only the `VERIFY` debits made so far. 4. If `tx` is neither a Profile 1 transaction nor a Profile 2 candidate, skip it. Nothing is deducted. 5. Otherwise the occurrence is admitted. Deduct `tx_gas(tx)` from the IL gas. Includers SHOULD NOT build an IL in which the total `tx_gas` of all listed transactions exceeds `MAX_GAS_PER_IL`, or which lists a transaction with `tx_gas` above `MAX_GAS_PER_IL_TX`. ### Claims and witnesses The [EIP-7732](./eip-7732.md) `ExecutionPayloadEnvelope` for slot `N+1` gains two fields, and `ExecutionPayloadBid` gains their roots: ```python class InclusionListClaim(Container): transaction_hash: Hash32 index: uint64 # ExecutionPayloadEnvelope inclusion_list_claims: List[InclusionListClaim, MAX_IL_CLAIMS] inclusion_list_witnesses: List[SignedInclusionList, MAX_IL_WITNESSES] # ExecutionPayloadBid inclusion_list_claims_root: Root inclusion_list_witnesses_root: Root ``` An envelope is invalid if the `hash_tree_root` of either list differs from the matching root in the bid. `transaction_hash` is the `keccak256` hash of the exact EIP-2718 envelope bytes of an omitted transaction. An envelope is invalid if its claims are not in strictly ascending order of `transaction_hash`. Let `n` be the number of transactions in the payload. A claim with `index > n` is read as `index = n`. `claim_index(T)` is the index of the claim whose hash matches `T`, or `n` if there is none. A claim that matches no enforced transaction of the node has no effect. A carried `SignedInclusionList` `w` is valid if all of the following hold: `w.message.slot == N`; `w.message.dependent_root` is the shuffling dependent root of slot `N` on the chain of the bid's `parent_block_root`; `w.message.validator_index` is in the slot `N` IL committee; `is_valid_inclusion_list_signature` holds for `w`; and `w` meets the size limits of the IL gossip rules. An envelope is invalid if it carries an invalid witness, two equal witnesses, or more than two witnesses with the same `validator_index`. A member with two carried witnesses is a *proven equivocator*, for every node. `support(j)` is the number of carried witnesses, from members that are not proven equivocators, that hold a transaction equal to the exact EIP-2718 envelope bytes of block transaction `j`. It is the same for every node, whether or not the node stored an IL from those members. Such a member has one carried witness, so `support(j)` is the number of distinct members that signed for transaction `j`. ### Relation to inclusion list bits This section applies while `ExecutionPayloadBid` has the `inclusion_list_bits` field. Let `i` be the committee position of `w.message.validator_index`. An envelope is invalid if it carries a witness `w` with `bid.inclusion_list_bits[i] == 0`, unless that member is a proven equivocator. The existing gossip check `is_inclusion_list_bits_inclusive` makes sure the bid covers every member that the node saw in time. The rule above makes sure the builder carries no IL from a member that its own bid says it did not see. `get_inclusion_list_bits` skips equivocators, so a builder that follows the Heze builder guide carries ILs from a member it knows as an equivocator only as a pair, which proves the equivocation to every node. ### If inclusion list bits are removed If `ExecutionPayloadBid` has no `inclusion_list_bits` field, the rule of the previous section does not apply. The bid commits to the claims and the witnesses through their own roots, and the envelope carries them. The gossip filter `is_inclusion_list_bits_inclusive` goes away with the bits, so a bid that ignored timely ILs is no longer dropped on gossip; such a payload is caught only by the omission check after the envelope is revealed. The omission rules of this EIP do not change. Consensus-specs pull request 5772 (an open draft as of 2026-11-12, not part of the Heze specification; [branch file](https://github.com/ethereum/consensus-specs/blob/c4cf93f1ea5ef1e56a2397b32bf0570106154c87/specs/heze/beacon-chain.md)) passes ILs to the execution layer, keeps `inclusion_list_bits`, and adds an IL exemption list with `inclusion_list_exemptions` in the envelope and `inclusion_list_exemptions_root` in the bid. If that exemption list is adopted, it can take the place of `inclusion_list_claims` and its root, and this EIP then adds only the witnesses and the writer rule. ### State at an index Let `S_k`, for `0 <= k <= n`, be the parent state with the [EIP-7928](./eip-7928.md) block access list changes at indices `0` through `k` applied. Index `0` holds pre-execution system updates. For a Profile 2 candidate `T`, with the payer as determined by the replay of `T` on `S_0`, `R(T)` is this set of state keys, whether or not that replay reads them: - `nonce`, `balance` and code of `T.sender` and of the payer; - storage slots `0` to `AA_VOPS_SLOT_COUNT - 1` of `T.sender` and of the payer; - the `NONCE_MANAGER` entries for `(T.sender, key)` for every nonzero key in `T.nonce_keys`; - the `RECENT_ROOT_ADDRESS` storage keys derived from the tuples of the recent root verifier frame of `T`; - the code of every other account whose code the replay on `S_0` loads, delegated target code included. Transaction `j` writes `R(T)` if the block access list records, at index `j`, a change to a key in `R(T)`. An index `i` is *clean* for `T` if every transaction `j` in `[1, i]` that writes `R(T)` has `support(j) >= listings(T)`. Index `0` is always clean. ### Omission rule Omission of a Profile 1 transaction is judged as in EIP-7805, at the end of the payload, with the obligation restricted to enforced transactions. Omission of an enforced Profile 2 candidate `T`, with `i = claim_index(T)`, is unjustified if and only if all of the following hold: 1. `fee_valid(T, block)`; 2. `is_profile2_eligible(T, S_0)`; 3. `i` is not clean for `T`; or `is_profile2_eligible(T, S_i)` and the replay on `S_i` reads no state key outside `R(T)`; 4. `T` fits the remaining block capacity after the payload in each gas dimension, per the EIP-8141 inclusion check. A payload with an unjustified omission does not satisfy the IL conditions of EIP-7805. A node that lacks state or code it needs MUST obtain authenticated data before it decides. Missing local data does not justify an omission. Without the writer rule, item 3 is only its second part. That is the claimed index of EIP-8369 with the parent state condition of item 2. ### Fork choice The node runs the omission check when it verifies the envelope in `on_execution_payload_envelope`. As in EIP-7805, the result does not affect payload validity: the payload is imported and its `FULL` node is added as usual. The node records the result with `record_payload_inclusion_list_satisfaction`. If the result is false, the node MUST NOT apply the `FULL` tiebreak to that node, MUST NOT select it as head for its slot `N+2` duties, and as proposer MUST NOT build on it. Later descendants of it are imported normally. ### Execution layer interface This EIP adds a new `engine_newPayload` version. It takes the parameters of the version in force at activation plus: - `inclusionLists`: `Array of Array of DATA`, one entry per IL member that is not a proven equivocator, in committee order, each holding the transaction bytes of that member's IL in IL order; - `witnessTransactions`: `Array of Array of DATA`, one entry per carried witness of a member that is not a proven equivocator, each holding the transaction bytes of that witness; - `inclusionListClaims`: `Array of Object`, each with `transactionHash` (`DATA`, 32 bytes) and `index` (`QUANTITY`), in envelope order. `inclusionLists` has the per-IL shape proposed in execution-apis pull request 960 (an open draft as of 2026-11-12). The execution layer first validates the payload as before. If the payload is `VALID`, it runs the admission fill, applies the omission rule with the block access list, and returns `INCLUSION_LIST_UNSATISFIED` instead of `VALID` if any omission is unjustified. The payload stays valid. The node's IL view is frozen before the envelope arrives, so the result is final for that node and the consensus layer does not retry. ### Honest builder A builder counts the listings of each IL transaction over the ILs it has seen for slot `N` from members that it does not know as equivocators. If a known equivocator lists a transaction that the builder omits with a claim, the builder carries two ILs of that member. With that, the count is an upper bound for `listings(T)` at a node whose frozen view the builder's view covers. The builder makes one pass over the IL transactions in its view, in descending order of that count. When it tries a Profile 2 candidate that is eligible at `S_0` and the candidate fails at the current position, the builder commits a claim with that position as the index, and keeps the index clean: every earlier block transaction that writes `R(T)` is in at least as many carried ILs as the builder's count for `T`. In this order, every IL transaction that the pass placed before `T` has a count that is not lower, so the builder only has to carry the ILs that list those writers and to keep unlisted writers of `R(T)` after the index. If the builder cannot keep the index clean, it includes the transaction at a position where it is eligible. A builder SHOULD carry only the ILs that a claim relies on. While the bid has `inclusion_list_bits`, a builder MUST set it as in the Heze builder guide. ## Rationale ### What this EIP adds to inclusion list bits | | `inclusion_list_bits` (Heze) | This EIP | |---|---|---| | Content in the block | One bit per member | Claims, and the signed ILs that a claim relies on, both committed by root in the bid | | Who sets it | The builder | The builder | | Use in the omission check | None | Claims set the evaluation state; witnesses give each writer a listing count, which decides if it may come before that state | | Evaluation state | End of payload | Claimed index, valid only if it is clean | EIP-8369 and the exemptions of consensus-specs pull request 5772 already judge an omission at a claimed index. The new part is the writer rule: a claim counts only if every writer of the transaction's validation state before the index is in at least as many carried ILs as the number of ILs that list the transaction. Carrying signed ILs, the gas caps and the `VERIFY` budget come from earlier work, listed below. ### Prior work - Proposer-carried aggregate IL: the original FOCIL post by Thomas Thiery (soispoke) and co-authors (ethresear.ch topic 19870) had the proposer aggregate the local ILs into its block. EIP-7805 dropped the aggregate; attesters check against their own IL view. This EIP brings back carried ILs only as witnesses, only the ones an omission relies on. - IL transaction invalidation: Julian Ma, "Transaction Invalidation", FOCIL site, September 2024, describes how a builder can invalidate an IL transaction with an earlier block transaction. This EIP limits which earlier transactions can do so. - Claims by index and the `VERIFY` budget: Thomas Thiery (soispoke), "FOCIL and Native Account Abstraction", Ethereum Magicians topic 27999, March 2026, proposed the per-IL `VERIFY` budget and index-based validation. EIP-8369 specifies both. This EIP keeps both and restricts the claim with the writer rule. The first draft of this EIP replaced the claimed index with an index that nodes derive, and counted a witness only if the node itself had stored an IL from the same member. Thomas Thiery's review of that draft (pull request 12663 in the EIPs repository) showed three problems: the counting rule can make nodes reject an honest payload, a one wei transfer to the payer lets the builder move the derived index, and without that transfer the builder has to recheck all transactions that share a payer after each inclusion. This version returns to the claimed index for these reasons. - Per-IL and per-IL-transaction gas caps: proposed by vlad and Thomas Thiery (soispoke) in the consensus-dev channel of the Eth R&D Discord (not publicly archived). This EIP applies them in the admission fill. - Node-derived evaluation index: chugarchugarr, in the EIP-8369 Ethereum Magicians topic 29298 (September 2026), proposed that nodes evaluate position-stable transactions at the end of the payload and keep the claimed index for the rest, and named the condition that removes the claim: a transaction invalid at an earlier index stays invalid at the end. This EIP does not classify transactions. It keeps the claim for every Profile 2 transaction, with the end of the payload as the default. - Passing ILs to the execution layer: Jihoon Song, consensus-specs pull request 5772 and execution-apis pull request 960 (both open drafts), building on execution-apis pull request 911 by Marc Harvey-Hill (Marchhill). The `inclusionLists` parameter follows that shape. ### The writer rule With a claimed index alone, any transaction before the index can excuse an omission, including a builder transaction that was never public. With the writer rule, a claim counts only if every earlier writer of the transaction's validation state was signed by at least as many committee members as list the omitted transaction, and the block carries the signatures. The builder still chooses the index. It chooses among states that transactions with enough listings produce. If a listed transaction drains a payer and a later listed transaction refunds it, the builder can claim an index between the two. The rule does not remove this choice. The rule also limits how the builder orders the block. An unlisted transaction that writes `R(T)` before the claimed index makes the claim void, and so does a listed one with fewer listings than `T`. One example is an unlisted transaction that the same paymaster sponsors. A builder that omits `T` has to place such transactions after the claimed index, or include `T` before them. Inclusion is always possible at the first position, because `T` is eligible at `S_0`. The cost of this constraint for builders is UNMEASURED. The rule costs one envelope field, one bid root and one scan of the block access list per omitted transaction. It can be removed without a change to the rest of this EIP. ### Why a listing count If one signed IL were enough for a writer, one committee member could make any transaction `X` a valid excuse. A member that works with the builder signs an IL with `X`, and `X` then excuses every transaction that shares state with it. A fixed threshold of `k` ILs for every writer does not work: two listed transactions that conflict and that both have fewer than `k` listings could not excuse each other, and no payload would satisfy both ILs. The threshold in this EIP is relative. A writer needs `listings(T)` carried ILs, so of two listed transactions that conflict, the one with more listings can always excuse the other, and with equal counts each can excuse the other. A builder that processes IL transactions in descending order of listings can always build a payload that satisfies every IL. The effect is that the members who list `T` are weighed against the members who list `X`. To excuse a transaction that `c` members list, a builder needs `c` signatures for `X`. A transaction that stays in the public mempool because builders skip it is the case that FOCIL targets, and it is the one that many members can list. When `listings(T)` is 1, the rule is the same as a rule that asks for one carried IL. When it is 0, which happens only if every member that lists `T` is a proven equivocator, the rule is the claimed index alone. A member that signs two ILs could otherwise raise `listings(T)` at nodes that saw one of them, while the builder, which treats the member as an equivocator, could not carry that IL as support. Two transactions that conflict could then both be unexcusable. The pair of carried ILs removes that member from both counts at every node. The count for `T` comes from the node's frozen IL view and the count for a writer comes from the envelope. A node with a smaller view has a lower `listings(T)` and is more lenient, as with the obligations of EIP-7805. ### Why carry the IL in the block A rule like "a writer counts if its hash is in any IL the node stored" depends on each node's IL view, and the views differ. A node that missed one IL would see a shorter excused set and could reject an honest block. A witness carried in the block makes the writer rule a function of the block and the envelope. The only node-local input is the frozen IL view of EIP-7805, which sets the obligations. The bid commits to the witnesses, so a builder cannot send different witness sets to different nodes for one bid. `inclusion_list_bits` alone cannot play this role, because it has no transaction content. ### Why the mechanism does not depend on the bits At FOCIL breakout 45 (2026-10-27), with ILs passed to the execution layer as proposed in consensus-specs pull request 5772, Nico Flaig noted that `inclusion_list_bits` can then be dropped from the payload attributes event. If the bits leave the bid as well, this EIP loses the bid binding, and the network loses the gossip filter `is_inclusion_list_bits_inclusive`. The omission check still works: the claims and the witnesses are committed by their own roots. A bid that ignored timely ILs is then caught after the envelope reveal instead of on bid gossip. ### Why a witness counts without the node's own copy The first draft counted a witness only if the node had stored an IL from the same member. The Heze IL gossip rules ignore an IL once its slot is over (`is_current_slot` in `validate_inclusion_list_gossip`). An IL that reaches the builder just before its freeze at slot `N`, `t=11s`, has about one second to reach other nodes. A member can send its IL only to the builder at that moment. Nodes that miss it would then reject a payload from an honest builder. EIP-8369 keeps private receipt of an IL out of consensus for the same reason. The counting rule also did not stop a colluding member. That member can publish one IL and sign another one for the builder. So this EIP counts every valid carried witness. ### Why a claimed index and not a derived one The first draft derived the evaluation state from the block: the state before the first writer that is not witnessed. The payer's balance is part of `R(T)`, and anyone can write it with a transfer of one wei. So a builder could place the derived index with a transfer, which is a claim in another form. A builder that did not do this had to recheck every listed transaction with the same payer after each inclusion, because any of them could become valid again. For `m` such transactions that is up to `m * (m - 1) / 2` replays. With a claim, the builder makes one pass and a node runs at most two replays per omitted transaction. ### Validity at the parent state Condition 2 excuses a transaction that becomes valid only through writes inside the block. Without it, each included IL transaction could make an earlier rejected one valid, and the builder would need a repeated append loop over IL transactions. With it and a claim, a builder tries each IL transaction once. The cost of this pass is UNMEASURED. A node runs at most two replays per omitted transaction. ### Static surface and reads outside R(T) `R(T)` holds the whole sender and payer surface, not only the keys the `S_0` replay reads. Otherwise a transaction without enough support could set a slot that the replay does not read at `S_0`, and a writer with enough support could then turn on a branch that reads it. A writer with enough support can also redirect validation to an account whose code the `S_0` replay did not load. Item 3 of the omission rule treats a replay that reads outside `R(T)` as not eligible, so a write outside `R(T)` can only make the rule more lenient. ### Gas caps The `VERIFY` budget bounds validation work. It does not bound the execution of an included IL transaction, which only the per-transaction gas cap bounds. An includer can list transactions that are expensive to simulate and slow down builders that must include them. The per-transaction and per-IL gas caps bound that work. The IL byte limit does not bound gas. Gas is deducted only for admitted occurrences, so a rejected occurrence cannot use up the IL's gas. ### Execution layer complexity The closest client data point is a draft Nethermind pull request (13590, head `0db03f67`) that implements EIP-8369 with a claimed index and the per-IL `VERIFY` budget. It is not an implementation of this EIP. Its diff is 4,776 added and 3,061 removed lines in 116 files; outside test projects, 2,056 added and 965 removed lines in 75 files. The largest new parts are the eligibility replay over block access list state (239 lines), the inclusion check (168 lines), the `VERIFY` budget fill and Profile 2 rules (162 and 144 lines), and validation tracing (102 lines). Line counts are from the pull request diff on 2026-11-12. Against that implementation, this EIP keeps the claim and adds: witness bytes as an `engine_newPayload` input, a scan over block access list indices up to the claimed index, a second replay per omitted transaction (at `S_0`), and the gas caps in the fill. Replay time, fill time and the added cost to the payload validation deadline are UNMEASURED. ### Witness encoding This EIP carries full `SignedInclusionList` objects. A compact form (IL header, signature, transaction count and an SSZ branch per witnessed transaction) is smaller when the builder relies on few transactions from an IL. Which encoding to use is open. ## Backwards Compatibility This EIP changes consensus rules and requires a network upgrade. It adds two fields to the execution payload envelope and two roots to the bid, extends `engine_newPayload`, and changes the EIP-7805 omission check. For Profile 1 transactions, the only change is that omission of a transaction with no admitted occurrence under the gas caps is justified. Blob-carrying transactions are not enforced. ## Test Cases Required vectors: - two IL transactions sharing a payer, where the builder includes one and omits the other with a claim; - an unlisted top-of-block transaction that does not write the omitted transaction's state; - an unlisted transaction that drains a payer before the claimed index; - an unlisted transfer of one wei to the payer before the claimed index; - an unlisted relayer transaction that carries an EIP-7702 authorization writing the sender's code; - an unlisted transaction that changes the delegation of a verifier account that the sender's code calls; - a funding chain where each IL transaction funds the payer of the previous one; - a listed transaction that drains a payer, a claim after it, and a later listed transaction that refunds the payer; - an omitted transaction with no claim; - claims out of order, two claims with the same hash, and a claim with an index above the number of block transactions; - an IL where an occurrence above `MAX_GAS_PER_IL_TX` precedes an occurrence that fits; - an envelope whose claims or witnesses do not match the roots in the bid; - a witness from a member whose bit in `inclusion_list_bits` is unset; - a witness from a member whose IL the judging node never stored; - a transaction listed in two ILs of the node's view, omitted with a claim after a writer that one carried witness lists; - the same case with a writer that two carried witnesses list; - two listed transactions that conflict, each listed in one IL, where the builder includes either one and claims the other; - three listed transactions that share a payer whose balance covers two of them, with listing counts 3, 2 and 2; - a member that signs two ILs, each listing one of two transactions that conflict, with the pair carried and with the pair not carried; - a witness with an unset bit from a member with one carried witness; - a node whose frozen view holds fewer ILs that list the omitted transaction than the builder's view; - a bid without `inclusion_list_bits`. ## Security Considerations ### Colluding committee member A builder that controls or colludes with committee members can get an arbitrary transaction `X` into their signed ILs. Nothing requires those ILs to have been gossiped, and a member can sign until the bid is signed. `X` then excuses the omission of a transaction `T` that shares state with it, for example through a key rotation or a payer drain, if the builder has at least `listings(T)` such members. So the writer rule protects `T` in slots where the builder has fewer members than the number of ILs that list `T`. As a model, with independent selection of the 16 members, a builder tied to a fraction `x` of the stake has at least `c` members with these probabilities: | `x` | `c = 1` | `c = 2` | `c = 3` | `c = 4` | |---|---|---|---|---| | 1% | 14.9% | 1.1% | 0.05% | below 0.01% | | 5% | 56.0% | 18.9% | 4.3% | 0.7% | | 10% | 81.5% | 48.5% | 21.1% | 6.8% | With a claimed index alone the builder needs no member. A transaction that only one member lists gets the `c = 1` column: the rule then assumes that the members who list `T` outnumber the members who work with the builder, which is stronger than the one honest member that EIP-7805 assumes for transactions with no conflict. How many ILs list a transaction in practice depends on how includers pick transactions and on transaction size, and is UNMEASURED. `X` does not have to be private. If the builder publishes `X`, honest members can list it too, and those listings count. For a payer drain, the EIP-8141 public mempool limits this: a node does not hold pending frame transactions whose summed maximum costs exceed the payer's balance, so a node that holds `T` does not hold an `X` that leaves the payer unable to pay for `T`. Includers that take transactions from other sources have no such limit. `X` must be signed and carried in the block. If a member also published a different IL, the block and that IL are a proof of equivocation. Includers SHOULD limit the number of transactions per sender and per payer in one IL. Closing this case needs an IL commitment duty before the view freeze, or slashing on equivocation proof, both outside EIP-7805. ### Verdict across nodes The verdict depends on the block, the envelope and the node's frozen IL view. The IL view only sets the obligations. A node that missed an IL has fewer obligations and is more lenient, as in EIP-7805. A carried witness counts for every node, and `listings(T)` only falls when a node holds fewer ILs. So a node that missed an IL never rejects a payload that a node with that IL accepts. A node can hold an IL that the builder never saw. Then it can have more obligations than the builder met, as in EIP-7805, and it can also have a higher `listings(T)` than the builder counted. While the bid has `inclusion_list_bits`, such a bid already fails `is_inclusion_list_bits_inclusive` on gossip if that IL was timely. ### Enshrined proposer-builder separation Under EIP-7732, the payload is revealed after slot `N+1` attestations, and the check runs on envelope verification. A payload that fails the check stays valid but gets no `FULL` tiebreak and is not built on by honest nodes. Because the obligations come from the node's frozen IL view, the check never makes a payload invalid. Otherwise a node could reject a chain that freshly synced nodes accept. The next proposer and the slot `N+2` attesters need to finish the check, replay included, before their deadlines. The time for this is not measured. ### Execution cost `MAX_GAS_PER_IL_TX` and `MAX_GAS_PER_IL` are not set. Until they are, an includer can list transactions that are expensive to simulate. Node replay is at most two replays per omitted transaction, at most `2 * INCLUSION_LIST_COMMITTEE_SIZE * MAX_VERIFY_GAS_PER_IL` `VERIFY` gas per slot, excluding state reconstruction and code loading. The wall time of one replay is not measured. ### Witness size The Heze IL gossip rules, which every witness must meet, reject an IL whose transactions exceed `MAX_TRANSACTIONS_BYTES_PER_INCLUSION_LIST` = 8,192 bytes or contain an empty transaction (consensus-specs Heze p2p interface). `MAX_IL_WITNESSES` = 32 witnesses therefore carry at most `32 * 8,192` = 262,144 bytes of transaction bytes, and 131,072 bytes if no member is a proven equivocator. The SSZ overhead of one witness with `k` transactions is 152 bytes of fixed fields and signature, plus 4 bytes of offset per transaction, plus 4 bytes for its offset in `inclusion_list_witnesses`. Because each transaction is at least 1 byte, `k` is at most 8,192, and one witness is at most `MAX_SIGNED_INCLUSION_LIST_SIZE` = 41,112 bytes. The loose ceiling for the list is `32 * (41,112 + 4)` = 1,315,712 bytes, which a witness reaches only with 1-byte transactions. If every transaction is at least 100 bytes, `k` is at most 81 and the overhead is at most 480 bytes per witness. A payload with no claim that relies on a listed writer carries no witness. The typical witness size is UNMEASURED. One claim is 40 bytes. The builder pays for the extra bytes. ### Profile 1 transactions with delegation Profile 1 omissions are still judged at the end of the payload. An unlisted builder transaction can drain the balance of an EIP-7702 delegated sender through its code and so excuse the omission, the invalidation case of the Motivation. This EIP does not close that case for Profile 1. Applying the claim and the writer rule to Profile 1 senders with a delegation indicator at `S_0` would close it and is left open. ### Fee bumps A transaction that replaces an IL transaction with the same keyed nonce after the view freeze is not listed. It does not excuse the listed transaction, so the builder includes the listed version. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).