In this note we describe a version of Ethereum shared sequencing for "based rollups" that retains the benefits of vanilla based sequencing (liveness, censorship resistance, L1 security and composability etc) while offering rollups stronger finality and a share of sequencing revenue. These are two separate ideas, one that leverages a separate BFT finality gadget (in which L1 validators can optionally participate), and one that uses a proposer selection mechanism similar to execution tickets.
TLDR
This version of based sequencing offers two flavors of preconfirmations: proposer preconfs, and attester preconfs. The proposer preconf comes first (subsecond latency) backed by collateral of an individual proposer for a shared sequencer slot, while the attester preconf comes second (~1-2 second latency) is backed by the collateral (and/or honest supermajority assumption) of all attesters participating in the preconfirmation layer.
Ethereum L1 proposers inherit the right to act as the shared proposer for L2 blocks as well. Participation in the preconfirmation layer as either an attester or proposer requires re-staking ETH (e.g., through Eigenlayer, though other implementations could be used and integrated).
We propose a way for rollups to elevate the status of attester preconfirmations without disrupting any other property of based sequencing. With this change, transactions that carry an attester preconfirmation are final conditioned on some published Ethereum block, meaning they are guaranteed to be executed unless either said Ethereum block is reorged or a threshold of the attesters are malcious (in which case their staked collateral is slashed). Crucially, these transactions may occur on the rollup long after the Ethereum block has already been published. This is not possible with vanilla based sequencing: new rollup transactions included by an L1 proposer in some block \(B_t\) that builds on block \(B_{t-1}\) are not conditionally final based on \(B_{t-1}\) because they will be abandoned in a reorg that drops \(B_{t}\)! A preconfirmation from the L1 proposer doesn't change this fact (i.e., a preconfirmation for the transactions included in \(B_t\) cannot be given risk free, unless the L1 proposer has already seen enough Ethereum attestations to be certain its proposal \(B_t\) won't be reorged).
The L1 proposer for block \(B_t\) may interleave L1 and L2 (rollup) transactions, enabling synchronous composability between L1 contracts and L2 contracts. However, it may prefer to first (using the attester preconfirmation mechanism) sequence rollup transactions that are conditionally final on block \(B_{t-1}\). These transactions may either execute on the rollup prior to any of the transactions included in \(B_t\), or are simply guaranteed to execute on the rollup even in the event that \(B_t\) is reorged. Users may pay tips to enjoy this stronger/faster finality of being conditioned on \(B_{t-1}\), particularly transactions on the L2 that do not depend on any L1 activity in block \(B_t\).
Another significant distinction is that while L1 proposers inherit the right to propose for rollups and give preconfirmations, in the event that an L1 proposer does not exercise this right for their slot another party can acquire it instead. This is particularly beneficial in the (likely) case that initially only a small fraction of L1 proposers participate in rollup sequencing and preconfirmations, and thus L1<>L2 synchronous interactions are less frequent.
Outside of blocks that have synchronous interaction between L1 and L2, which may not be every block for most rollups, transactions can be recorded and made available through the attester side protocol (DA + BFT) and settled to the rollup contract periodically (instead of every Ethereum block). Assuming the side protocol has higher throughput and is cheaper than Ethereum L1, this helps with data compression for rollups. This is particularly advantageous for validiums.
This Ethereum shared sequencer version is also unique in that it internalizes the revenue generated by the preconfirmation layer and it will redistribute this revenue to the based rollups that join it proportional to their marginal contribution.
What is an Ethereum shared sequencer for based rollups?
Quoted from Justin Drake, it is a shared sequencer that achieves the following properties:
There are two key components that are introduced on top of the Ethereum L1. Importantly, they will not be used in any way to compromise on the four properties listed above.
The following is a description of how these components are utilized to achieve an Ethereum shared sequencer for rollups.
First let us distinguish two types of rollup contract calls:
(a L1–>L2 txs: function call depends on and may write to state of Ethereum L1. These include bridge deposits. This will not immediately write to the L2 state but will update a queue that is eventually consumed by an L2->L2 txn.
(b) L2—>L2/L1: updates the rollup state st, has no immediate side effect on L1 state, but may depend on queue of L1->L2 txs, and may update a queue of L1 txs (e.g., withdrawals) that is eventually consumed by an L1 txn.
Tracking the state of Ethereum L1 in BFT-FG. While the BFT-FG state does not execute rollup transactions, there is a minimal state and execution engine within the protocol. The BFT-FG state will track the state of Ethereum as follows. Each BFT state points to the tip of an Ethereum L1 fork, which we can call the <L1_ref>. Every BFT-FG block proposal has the opportunity to update the <L1_ref> to point to a new Ethereum block if either (a) the block is at the tip of a chain that extends the old <L1_ref>, or (b) the block is at the tip of a fork that is “heavier”, i.e. preferred according to the fork choice rule of Ethereum. Note that the BFT-FG state is not guaranteed to track the true latest state of Ethereum at any given time, nor is this equivalent to having all the BFT-FG validators to vote on their opinion of the Ethereum state. However, any honest BFT-FG proposer that knows the latest state will be able to successfully update BFT-FG to reflect this. This is the key property that we want. In essence, BFT-FG acts as a trusted client for the Ethereum L1.
Implicit DAG in the BFT-FG. The chain of BFT-FG blocks induces a DAG structure over L2 states indexed by L1 forks. Every round of BFT-FG may update <L1_ref> pointing to a fork of Ethereum L1 and also adds L2 blocks on the respective rollup namespaces. The <L1_ref> of any L2 block is the <L1_ref> of the previous BFT-FG block. All successive L2 blocks that share the same <L1_ref> will be interpreted by rollups as being executed after the <L1_ref> block and before the next L1 block that follows <L1_ref>. Each L2 block is an L2->L2 contract call to the rollup contract, and thus can be retroactively inserted before the next L1 block without having any immediate impact on L1 state. L2 blocks may still queue operations (e.g. withdrawals) that will eventually have effect on L1 when the contract is updated in an L1 block. L2 blocks may also consume queued txs from the L1 (e.g., deposits). The L1 block also cannot change the state of the rollup contract without going through BFT-FG, but can queue L1->L2 transactions (like bridge deposits). Queued transactions from L2 blocks will be settled in the L1 block that finally updates the L2 state of the rollup contract. Thus, every BFT-FG block is interpreted by the rollups derivation pipelines as being executed on a particular fork of Ethereum, and is by default only final conditioned on the fork finalizing on Ethereum. However, an individual transaction included in a BFT-FG block may elect to be conditionally final based on an earlier Ethereum block that precedes <L1_ref>. Concretely, if a transaction sets its reference point to some Ethereum block id, then rollups will execute this transaction on any fork of Ethereum that includes id. There is a strong reason to do so if the transaction does not depend on any L1→L2 transactions appearing between blocks id and <L1_ref> because it will have stronger finality (block id is less likely to reorg). We provide more details on the contract next.
Proposer for L1 pointer. Every BFT-FG slot has an assigned proposer to update the tracked Ethereum state <L1_ref>, just as any other namespace. The L1 proposer always has the ability to acquire the proposer rights for this as well. Note that while an <L1_ref> update may be proposed simultaneously with rollup blocks in the same BFT-FG slot, as detailed in item 2 above the rollup blocks will be applied first (i.e., occurring before the new L1 block not after).
Rollup smart contract on the L1. The rollup smart contract on the L1 tracks the state of the rollup, but may lag behind. A rollup smart contact is updated by calling it inside an L1 block. Today, rollup contracts are typically only called once per Ethereum block or even less frequently. However, if L1 block building is coordinated with L2 block building, then it is possible that a rollup contract may be called multiple times within a single L1 block, interacting synchronously with other contracts on the L1. Today, most rollup smart contracts have a designated sequencer, a party that must sign off on any update to the contract (with the exception of bridge transactions). We propose that rollups replace this with the following logic.
– The rollup contract stores a state of the BFT-FG (it is a light client for the BFT-FG). The BFT-FG forms a continuous chain (it never forks).
– Rollup contract stores rollup state st, a queue of L1 contract calls, and pointers to the last BFT-FG block h used to update this state. When it receives bridge transactions from contract call inside L1 block, they are added to the queue but this doesn’t immediately change st, which can only be changed by providing proof of the correct execution of L2 blocks finalized by BFT-FG from the last time the contract was updated on the present branch. In more detail, if the contract is called to update the rollup state in an L1 block with identifier id, with current state st and pointer to h where it was updated last, the new state st’ with pointers to h’ should be the result of executing all finalized BFT-FG blocks between h to h’ along the unique fork that id extends. (In the case of OR the rollup contract receives st’ which can be challenged through fraud proofs, and in a ZKR it directly receives a proof of correct derivation). Importantly, it is the order in which L2 blocks and L1 references appear in the BFT-FG that determines the relative ordering of L1/L2 transactions. The L1 block in which the L2 state update is ultimately recorded has no impact on relative ordering, and the recorded state in the L1 contract may lag behind the true state of the L2.
– In the description so far, the BFT-FG only interleaves entire L1 blocks with entire L2 blocks. We add one more feature to enable synchronous interaction between L1 and L2, when the L1 proposer is simultaneously the BFT-FG proposer, which is for BFT-FG to record partial L1 states. Essentially, this allows for building a branch off some <L1_ref> block that interleaves L1 and L2 transactions before a full L1 block is complete, and which will be abandoned if the L1 block containing these transactions is never proposed on the L1. These transactions have much weaker finality until the L1 block containing them is proposed. The L1 proposer can easily reorg this temporary branch recorded in BFT-FG by never proposing. The main purpose of this feature is to enable synchronous composability between L1 and L2 without breaking anything else. We can’t simply allow every L1 block to include L2 transactions without BFT-FG’s involvement as that would break the ability of BFT-FG to provide finality on L2 blocks between L1 blocks as described above. Instead, when the L1 proposer building off of <L1_ref> is also the BFT-FG proposer, it can first get BFT-FG to accept <L1_ref> as the current Ethereum chain head, and then gets BFT-FG to record each successive L1>L2 and L2->L2/L1 transaction in order. The rollup derivation pipeline will execute these transactions in the order they appear. After BFT-FG finalizes each L2->L2/L1 txn the L1 proposer can record the state change in the L1 contract. This enables passing messages from L1 to L2 and from L2 back to L1 in the same block.
Other notes: