This is a proposal for structuring the fork choice in a manner that is compatible with the goals and constraints of epbs, FOCIL, and PeerDAS.
Overall, the slot still very much resembles the epbs slot from the PTC proposal, which has seen quite a bit of iteration since and has been the basis for EIP-7732. In particular, we still have the main phases of the epbs slot: beacon block proposal, attesting (so far just like in today's slot), payload release and finally a committee voting on the payload. This committee, formerly known as the payload timeliness committee (PTC), is renamed to availability committee (AC), because it now not only has the responsibility to vote both on payload timeliness (which itself could also be thought of as payload availability at the time of the vote), but also on the availability of the blob data associated to the payload (columns in PeerDAS).
In addition to these phases from the existing epbs proposals, we have a "freeze" deadline similar to that in in FOCIL (generally inspired by the view-merge concept), which is used both to ensure that the next proposer has enough time to satisfy all ILs that end up being enforced by attesters, and to ensure that its view of the AC's vote coincides with that of the attesters.. This is all to ensure that an honest proposer can be sure to do the right thing, i.e., extend the correct chain so that its proposal is attested to and becomes part of the canonical chain.
There are a few actors in the pipeline, so let's separately break down what each of them are doing and how their behaviors all fit together. We focus on a slot N, where a beacon block \(B\) is proposed, committing to a payload \(P\), and then look at the whole chain of actions that play a role in the outcome, including the proposal and attestations of slot \(N+1\). We assume that the chain is fully stable up until this point.
Firstly, a builder, including a local block builder, has to make a payload, with the added constraint of satisfying ILs. Compared to vanilla FOCIL, without epbs, IL enforcement is initially done by the AC members rather than by attesters. The reasoning for this is that the next proposer (slot N+1) needs to know whether the current payload "passed the IL check" (which is time dependent, so not objective), and thus whether it should extend it or not, before the next round of attestations even happens. As in FOCIL, validators will enforce the ILs that that they have seen by the freeze deadline (10s in the slot structure above, though could be earlier), and a builder can ensure that they satisfy all of them by taking into account all ILs they see until later in the slot, up until constructing the payload.
However, one of the goals of epbs is to not require the AC members to execute the payload before voting, so that we relax the timing constraints for payload execution. Without executing, the AC members cannot by themselves check whether the payload actually satisfies the ILs: a certain IL tx might not be contained, but only because it was invalidated during execution of the payload, which after EIP-7702 might even happen without a transaction from the same sender being in the block. In order to aid the AC member in their enforcement role, the payload contains a bitfield specifying from which of the IL proposers the builder has received an IL. We explain later how this is used in enforcement.
The default builder behavior is quite simple:
Though it is not part of the builder's behavior, it is crucial to specify a payment processing rule. In the good case where \(P\) is released and becomes canonical the payment is immediately processed, and otherwise the payment is held up for some time to try to attribute whose fault it was that the exchange did not work out:
We are going to argue that, assuming sufficient network synchrony and connectedness of the builder, the protocol achieves the following properties:
The rationale for the default release rule used by the builder is simple, and immediately gives us these properties:
Very little changes about the behavior of the proposer. Here, we focus on the proposer of slot N+1 to continue with our analysis of the process started at slot N. Firstly, the proposer runs the fork-choice just like today, with the exception of blocks with and without payloads being separate and competing fork-choice objects. If the head of the chain is not a beacon block proposed in slot N, it just extends it normally. If instead it is a beacon block \(B\) from slot N, and it is not subject to proposer boost reorging, it has to determine whether to extend \(B\) or its payload \(P\) (more precisely, the object "\(B\) with payload"). At this point, it cannot do so based on attestations from slot \(N\), because attesters in slot \(N\) did not have a chance to attest to \(P\) yet. Instead, it uses the availability committee to make this determination, by using a relative majority threshold: if a majority of the AC votes it received (not necessarily of all possible votes) is positive, it extends \(P\), and otherwise extends \(B\) (without a payload). As we'll see in the upcoming section about attesters, this is the same criterion they use to decide what to attest to.
In order to prevent cases where the AC is roughly evenly divided and a few strategically released adversarial votes can sway attesters against what the proposer chose, we use a lightweight view-merge, only applied to the AC votes from the previous slot:
As usual, one needed clarification is what to do with equivocating AC votes. Luckily, in this case we have a very simple way of dealing with them:
With this, assuming sufficient network synchrony, the AC votes used by attesters in slot N+1 will exactly coincide with the AC votes used by the proposer. The reasoning is simple: the set of votes seen by the proposer is a superset of the votes seen by any attester, except possibly in the case of equivocations, and in the case of equivocations the attesters will just default to agreeing with the proposer. More explicitly:
The availability committee has three purposes:
An AC member acts like this throughout slot N:
As we already discussed, the proposer and attesters of slot N+1 require the payload to get a majority of AC votes. Assuming the AC is majority honest (or a bit more in the case of the DA check, to account for the error induced by partial availability views), this means that the AC can succesfully enforce that the payload be published on time and with a bitfield that commits to satisfying all timely sent ILs.
The DA check differs somewhat from the rest, in that attesters in the next slot will again do their own DA check, and so will attesters in future slots as well: no one will attest to something unavailable, even if for whatever reason this has happened in previous slots. As already mentioned at the beginning, the AC is not so much enforcing DA, but rather providing an early signal about DA to the next proposer, in case it cannot make a full availability determination by itself.
While the timeliness and DA enforcement is straightforward, the IL enforcement is not so, so let's discuss it a bit more in detail. The bitfield is used by the next slot's proposer to decide whether to extend the payload or not, by checking satisfaction of the ILs it implicitly references, and in the same way it will be used by the next slot's attesters to decide whether to vote for the payload (or a block extending it) or not. In other words, IL enforcement is split into two parts:
A small caveat here is that a bitfield over IL proposers does not uniquely specify an IL in the case of IL proposer equivocation, where the builder might have seen and satisfied one IL but other nodes might expect another one to be satisfied. However, our propagation rule for ILs prescribes to propagate up to two ILs per IL proposer, so that equivocation evidence spreads by default. Then, attesters of slot N+1 will simply ignore any ILs from equivocating IL proposers: even if the bitfield has a 1 for a certain equivocating IL proposer, attesters will treat it as a 0, so they will not put any extra constraint on the payload based on ILs sent by that proposer.
Finally, we are getting to the last actors in our pipeline, the ultimate enforcers of everything that we have discussed, because responsible for solidifying temporary local decisions and AC votes into the fork-choice.
Let's first discuss exactly how the fork-choice works in this context. Instead of just beacon blocks, the block tree now has two kinds of objects: empty and full beacon blocks, or in other words beacon blocks without and with a payload. For a given beacon block \(B\) committing to payload \(P\), both "\(B\) with \(P\)" and "\(B\) without \(P\)", or \(B\) empty and \(B\) full, have the same parent in the fork-choice tree, which is \(B\)'s parent (and which could itself be an empty or a full block). As usual for objects with the same parent in the fork-choice tree, \(B\) empty competes with \(B\) full, meaning that only one of the two branches can be chosen when the fork-choice is run.
Choosing a branch is done by picking the subtree with the most attestation weight, as always, but with a small caveat: the votes to \(B\) empty from \(slot(B)\) are counted both for \(B\) empty and \(B\) full, whereas votes from slots \(> slot(B)\) can only fall in one of the two subtrees. There's a simple reason for this: attesters in \(slot(B)\) can only attest to \(B\) empty, because at that point the payload has not been released yet. The decision between \(B\) empty and \(B\) full is initially made by the AC, and it is then solidified by the round of attestations in \(slot(B)+1\), as we discuss in the next section. At that point, those attestations are the only fork-choice weight that distinguishes \(B\) empty from \(B\) full, since the attestations from \(slot(B)\) count for both, and they therefore fully determine the final decision between them.
Attesters at slot N+1 run the fork-choice and figure out what the head of the chain is. There are two cases depending on whether or not a beacon block from slot \(N\) is reached:
As already mentioned in the section about the availability committee, "ILs referenced by the bitfield" means "all ILs sent by IL proposers with a 1 in the bitfield, excluding only equivocators".