AggregateVerifier games on L1. It selects the next checkpoint from the latest onchain parent
state, obtains a TEE proof for that range, validates the proof against canonical L2 state, and
creates the next dispute game through DisputeGameFactory.
The production proposer is controlled by its configured L1 transaction signer. Its output is still
self-validating: each game is uniquely identified by the game type, claimed output root, parent,
L2 block number, and intermediate output roots, and the proof can be checked by the onchain verifier
and by independent challengers.
Responsibilities
A conforming proposer performs the following work:- Read the active
AggregateVerifierimplementation and proposal parameters from L1. - Recover the latest onchain parent state from
AnchorStateRegistryandDisputeGameFactory. - Select the next checkpoint block that is no later than the chosen safe head.
- Build a
prover_proverequest for the checkpoint range. - Accept only TEE proof results for proposal creation.
- Revalidate the aggregate output root and all intermediate roots against canonical L2 state immediately before L1 submission.
- Optionally pre-check the TEE signer against
TEEProverRegistry. - Submit
DisputeGameFactory.createWithInitData()with the required bond. - Retry transient proof, RPC, and transaction failures without creating out-of-order games.
Startup Configuration
At startup, the proposer connects to:- an L1 execution RPC for contract reads and transaction submission
- an L2 execution RPC for agreed L2 block headers
- a rollup RPC for sync status and output roots
- a prover RPC that implements
prover_prove AnchorStateRegistryDisputeGameFactory- an optional
TEEProverRegistry
BLOCK_INTERVAL must be at least 2, INTERMEDIATE_BLOCK_INTERVAL must be non-zero, and
BLOCK_INTERVAL % INTERMEDIATE_BLOCK_INTERVAL must be 0. The number of intermediate roots in a
proposal is:
Parent Recovery
The proposer recovers the latest onchain parent state from L1 before planning new work. The parent state is:AnchorStateRegistry:
-
Compute:
-
Fetch the canonical output root for every intermediate checkpoint:
for
iin1..=BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL. -
Treat the final intermediate root as the canonical root claim for
expectedBlock. -
Encode
extraDatafromexpectedBlock,parentAddress, and the ordered intermediate roots. -
Look up the expected game:
-
If the lookup returns
address(0), stop. The current parent is the latest recovered state. - Otherwise, advance the parent to the returned game proxy and continue.
Checkpoint Selection
After recovery, the next proposal target is:targetBlock unless:
safeHead is either:
finalized_l2.number, by defaultsafe_l2.number, only when non-finalized proposals are explicitly enabled
Proof Request
For a checkpoint range, the proposer builds aProofRequest with:
| Field | Value |
|---|---|
l1_head | Hash of the latest L1 block at request construction time |
l1_head_number | Number of the latest L1 block at request construction time |
agreed_l2_head_hash | L2 block hash at parentL2BlockNumber |
agreed_l2_output_root | Parent output root recovered from L1 |
claimed_l2_output_root | Rollup RPC output root at targetBlock |
claimed_l2_block_number | targetBlock |
proposer | L1 address that will submit the proposal transaction |
intermediate_block_interval | INTERMEDIATE_BLOCK_INTERVAL |
image_hash | Expected TEE image hash |
ProofResult::Tee for proposal creation. A ZK proof result is not valid input
for the current proposer path.
TEE Proposal Journal
The TEE prover returns:- an aggregate proposal for the full checkpoint range
- per-block proposals for the blocks in that range
journal is packed as:
intermediateRoots are sampled every INTERMEDIATE_BLOCK_INTERVAL blocks and include
the final target block root.
Pre-Submission Validation
Immediately before submitting to L1, the proposer must re-check the proof against canonical L2 state:- Fetch the rollup output root at
targetBlock. - Require it to equal the aggregate proposal’s
outputRoot. - Extract the intermediate roots from the per-block proposals.
- Fetch the canonical output root for each intermediate checkpoint.
- Require every proposed intermediate root to equal its canonical root.
TEEProverRegistry is configured, the proposer should recover the TEE signer from the
aggregate proposal signature and call:
false, the proposer must not submit that proof. It should discard the
proof and request a new one. If the registry check itself fails because of an RPC or deployment
issue, the proposer may continue to submission and rely on the onchain verifier to enforce signer
validity.
Game Creation
The proposer creates a game with:extraData is packed, not ABI-encoded:
l2BlockNumber is encoded as a 32-byte big-endian integer. parentAddress is the recovered parent
game proxy address, or the AnchorStateRegistry address for the first game after the anchor.
initData is the TEE proof bytes for AggregateVerifier.initializeWithInitData():
v value in the signature must be normalized to 27 or 28 before submission.
initBond is read from DisputeGameFactory.initBonds(gameType) at startup and is sent as the
transaction value. Nonce management, fee bumping, signing, and transaction resubmission are handled
by the L1 transaction manager.
Duplicate Games
The factory key for a game is:createWithInitData() reverts with GameAlreadyExists, the proposer treats the target as
already submitted. It refreshes recovery from L1 and continues from the recovered tip. This handles
the case where a previous transaction succeeded but the proposer did not observe the receipt, or
where another valid proposer submitted the same game first.
Retry Behavior
The proposer retries transient failures on later ticks:| Failure | Required behavior |
|---|---|
| Recovery RPC or contract read failure | Skip the current tick and retry recovery on the next tick |
| Proof request failure | Retry the target on a later tick |
| Repeated proof failure | Reset pipeline state and recover from L1 |
| L1 submission failure | Keep the proved result and retry submission on a later tick |
| L1 submission timeout | Treat as a submission failure and retry after recovery |
GameAlreadyExists | Treat as success, refresh recovery, and continue |
| Canonical root mismatch | Reset pipeline state and re-prove from recovered L1 state |
| Invalid TEE signer | Discard the proof and request a new one |
Admin Interface
The proposer may expose an optional JSON-RPC admin interface. When enabled, it provides:| Method | Result |
|---|---|
admin_startProposer | Starts the proving pipeline |
admin_stopProposer | Stops the proving pipeline |
admin_proposerRunning | Returns whether the pipeline is running |