Zone Proving
Zone settlement uses validity proofs to verify correct execution. The prover implements a pure state transition function in Rust with no_std compatibility, allowing it to run in both ZKVMs (SP1) and TEEs (SGX/TDX).
Batch Submission
The sequencer posts batches to Tempo Mainnet via submitBatch on the portal. Each batch covers one or more zone blocks and includes:
| Field | Description |
|---|---|
tempoBlockNumber | Tempo block the zone committed to (from zone's TempoState) |
recentTempoBlockNumber | Optional recent block for ancestry proof (0 = direct lookup) |
blockTransition | Zone block hash transition (prevBlockHash → nextBlockHash) |
depositQueueTransition | Deposit queue processing progress |
withdrawalQueueHash | Hash chain of withdrawals for this batch (0 if none) |
verifierConfig | Opaque payload for the verifier (domain separation / attestation) |
proof | Validity proof or TEE attestation |
The portal verifies that prevBlockHash matches the stored blockHash, calls the verifier, and on success updates withdrawalBatchIndex, blockHash, lastSyncedTempoBlockNumber, and adds withdrawals to the queue.
Verifier Interface
The verifier is abstracted behind a minimal interface. ZK systems and TEE attesters implement the same contract:
interface IVerifier {
function verify(
uint64 tempoBlockNumber,
uint64 anchorBlockNumber,
bytes32 anchorBlockHash,
uint64 expectedWithdrawalBatchIndex,
address sequencer,
BlockTransition calldata blockTransition,
DepositQueueTransition calldata depositQueueTransition,
bytes32 withdrawalQueueHash,
bytes calldata verifierConfig,
bytes calldata proof
) external view returns (bool);
}The proof verifies that:
- Valid state transition from
prevBlockHashtonextBlockHash. - Zone committed to
tempoBlockNumbervia TempoState. - Anchor block hash matches (direct or ancestry mode).
ZoneOutbox.lastBatch()has the correctwithdrawalBatchIndexandwithdrawalQueueHash.- Deposit processing is correct (validated via Tempo state read inside proof).
- Zone block
beneficiarymatches the registered sequencer.
State Transition Function
The prover takes a complete witness of zone blocks and their dependencies, executes the EVM state transitions, and outputs commitments for on-chain verification:
pub fn prove_zone_batch(witness: BatchWitness) -> Result<BatchOutput, Error>Execution Flow
- Verify Tempo state proofs. Validate MPT proofs for all Tempo storage reads against Tempo state roots.
- Initialize zone state. Load the zone state from the witness, binding the initial state root to the previous block hash.
- Execute zone blocks. For each block:
- Validate parent hash continuity and block number sequencing.
- Verify beneficiary matches the registered sequencer.
- Execute
advanceTempo()system transaction (if present) to process deposits. - Execute user transactions via revm.
- Execute
finalizeWithdrawalBatch()in the final block only. - Compute the zone block hash from the simplified header.
- Extract output commitments. Block hash transition, deposit queue transition, withdrawal queue hash, and last batch parameters.
Deployment Modes
ZKVM (SP1): The prover runs inside a ZKVM. The witness is read from the ZKVM IO, and the output is committed to the proof.
TEE (SGX/TDX): The same function runs inside a trusted execution environment. The output is signed by the TEE attestation.
Ancestry Proofs
EIP-2935 provides access to the last ~8,192 block hashes on Tempo. If a zone is inactive longer than this window, tempoBlockNumber rotates out of EIP-2935, which would prevent batch submission.
The solution verifies ancestry inside the ZK circuit:
- The portal reads
recentTempoBlockNumberhash from EIP-2935 (must be recent). - The prover includes Tempo headers from
tempoBlockNumber + 1torecentTempoBlockNumberas witness data. - The proof verifies the parent hash chain: each header's parent hash must match the previous header's hash.
- The portal verifies the constant-size proof against the recent block hash.
| Mode | Condition | Behavior |
|---|---|---|
| Direct | recentTempoBlockNumber = 0 | Portal reads tempoBlockNumber hash from EIP-2935 |
| Ancestry | recentTempoBlockNumber > tempoBlockNumber | Portal reads recentTempoBlockNumber hash; proof verifies parent chain |
Proving time increases linearly with the block gap (each gap block adds ~1 keccak operation), but on-chain verification cost remains constant. This prevents the zone from becoming stuck after an extended downtime.
Tempo State Access
The zone accesses Tempo state via the TempoState predeploy (0x1c00...0000). During batch execution:
ZoneInboxcallsTempoState.finalizeTempo(header)to advance the zone's view of Tempo.- System contracts read Tempo storage via
TempoState.readTempoStorageSlot(), restricted to zone system contracts only. - The proof includes Merkle proofs for each Tempo account and storage slot accessed during the batch.
Tempo state staleness depends on how frequently the sequencer calls advanceTempo(). The zone client must only finalize Tempo headers after finality to avoid reorg risk.
Was this helpful?