OP Stack Integration
Proof-of-concept integration with the OP (Optimism) stack
Last updated
Proof-of-concept integration with the OP (Optimism) stack
Last updated
Espresso has created a proof-of-concept integration of the OP Stack with Espresso. This integration highlights Espresso’s vision of connecting and decentralizing rollups without compromising the scale and speed that rollup users have grown accustomed to.
We designed this integration with the following goals in mind:
The L2 block sequence should be deterministically derivable by the derivation inputs on the L1. L2 derivation inputs consist of deposits, transactions that are forced-included, system configuration updates, and with this integration, a justification proving that L2 transactions were sequenced by Espresso.
The L2 block sequence should be deterministically derivable from the output of Espresso. This allows for faster transaction confirmations because the HotShot network underlying Espresso has a lower latency than the L1.
We accomplished (1) and (2) by modifying the L2 derivation pipeline to enforce that each L2 batch is determined by Espresso, using information available on the L1 (see Mapping the HotShot Block Stream to an OP Batch Stream).
The transaction sequencing flow through the OP-Espresso integration is as follows:
User submits a deposit transaction to the L1 directly. This deposit will be used to fund L2 activity.
User submits an L2 transaction to a .
The proxy forwards transaction data to Espresso. Other RPC requests are routed to an op-geth
instance so that clients like MetaMask can continue to operate normally.
The OP node scans the L1, fetches transaction receipts, and derives deposits from them.
The OP node fetches blocks containing sequenced transactions from Espresso and metadata necessary for justifying the eventual transaction batch. Special care must be taken to ensure that the L2 block sequence can be deterministically derived from the HotShot and L1 transaction sequences (see Mapping the HotShot Block Stream to an OP Batch Stream).
The OP node submits the batch payload to an op-geth
instance.
op-geth
executes the payload, which contains a combination of transactions sequenced by Espresso and L1 derivation inputs.
The OP batcher queries recently executed L2 batches.
The OP batcher posts batches to the batch inbox.
The transaction validation flow through the OP-Espresso integration is as follows:
A HotShot commitment task fetches recently sequenced block commitments from Espresso.
The HotShot commitment task posts these commitments to the HotShot sequencer contract.
An OP node in validator mode fetches deposits from the L1.
The OP node fetches batches from the batch inbox contract.
The OP node fetches block commitments corresponding to the HotShot blocks contained in the batches.
The OP node validates batches according to the OP derivation constraints. Espresso-specific rules that map the HotShot sequence deterministically into an L2 sequence are also validated (see Mapping the HotShot Block Stream to an OP Batch Stream). Additionally, all Espresso transactions are validated against the commitments posted to the HotShot sequencer contract. The namespace proof that the batches contain the complete set of OP transactions in a given window is currently mocked.
The OP node submits the batch payload to the op-geth
instance.
One interesting challenge posed by this integration was the need to transform HotShot, which is responsive, into a fixed-rate L2 batch stream that satisfies OP derivation constraints. This challenge prompted a new feature in HotShot: certifying a recent L1 block number and a timestamp in each block. With certified timestamps, it becomes possible to deterministically derive a batch B
from the HotShot block stream by requiring that it contains all and only the OP transactions from HotShot blocks whose timestamps fall within the sequencing window for B
:
= B.parent.timestamp + rollupConfig.L2BlockTime
B.transactions
includes, in order, all of the HotShot transactions in the range i+1
to j-1
, where
HotShot[i].header.timestamp
< B.timestamp
HotShot[i+1].header.timestamp
>= B.timestamp
HotShot[j-1].header.timestamp
< B.timestamp + rollupConfig.L2BlockTime
HotShot[j].header.timestamp
>= B.timestamp + rollupConfig.L2BlockTime
(1) and (4) prove that there were no additional blocks within the window before or after the HotShot blocks that were included (this is why indices i
and j
are necessary even though the batch transactions are in the block range i+1
to j-1
).
An OP batch also requires an L1Origin
, the L1 block that contains derivation inputs. For this integration, we define the L1Origin
the following way:
Set the L1Origin
as the L1 block certified by the last block in a batch.
Adjust the L1Origin
backwards if necessary (e.g. if the L1Origin
is newer than the L2 batch), or forwards in the rare case that HotShot is very far behind the L1 and L1Origin
is stale.
This definition ofL1Origin
satisfies these properties:
It is a block in the past, so the OP nodes don't have to block waiting for it to be produced
It is relatively recent, so it likely satisfies the OP constraints that would reject a stale L1Origin
.
It is deterministic based on the HotShot block stream.
If after readjustment, the L1Origin
is still invalid (it is too far behind the L2 with respect to the sequencer drift rules), we allow (and require) the OP node to produce an empty batch.
Unlike the Espresso-Polygon zkEVM integration, which uses HotShot for DA, the OP Stack integration currently uses the L1 for DA. OP nodes in validator mode derive the L2 chain from data submitted to the L1.
This underscores the flexibility that rollups have in using Espresso: rollups can opt for any DA solution as long as the data stored can be eventually verified against the HotShot block stream.
Because an OP transaction batch is determined by HotShot consensus even before it is sent to the L1, it is possible to a transaction. Here we describe some motivating applications enabled by .
In certain bridge designs, bonders put up collateral and execute L2 transactions off-chain to allow users of the bridge to transfer tokens cross-chain faster than can strictly be verified on-chain. For example, in Hop, the time to bridge between Optimism and Base is 25 minutes, because that’s the amount of time a bonder needs to be certain the rollup from which the transfer originates won’t reorg. If a transaction was initiated to move funds between rollups using Espresso, the bonder could instead use the pre-confirmations provided by HotShot consensus. This would bring down the bridging time for users from 25 minutes to a couple of seconds.
Similarly, in Across, relayers assist users in cross-chain bridging by sending them tokens on the destination chain after a pre-determined minimum number of block confirmations. With HotShot’s finality guarantees, relayers could safely send users their funds on the destination chain after a transaction is 3 HotShot blocks deep. If both rollups involved in a bridge transaction are using Espresso, then 1 block is enough, as they can’t independently reorg.
The pre-confirmations that HotShot provides serve to make cross-chain bridging safer and more capital efficient for parties such as bonders and relayers, and faster for the end user.
The code for the OP Stack integration proof-of-concept can be found on GitHub: op-espresso-integration
.