Search
K

Espresso ↔ Rollup

In order to keep the sequencer nodes themselves as generic and simple as possible, there is no rollup-specific logic in the Espresso Sequencer itself, and thus the sequencer never actively communicates with any rollup. Instead, sequencer query service nodes present a public interface which rollups are expected to query in order to integrate with the sequencer. This interface takes the form of a REST API.

Types

{
"height": integer,
"timestamp": integer,
"l1_head": integer,
"l1_finalized": null | {
"number": integer,
"timestamp": string,
"hash": string
},
"payload_commitment": [byte]
}

Block

{
"header": Header,
"payload": [byte],
"size": integer,
"hash": string,
}

Leaf

{
"leaf": {
"view_number": integer,
"justify_qc": QC,
"parent_commitment": string,
"block_header": Header,
"proposer_id": string,
},
"qc": QC,
}

Transaction

{
"vm": integer,
"payload": [byte]
}

Endpoints

GET /status/latest_block_height
Get the height of the Espresso Sequencer blockchain
GET /availability/stream/leaves/:height
Subscribe to a sequenced stream of leaves, which include block headers, signatures, and metadata like the proposer ID.
GET /availability/stream/blocks/:height
Subscribe to a sequenced stream of complete blocks. This stream may lag behind the leaf stream since it takes some time for complete blocks to propagate after a leaf is sequenced. However, it will eventually yield the block corresponding to each leaf in the other stream in the same order.
GET /availability/stream/headers/:height
Similar to the leaf and block streams, but yields only the header for each sequenced block.
GET /availability/leaf/:height, GET /availability/leaf/hash/:hash
Get a specific leaf by height or hash, if available.
GET /availability/block/:height, GET /availability/block/hash/:hash
Get a specific block by height or hash, if available.
GET /availability/header/:height, GET /availability/header/hash/:hash
Get a specific block header by height or hash, if available.
GET /availability/block/:height/namespace/:namespace
Get the transactions in a given namespace, with proof
Response
{
"header": Header,
"transactions": [Transaction],
"proof": [byte]
}
GET /availability/headers/window/:start/:end, GET /availability/headers/window/from/:height/:end, GET /availability/headers/window/from/hash/:hash/:end
Get block headers in a time window.
Returns all available headers, in order, whose timestamps fall between :start (inclusive) and :end (exclusive), or between the block indicated by :height or :hash (inclusive) and :end (exclusive). The response also includes one block before the desired window (unless the window includes the genesis block) and one block after the window. This proves to the client that the server has not omitted any blocks whose timestamps fall within the desired window.
It is possible that not all blocks in the desired window are available when this endpoint is called. In that case, whichever blocks are available are included in the response, and next is null to indicate that the response is not complete. The client can then use one of the /from/ forms of this endpoint to fetch the remaining blocks from where the first response left off, once they become available. If no blocks are available, not even prev, this endpoint will return an error.
Response
{
"prev": Header | null,
"window": [Header],
"next": Header | null
}
POST /submit/submit
Submit a transaction to be sequenced. The body of the request contains the transaction to be sequenced and an identifier indicating the rollup which should execute the transaction.

Usage

Rollup nodes may use these APIs differently depending on the role they are playing in the system (e.g., prover, full node, etc.). A prover can use the API to stream block data from the sequencer, so that it can execute blocks as they are sequenced and generate proofs. The prover also interacts with the L1, since it can only verify a rollup proof on the L1 if the L1 has already verified the sequencing of the corresponding block.
Prover / Sequencer Integration
A rollup may also include full nodes which store and provide access to rollup-related state, but do not run a prover. Such a full node can stream blocks and verify consensus proofs (QCs) directly from the HotShot APIs, without interacting with the L1. Avoiding interaction with the L1 allows state updates to be computed faster.
Full Node / Sequencer Integration
The rollup also interacts with HotShot via the submit API. This interaction is completely independent of the streaming interaction illustrated above. It is simply used to add transactions to HotShot’s mempool so that they may eventually be included in the sequence. Any rollup node which serves a rollup API (e.g. JSON-RPC) should be able to handle transaction submissions through HotShot's submit API.
The body of submit requests includes the transaction to submit as well as a rollup-specific numeric identifier. This identifier is associated with the transaction in the final sequence, so rollup proofs can use the ID to easily exclude transactions intended for other rollups. Each rollup should have its own protections against cross-rollup replay attacks, such as an EVM chain ID, in addition to this rollup ID.