EIP-7805 Inclusion lists enforced by fork choice (Fork-choice enforced Inclusion Lists (FOCIL))
No call decision · Consensus & staking · EIP status Draft · created 2024-11-01
A 16-validator committee each slot builds an inclusion list from public mempool transactions, and attesters do not vote for blocks that leave those transactions out, so transactions get included on time without censorship.
Why it is needed
To keep the validator set from centralizing, Ethereum has handed the right to build blocks to specialized firms called builders through an auction. As a result, a small number of sophisticated builders came to dominate block production, and the network's censorship resistance, its ability to stop specific transactions from being left out, got worse. Research followed on letting validators place constraints on builders, and the method is the inclusion list (IL), which forces transactions into a block. However, earlier inclusion list designs and proposals for joint block construction had problems with bribery and coercion attacks, list equivocation, account abstraction, and transaction invalidation. FOCIL addresses these problems by having a committee of many validators build the lists and by putting a rule into fork choice that attesters do not vote for blocks that fail to satisfy the lists.
What changes
Today
- Block-building power is concentrated in a few specialized builders, and nothing prevents a builder from leaving out a particular transaction.
- The earlier inclusion list design (EIP-7547) is forward-looking, so transactions are enforced one slot late.
- If a single proposer builds the inclusion list, it is exposed to bribery and coercion attacks.
After EIP-7805
- Each slot, a 16-member committee each picks transactions from the public mempool and gossips an inclusion list.
- The proposer or builder must include the transactions from the collected lists in the block. Attesters do not vote for a block that omits them, so it cannot become part of the canonical chain.
- A transaction submitted in slot N can be enforced directly in the block of slot N+1.
- A list transaction may be left out if it would be invalid when appended to the end of the block or if the block is full (conditional inclusion).
Who is affected
- Users: Submitting a transaction to the public mempool makes it harder for a builder to drop it arbitrarily. How wallets are used and what users experience do not change.
- Validators: If selected for the committee, a validator builds and gossips a list each slot, and attesters vote only for blocks whose list conditions they have checked. There is no separate reward.
- Builders and proposers: Builders must receive all lists for slot N and update the payload at second 11, so they need good connectivity to committee members.
- Client teams: Changes to the beacon chain, fork choice and P2P on the consensus layer must be implemented together with Engine API changes on the execution layer, and a hard fork is required.
In depth
Inclusion list check on the execution layer
When the execution layer receives a new payload, it performs one more check. After executing all transactions in block B, let the state be S and the remaining gas be gas_left. For each transaction T in the inclusion list, it proceeds in the following order. First, if T is already in B, it moves on to the next transaction. Second, if T.gas is greater than gas_left, it moves on to the next transaction. Third, it checks the nonce and balance of T.origin against S. If T is invalid, it moves on to the next transaction. If T is valid, it stops immediately and returns the INCLUSION_LIST_UNSATISFIED status. In other words, if any list transaction missing from the block could still be executed when appended to the end, the list is not satisfied. In that case the block itself is valid, but the consensus layer does not attest to it.
Engine API changes and list building rules
Three changes are made to the Engine API. A new engine_getInclusionListV1 endpoint is added to retrieve the inclusion list from the ExecutionEngine. engine_forkchoiceUpdated is extended so that the inclusion list to use when building a block is passed in payloadAttributes. engine_newPayload gets a new parameter carrying the inclusion list transactions set by the committee, and it must return the INCLUSION_LIST_UNSATISFIED status if the list is not satisfied. How to fill the list is left to the implementer. Transactions can be chosen at random from the public mempool, in order of priority fee, or in order of longest waiting time. However, the total size of the RLP-encoded transactions cannot exceed MAX_BYTES_PER_INCLUSION_LIST = 8 KiB.
Beacon chain constants and new containers
Three values are added to the beacon chain preset. DOMAIN_IL_COMMITTEE is DomainType('0x0C000000'), IL_COMMITTEE_SIZE is uint64(2**4), which is 16 members, and MAX_BYTES_PER_INCLUSION_LIST is uint64(2**13), which is 8192 bytes. The new container InclusionList has four fields: slot, validator_index, inclusion_list_committee_root and transactions. transactions has the type List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]. SignedInclusionList carries an InclusionList as message and attaches a signature of type BLSSignature. The full changes to the beacon chain, fork choice, P2P and the honest validator guide are split up under _features/eip7805 in the consensus-specs repository.
Fork choice and P2P changes
Three rules are added to fork choice. Inclusion lists received over gossip before the view freeze deadline are stored. If two or more lists are received from the same committee member, that member is marked as an equivocator and later lists are ignored. A beacon block in the current slot is attested to only if it satisfies all stored lists from members who are not equivocators. P2P gains one global topic for gossiping SignedInclusionList and one RPC topic for requesting a SignedInclusionList by committee index. After the attestation deadline of slot N+1 (t=4s) has passed, validators ignore new lists from the previous slot's committee and also stop recording equivocation evidence.
Six consensus layer P2P validation rules
When a validator receives an inclusion list, it checks six things before propagating or storing it. 1) The slot of the list matches the current or previous slot. 2) The committee root the list points to matches the expected committee root for that slot. 3) No more than two lists have been received from this member. 4) The validator signature is valid. 5) The validator belongs to the committee. 6) The list size does not exceed MAX_BYTES_PER_INCLUSION_LIST = 8 KiB. These rules limit list size and restrict authorship to a small committee, which keeps bandwidth consumption tightly bounded. The only meaningful check during propagation is signature verification, so the verification time burden is also small. No execution layer validity check is done at this stage, so a list is propagated even if it contains invalid transactions. This choice avoids extra computation.
Six design principles
Committee based: many validators, not a single proposer, build the list, which greatly reduces the attack surface for bribery and coercion. Fork choice enforcement: forced inclusion is placed in the fork choice rule, the core of the consensus process, so no one can bypass it. A block that fails the conditions gets no attester votes, so it cannot become part of the canonical chain. Same slot: the list runs in parallel with building the slot N+1 block during slot N, so a transaction submitted in slot N can be enforced right away. This is a clear improvement over forward-looking list designs such as EIP-7547, which had a one-slot delay. Conditional inclusion: if a transaction cannot be appended to the end of the block or the block is full, some list transactions are accepted as missing. Position independence: it does not matter where in the block the list transactions appear, which reduces the incentive to route around the protocol through side channels, and combined with conditional inclusion, it makes an off-protocol market less attractive. No reward: committee members receive no explicit reward. The complexity of adding a fee scheme is judged not to be justified, and because the assumption is that only 1 of N committee members needs to be honest, the design relies on altruistic participation.
Security considerations: liveness, equivocation, payload construction
Consensus liveness: the builder for slot N+1 cannot build a canonical block before it receives the lists gossiped in slot N. Builders (including proposers who build blocks themselves) therefore need good connectivity to committee members, and there must be enough time between the view freeze (t=9s of slot N) and block propagation to collect the lists and update the payload. Equivocation: a P2P rule propagates at most two lists per member. If two different lists from the same member are seen, all of that member's lists are ignored. In the worst case, gossip subnet bandwidth can double. Payload construction: a naive approach that checks the lists' missing transactions against the post-state, appends a valid one to the end, and then restarts the check from the beginning can require n + (n-1) + (n-2) + ... checks for n transactions, that is, O(n^2) checks. One example is when only the nth transaction is valid, and its execution sends balance to the sender of the (n-1)th transaction, making each one valid in turn. Instead, before building the payload, the builder can store the nonce and balance of every EOA involved in the list transactions and update them only when a nonce rises or a balance changes without a nonce change (for example, when an account abstraction transaction interacted with that EOA), which lets it judge validity in real time.
Status and fork inclusion discussion
This EIP is in Draft status, so its content may change. The source also says the exact timing for the builder to freeze the list view and update the payload will be set after testing and benchmarking. It is a backward-incompatible change to the consensus layer block validation rules, so a hard fork is required, but nothing breaks current user activity or experience. In the core developer calls, 09.21 ACDT #97 confirmed that Hegotá devnets would start separately, one for FOCIL only and one for frames only, and then merge into a combined Hegotá devnet once stable. The decision separates complex interactions early to make root causes easier to find. 10.12 ACDT #100 confirmed that heze-devnet-2 would include EIP-7805 (FOCIL) together with EIP-8015 (remove eth1data), EIP-8365 (ban 0x00 validators) and EIP-8198 (quick slots, 12 seconds), so the consensus layer Hegotá candidates are verified together on one devnet.