Prototype sequencer, currently backed by a dummy wallet app (Transfer, Withdrawal).
Current focus is reliability of sequencing, persistence, and replay semantics.
- Language: Rust (edition 2024)
- API: Axum (
POST /tx,GET /ws/subscribe) - Hot path: single blocking inclusion lane
- Storage: SQLite (
rusqlite, WAL) - Signing: EIP-712 (
alloy) - Payload encoding: SSZ
- User ops arrive through the API, are validated, executed, and persisted by the inclusion lane.
- Direct inputs are stored in SQLite (
direct_inputs) and sequenced in append-only replay order (sequenced_l2_txs). - Deposits are direct-input-only (L1 -> L2) and are not accepted as user ops.
- Ordering is deterministic and persisted. Replay/catch-up reads
sequenced_l2_txsjoined withuser_opsanddirect_inputs. - Frame fee is fixed per frame (
frames.fee):- users sign
max_fee - inclusion validates
max_fee >= current_frame_fee - execution charges
current_frame_fee - the next frame fee is sampled from
recommended_feeswhen rotating to a new frame
- users sign
From repo root:
cargo check
cargo test
cargo fmt --all
cargo clippy --all-targets --all-features -- -D warningsRun the server with a local deployment domain:
SEQ_ETH_RPC_URL=http://127.0.0.1:8545 \
SEQ_DOMAIN_CHAIN_ID=31337 \
SEQ_DOMAIN_VERIFYING_CONTRACT=0x1111111111111111111111111111111111111111 \
cargo run -p sequencerOptional runtime inputs:
SEQ_HTTP_ADDRdefaults to127.0.0.1:3000SEQ_DB_PATHdefaults tosequencer.dbSEQ_LONG_BLOCK_RANGE_ERROR_CODESdefaults to-32005,-32600,-32602,-32616
Required runtime inputs:
SEQ_ETH_RPC_URLSEQ_DOMAIN_CHAIN_IDSEQ_DOMAIN_VERIFYING_CONTRACT
Fixed protocol identity:
- domain name:
CartesiAppSequencer - domain version:
1
Most queue sizes, polling intervals, and safety limits are now internal runtime constants instead of public launch-time configuration.
Request shape:
{
"message": {
"nonce": 0,
"max_fee": 1,
"data": "0x..."
},
"signature": "0x...",
"sender": "0x..."
}Notes:
signaturemust be 65 bytes.senderis required and must match the recovered signer.message.datais SSZ-encoded method payload bytes.- payload size is bounded at ingress; oversized requests are rejected before entering the hot path.
- overload is enforced at queue admission: if the inclusion-lane queue is full,
POST /txreturns HTTP429with codeOVERLOADEDand messagequeue full. - queue capacity is an internal runtime constant tuned alongside inclusion-lane chunking to absorb short bursts; if this starts triggering persistently, it is a signal to revisit runtime sizing or throughput rather than add another admission layer.
WebSocket stream of sequenced L2 transactions from persisted order.
Notes:
from_offsetis optional and defaults to0.- messages are JSON text frames.
- binary fields are hex-encoded (
0x-prefixed). - the current runtime enforces a subscriber cap of
64and a catch-up cap of50000events. - if the requested catch-up window exceeds that cap, the server upgrades and then immediately closes the socket with close code
1008(POLICY) and reasoncatch-up window exceeded.
Message shapes:
{ "kind": "user_op", "offset": 10, "sender": "0x...", "fee": 1, "data": "0x..." }{ "kind": "direct_input", "offset": 11, "payload": "0x..." }Success response:
{
"ok": true,
"sender": "0x...",
"nonce": 0
}batches: batch metadataframes: frame boundaries within each batchframes.fee: committed fee for each frameuser_ops: included user operationsdirect_inputs: direct-input payload streamsequenced_l2_txs: append-only ordered replay rows (UserOpxorDirectInput)recommended_fees: singleton mutable recommendation for the next frame fee
sequencer/src/main.rs: thin binary entrypointsequencer/src/lib.rs: public crate surfacesequencer/src/config.rs: runtime input parsing and EIP-712 domain constructionsequencer/src/runtime.rs: sequencer bootstrap and component wiringsequencer/src/api/: HTTP API and error mappingsequencer/src/inclusion_lane/: hot-path inclusion loop, chunk/frame/batch rotation, catch-upsequencer/src/input_reader/: safe-input ingestion from InputBox into SQLitesequencer/src/l2_tx_feed/: DB-backed ordered-L2Tx feed for WS subscriptionssequencer/src/storage/: schema, migrations, SQLite persistence, and replay readssequencer-core/src/: shared domain types and interfaces (Application,SignedUserOp,SequencedL2Tx, feed message types)examples/app-core/src/: wallet prototype implementingApplicationbenchmarks/: benchmark harnesses and benchmark spec
- Wallet state is in-memory and not persisted.
- Schema and migrations are still in prototype mode and may change.
- Some
sequencertests spin upAnvil; install Foundry locally if you want the full test suite: - Self-contained benchmarks also spawn
Anvilfrom a preloaded rollups state dump.
foundryup- Prepare local benchmark + guest build dependencies:
just setup- Enable the Anvil-backed reader tests explicitly:
RUN_ANVIL_TESTS=1 cargo test -p sequencer --libApache-2.0. See LICENSE.
Authors are listed in AUTHORS.