Skip to content

feat: per-block L1-to-L2 message bundles, move parity to checkpoint root (A-1374)#24603

Open
spalladino wants to merge 6 commits into
spl/a-1373-inbox-rolling-hashfrom
spl/a-1374-per-block-bundles
Open

feat: per-block L1-to-L2 message bundles, move parity to checkpoint root (A-1374)#24603
spalladino wants to merge 6 commits into
spl/a-1373-inbox-rolling-hashfrom
spl/a-1374-per-block-bundles

Conversation

@spalladino

Copy link
Copy Markdown
Contributor

Stacked on #24600 (A-1373). AZIP-22 Fast Inbox, FI-04.

What

Moves parity verification from the block-root circuits to the checkpoint root, and gives every block-root variant a per-block L1→L2 message bundle. This gets the circuit structure right for per-block messages while keeping behavior bit-identical to today — the flip to compact per-block distribution (FI-14) becomes a constant change plus padding removal, not a circuit restructure.

Circuits (noir)

  • Block-root variants take a message bundle (l1_to_l2_messages, num_msgs, frontier hint) and append it to the L1→L2 tree via append_leaves_to_snapshot (the A-1372 gadget), absorbing the same leaves into an L1ToL2MessageSponge (Poseidon2) threaded across the checkpoint's blocks. First-block variants lose the parity-root proof.
  • BlockRollupPublicInputs drops in_hash and the FI-03 inbox_rolling_hash pair; gains is_first_block: bool and start_msg_sponge/end_msg_sponge. is_first_block takes over in_hash's former structural role (leftmost asserted true at the checkpoint root, every right rollup asserted false at merge) and drives the block-end blob-absorb flag.
  • Block merge propagates is_first_block and start_msg_sponge from the left, end_msg_sponge from the right; validate_consecutive_block_rollups asserts !right.is_first_block and right.start_msg_sponge == left.end_msg_sponge.
  • Checkpoint root verifies the moved parity-root proof, asserts parity.start_sponge == empty and merged.end_msg_sponge == parity.end_sponge (the "blocks inserted exactly the parity-committed list, in order" check — no leaf arrays cross a circuit boundary), and sources the header's in_hash = parity.sha_root and inbox_rolling_hash = parity.end_rolling_hash.
  • Parity base absorbs the padded batch into a message sponge; parity root threads it across the four bases alongside the rolling hash.

TypeScript

  • New stdlib/src/messaging/l1_to_l2_message_sponge.ts mirrors the noir sponge (iv-0, absorb-only). Parity/block/checkpoint-root inputs and conversion/server.ts mirror the field changes.
  • Orchestrator DAG: parity proofs move from block-proving-state.ts to checkpoint-proving-state.ts; the sub-tree enqueues parity once per checkpoint and surfaces it in SubTreeResult; block roots no longer gate on parity. Transitional wiring: first block carries the checkpoint's messages padded to 1024 (num_msgs=1024), non-first blocks carry empty bundles inheriting the checkpoint sponge.

Constants

L1_TO_L2_MESSAGE_SPONGE_LENGTH = 10; BLOCK_ROLLUP_PUBLIC_INPUTS_LENGTH 58 → 76. Circuit ABIs changed, so pinned-build.tar.gz is regenerated and committed.

Testing

  • noir rollup_lib 386 passed (adds sponge-threading, is_first_block structural, and checkpoint-root parity/sponge-mismatch failure cases); transitional equivalence held (append_matches_subtree_insert_1024, unchanged checkpoint-header fixtures).
  • yarn build, yarn lint/format, forge, orchestrator suites (15), and touched stdlib suites (22) all green.
  • Cross-chain l1_to_l2 e2e: the real send+consume path (the new per-block bundle circuit path) works; the suite's only two cases are the duplicate re-consumption ones, which hit a pre-existing PXE nullifier-sync issue registered flaky in .test_patterns.yml, unrelated to this change.
  • A codex cross-layer review found no correctness bugs; it confirmed sponge chunking associativity, tree/list pinning, is_first_block soundness, header sourcing/continuity, the blob-flag derivation, and TS↔noir serde order.

…oot (A-1374)

Implements AZIP-22 Fast Inbox FI-04. Parity verification moves from the block-root
variants to the checkpoint root. Every block-root variant now takes a per-block message
bundle (l1_to_l2_messages, num_msgs, frontier hint) that appends to the L1-to-L2 tree via
append_leaves_to_snapshot and absorbs the same leaves into an L1ToL2MessageSponge threaded
across the checkpoint's blocks. BlockRollupPublicInputs replaces in_hash and the FI-03
inbox_rolling_hash pair with an explicit is_first_block flag and start/end message sponges.
The checkpoint root gains the parity-root proof, asserts sponge continuity and that the
merged block sponge equals the parity sponge, and sources the header's legacy in_hash and
inbox_rolling_hash from parity. Transitionally the first block carries the whole checkpoint's
messages padded to 1024 with num_msgs=1024; non-first blocks carry empty bundles. Behavior
stays bit-identical to the current state (same tree roots, same header bytes).
@spalladino spalladino requested a review from LeilaWang as a code owner July 8, 2026 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant