Abstract
This EIP defines when a builder may omit an EIP-8141 frame transaction that an inclusion list (IL) lists under EIP-7805. It specifies the enforcement that EIP-8369 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 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. 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
Nis the slot of the ILs. SlotN+1is the slot of the bid and payload. - An occurrence is one transaction entry in one IL.
tx_gas(tx)ismax_gasas defined in EIP-8141 for a frame transaction, and the signed gas limit otherwise.- IL members are the slot
NIL 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 envelope bytes.
listings(T)is the number of IL members, proven equivocators excluded (see Claims and witnesses), whose frozen-view IL has an admitted occurrence ofT.- A Profile 1 transaction is a legacy, EIP-2930, EIP-1559 or EIP-7702 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_hasheslist; ignoring the optional expiry verifier frame and an optional EIP-8272 recent root verifier frame at the position EIP-8272 allows, matches one of the prefix shapesself_verify,deploy | self_verify,only_verify | payordeploy | only_verify | payby modes, flags and targets; has no frame in the validation prefix withATOMIC_BATCH_FLAGset; and has no frame after the validation prefix with modeVERIFY. - EIP-4844 transactions and frame transactions with a non-empty
blob_versioned_hasheslist 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 nonce and keyed nonce check made before the first frame, and a replay of the validation prefix of T meets all of the following:
- 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
SLOTNUMandSLOADpermissions. The EIP-8141 public mempoolMAX_VERIFY_GASlimit and other mempool-only policies do not apply; replay gas is bounded byMAX_VERIFY_GAS_PER_TXas below. The prefix is the frames up to and including the first frame whoseAPPROVEsets the payer. - If present, the first non-expiry frame is a deploy frame that installs code or an EIP-7702 delegation indicator at
T.sender. - The prefix reads state only from the Profile 2 surface:
nonce,balanceand code ofT.senderand of the payer; storage slots0toAA_VOPS_SLOT_COUNT - 1ofT.senderand of the payer; the EIP-8250NONCE_MANAGERentries for(T.sender, key)for every nonzero key inT.nonce_keys; the EIP-8272RECENT_ROOT_ADDRESSstorage keys derived from the tuples of the recent root verifier frame ofT; and the code of any other account that the prefix calls or delegates to. - The total size of distinct code bodies the prefix loads is at most
MAX_VERIFY_CODE_BYTES. - The recent root verifier frame of
T, if present, succeeds. - The prefix succeeds and sets the payer through
APPROVE_PAYMENTorAPPROVE_EXECUTION_AND_PAYMENT, and the payer can paymax_costas 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 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:
- If the bytes do not decode to a valid transaction, skip it. Nothing is deducted.
- If
tx_gas(tx) > MAX_GAS_PER_IL_TXortx_gas(tx)exceeds the gas left in the IL, skip it. Nothing is deducted. - If
txis a Profile 2 candidate, run the EIP-8369 staticVERIFYbudget fill step for this occurrence: compute signature and prefix cost, skip with no debit if their sum exceedsMAX_VERIFY_GAS_PER_TXor theVERIFYgas 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 theVERIFYdebits made so far. - If
txis neither a Profile 1 transaction nor a Profile 2 candidate, skip it. Nothing is deducted. - 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 ExecutionPayloadEnvelope for slot N+1 gains two fields, and ExecutionPayloadBid gains their roots:
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: RootAn 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) 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 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,balanceand code ofT.senderand of the payer;- storage slots
0toAA_VOPS_SLOT_COUNT - 1ofT.senderand of the payer; - the
NONCE_MANAGERentries for(T.sender, key)for every nonzero key inT.nonce_keys; - the
RECENT_ROOT_ADDRESSstorage keys derived from the tuples of the recent root verifier frame ofT; - the code of every other account whose code the replay on
S_0loads, 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:
fee_valid(T, block);is_profile2_eligible(T, S_0);iis not clean forT; oris_profile2_eligible(T, S_i)and the replay onS_ireads no state key outsideR(T);Tfits 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 withtransactionHash(DATA, 32 bytes) andindex(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
VERIFYbudget: Thomas Thiery (soispoke), "FOCIL and Native Account Abstraction", Ethereum Magicians topic 27999, March 2026, proposed the per-ILVERIFYbudget 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
inclusionListsparameter 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_TXprecedes 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_bitsis 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.
