FOCIL implements a robust mechanism to preserve Ethereum’s censorship resistance properties by guaranteeing timely transaction inclusion.
FOCIL (Fork-choice enforced Inclusion Lists) is built in a few simple steps:
In an effort to shield the Ethereum validator set from centralizing forces, the right to build blocks has been auctioned off to specialized entities known as builders. This has led to a few sophisticated builders dominating block production, leading to a deterioration of the network’s censorship resistance properties. To address this issue, research has focused on improving Ethereum's transaction inclusion guarantees by enabling validators to impose constraints on builders. This is achieved by force-including transactions in blocks via ILs.
FOCIL is a committee-based, fork-choice enforced inclusion list (IL) design that improves upon previous IL mechanisms and block co-creation proposals. It addresses issues related to bribing/extortion attacks, IL equivocation, account abstraction (AA), and transaction invalidation.
This section outlines the workflow of FOCIL, detailing the roles and responsibilities of various participants: IL committee members, validators, builders, proposers and attesters.
Slot N
, t=0 to 8s
:
IL committee members construct their ILs by including transactions pending in the public mempool, and broadcast them over the P2P network after processing the block for slot N
and confirming it as the head. If no block is received by t=7s
, they should run get_head
and build and release their ILs based on the node’s local head.By default, ILs are built by selecting raw transactions from the public mempool, ordered by priority fees, up to the IL’s maximum size in bytes of MAX_BYTES_PER_INCLUSION_LIST = 8 KiB
per IL. Additional rules can be optionally applied to maximize censorship resistance, such as prioritizing valid transactions that have been pending in the mempool the longest.
Slot N
, t=0s to 9s
: Validators receive ILs from the P2P network and store (1) all new ILs that pass the CL P2P validation rules, and (2) any evidence of IL equivocation by committee members (i.e., if multiple ILs are received from the same committee member).
Slot N
, t=9s
to Slot N+1
, t=4s
: After the view freeze deadline at t=9s
, validators:
After the attestation deadline of Slot N+1
, t=4s
, validators ignore any new ILs related to the previous slot's IL committee, and stop recording equivocation evidence for the previous slot's ILs.
Slot N
, t=0s to 11s
: The builder (i.e., a proposer doing local block building or an external builder) receives ILs from the P2P network, forwarding and caching those that pass the CL P2P validation rules. Optionally, an RPC endpoint can be added to allow the builder to request missing ILs from its peers (e.g., by committee index at t=10s
).
Slot N
, t=11s
:
The builder freezes its view of ILs and asks the EL to update its execution payload by adding transactions from its view (the exact timings will be defined after running some tests/benchmarks).
Slot N+1
, t=0s
:
The proposer broadcasts its block with the up-to-date execution payload satisfying IL transactions over the P2P network.Slot N+1
, t=4s
:
Attesters monitor the P2P network for the proposer’s block. Upon detecting it, they verify whether all transactions from their stored ILs are included in the proposer’s execution payload, except for ILs whose sender has equivocated. Based on their frozen view of the ILs from t=9s
in the previous slot, attesters check if the execution payload satisfies IL conditions. This is done either by confirming that all transactions are present or by determining if any missing transactions are invalid when appended to the end of the payload. In such cases, attesters use the EL to perform nonce and balance checks to validate the missing transactions and check whether there is enough space in the block to include the transaction(s).When validators receive ILs from the P2P network, they perform a series of validation checks before forwarding or caching them. These rules protect against Denial-of-Service attacks by (1) limiting ILs' byte size and (2) restricting IL proposals to a small committee of IL committee members, thereby tightly bounding bandwidth, the main resource consumed by the propagation of ILs. Consumption of other relevant resources, such as verification time, is minimal because the only nontrivial check performed on IL propagation is signature verification. At this stage, there is no EL verification of the transactions within ILs. This means that ILs are allowed to contain any transactions—valid or invalid—since validators do not perform EL-side validity checks. This design choice is intended to avoid additional computational overhead.
MAX_BYTES_PER_INCLUSION_LIST = 8 KiB
).On the execution layer, the block validity conditions are extended such that, after all of the transactions in the block have been executed, we attempt to execute each valid transaction from ILs that was not present in the block. If one of those transactions executes successfully, then the block is invalid.
Let B
denote the current block.
Let S
denote the execution state following the execution of the last transaction in B
.
For each transaction T
in ILs, perform the following:
Check whether T
is present in B
. If T
is present, then jump to the next transaction, else continue with next step.
Validate T
against S
.
If T
is invalid, then continue to the next transaction.
If T
is valid, terminate process and assert block B
as invalid.
Execute T
on state S
. Assert that the execution of T
fails.
If B
is full, the process terminates. Also note that we do not need to reset the state to S
, since the only way for a transaction to alter the state is for it to execute successfully, in which case the block is invalid, and so the block will not be applied to the state.
We make the following changes to the engine API:
engine_getInclusionList
endpoint to retrieve an IL from the ExecutionEngine
engine_newPayload
endpoint to include a parameter for transactions in ILs determined by the proposerengine_forkchoiceUpdated
endpoint to include a field in the payload attributes for transactions in ILs determined by the proposerThe full consensus changes can be found in the following GitHub repository. They are split between:
Name | Value |
---|---|
DOMAIN_IL_COMMITTEE |
DomainType('0x0C000000') |
IL_COMMITTEE_SIZE |
uint64(2**4) (=16) |
MAX_BYTES_PER_INCLUSION_LIST |
uint64(2**13) (=8192) |
class InclusionList(Container):
slot: Slot
validator_index: ValidatorIndex
inclusion_list_committee_root: Root
transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST]
class SignedInclusionList(Container):
message: InclusionList
signature: BLSSignature
SignedInclusionList
objects.SignedInclusionList
based on IL committee index.slot N+1
during slot N
, the constraints imposed on block B
for slot N+1
can include transactions submitted during slot N
. This represents a strict improvement over forward IL designs like EIP-7547, where the forward property introduced a 1-slot delay.1-out-of-N
honesty assumption from IL committee members for the mechanism to work as intended.This EIP introduces backward incompatible changes to the block validation rule set on the consensus layer and must be accompanied by a hard fork. These changes do not break anything related to current user activity and experience.
The builder of slot N+1
cannot construct a canonical block without first receiving the ILs broadcast during slot N
. This means that the builder (including cases in which the proposer locally builds its block) must be well-connected to the IL committee members to ensure timely access to these inclusion lists. Additionally, there must be sufficient time between the view freeze deadline (t=9s
of slot N
) and the moment the proposer must broadcast block B
to the rest of the network. This buffer allows the builder to gather all available ILs and update the execution payload of block B
accordingly.
To mitigate IL equivocation, FOCIL introduces a new P2P network rule that allows forwarding up to two ILs per IL committee member. If the proposer or attesters detect two different ILs sent by the same IL committee member, they should ignore all ILs from that member. In the worst case, the bandwidth of the IL gossip subnet can at most double.
The builder, responsible for constructing the execution payload, must ensure that the IL is satisfied. A naive way to do so would be to build an initial payload in whatever way the builder desires, then execute the following algorithm:
The issue with this simple approach is that, given a set of n
IL transactions, one might end up needing to do n + (n-1) + (n-2) + ...
validity checks, so O(n^2)
. For example, the n
th tx might be valid while all others are not, but its execution sends balance to the sender of the (n-1)
th tx, making it valid, and in turn, the (n-1)
th sends balance to the sender of the (n-2)
th tx, etc.
To efficiently ensure that all valid IL txs have been included in the payload, builders can adopt a simple strategy: prior to building the payload, they store the nonce
and balance
of all Externally Owned Accounts (EOAs) involved in IL transactions. As they construct the payload, builders track these EOAs, maintaining and updating each EOA's nonce
and balance
whenever changes occur—specifically, when the nonce
increments (indicating that a transaction from that EOA has been executed) or when the balance
changes without a nonce
increment (e.g., after an Account Abstraction (AA) transaction has interacted with that EOA).
This tracking allows builders to verify IL transaction validity in real-time, enabling them to add transactions sequentially until all remaining transactions are either invalid because the nonce or balance of the associated EOA does not change or cannot be included due to insufficient gas. This approach minimizes overhead by keeping track only of the state changes that are relevant to the validity of IL txs.
Copyright and related rights waived via CC0.