Skip to content

feat(fast-inbox): add block_root_msgs_only_rollup circuit for no-tx blocks with messages (A-1375) - #24612

Closed
spalladino wants to merge 5 commits into
spl/a-1374-per-block-bundlesfrom
spl/a-1375-msgs-only-block
Closed

feat(fast-inbox): add block_root_msgs_only_rollup circuit for no-tx blocks with messages (A-1375)#24612
spalladino wants to merge 5 commits into
spl/a-1374-per-block-bundlesfrom
spl/a-1375-msgs-only-block

Conversation

@spalladino

@spalladino spalladino commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Stacked on #24603 (A-1374). AZIP-22 Fast Inbox, FI-05.

What

Adds block_root_msgs_only_rollup (crate rollup-block-root-msgs-only, VK index BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX) — a non-first, transaction-less block that still inserts a non-empty L1→L2 message bundle. This lets a proposer keep draining the Inbox into a checkpoint when the tx pool is dry. It is completely inert pre-flip: nothing in the node produces this shape until FI-12.

Circuit

Modeled on the first-empty variant but for a mid-checkpoint position (block_root_msgs_only_rollup.nr):

  • asserts num_msgs > 0 (a message-only block with no messages has no reason to exist);
  • inherits start_sponge_blob and start_msg_sponge from the previous block (non-empty), sets is_first_block = false, appends the bundle to the L1→L2 tree and absorbs the message sponge, threads the start sponge blob through unchanged (no tx effects);
  • deliberately cannot be leftmost — the checkpoint root requires the leftmost rollup's is_first_block to be true.

Composes via a new new_from_no_rollups_with_start_sponge_blob (a new_from_no_rollups that takes an inherited sponge blob instead of an empty one; the first-empty variant now delegates to it, preserving its empty-sponge start).

Wiring

  • BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX added to the vk tree and the ALLOWED_PREVIOUS_VK_INDICES of the block-merge and both checkpoint-root variants.
  • New crate + Nargo registration; pinned-build.tar.gz regenerated.
  • TS: proving request type + schema + ProvingJobResultsMap entry, the ServerCircuitProver interface method and all implementers (bb-prover, TestCircuitProver, MockProver, BrokerCircuitProverFacade), the proving-broker queue map + priority list + job-controller dispatch, and npct artifact/type generation.

Tests

Noir (rollup_lib, 386 passed) covers the roadmap done-when — a checkpoint [first block, msgs-only block, normal block] — plus the failure cases: num_msgs == 0 rejected, a msgs-only block cannot be leftmost, and merge continuity catches a bad hinted start_msg_sponge. yarn build, lint, and the orchestrator + proving-broker suites (123) are green. Cross-chain l1_to_l2 e2e: only the two pre-registered-flaky duplicate-consume cases fail (a pre-existing PXE nullifier-sync issue, unrelated). A codex review found no soundness or wiring bugs.

Deferred to FI-12/FI-15 (orchestrator selection + integration test)

block-proving-state.ts selecting this variant, and an orchestrator integration test driving a mid-checkpoint msgs-only block, are intentionally not in this PR. Driving one requires reworking the transitional per-block message distribution: today the first block carries the whole padded checkpoint bundle and non-first blocks inherit the full checkpoint sponge and absorb nothing, so a msgs-only block absorbing real messages mid-chain would break both the block-merge right.start_msg_sponge == left.end_msg_sponge continuity and the checkpoint-root merged.end_msg_sponge == parity.end_sponge check. That distribution rework belongs with the sequencer that actually produces these blocks (FI-12) and its live-path e2e (FI-15). The circuit is fully proven by the noir tests, and the existing BlockProvingState guard still rejects non-first zero-tx blocks, so nothing can construct the shape until that work lands.

Proving-result schema (CI fix)

The ProvingJobResult Zod discriminated union was missing a member for the new BLOCK_ROOT_MSGS_ONLY_ROLLUP request type added here, so once the flip (A-1384) lets the node actually produce a message-only block, decoding its proving result threw Invalid discriminator value in jsonParseWithSchema and stalled the epoch (surfaced as a cross-chain e2e timeout up-stack). The union member is added alongside the request type in this PR — its natural home, since this is where the type is introduced. A stdlib round-trip regression test (proving-job-source.test.ts) serializes a message-only block-root result and asserts it decodes back with type === BLOCK_ROOT_MSGS_ONLY_ROLLUP.

@spalladino
spalladino requested a review from LeilaWang as a code owner July 8, 2026 18:08
@spalladino
spalladino force-pushed the spl/a-1374-per-block-bundles branch from ef2b683 to cce1329 Compare July 9, 2026 00:40
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from 425f45b to a5eca42 Compare July 9, 2026 00:40
@spalladino
spalladino force-pushed the spl/a-1374-per-block-bundles branch from cce1329 to d6ea15d Compare July 13, 2026 19:37
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from a5eca42 to 1dd74af Compare July 13, 2026 19:52
@spalladino
spalladino force-pushed the spl/a-1374-per-block-bundles branch from d6ea15d to 84ffffa Compare July 13, 2026 21:52
@spalladino
spalladino requested a review from just-mitch as a code owner July 13, 2026 21:52
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from 1dd74af to bae1a1f Compare July 13, 2026 21:53
@spalladino
spalladino force-pushed the spl/a-1374-per-block-bundles branch from 84ffffa to 4f4bbc5 Compare July 14, 2026 20:02
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from bae1a1f to f7cca39 Compare July 14, 2026 20:06
@spalladino spalladino changed the title feat: add block_root_msgs_only_rollup circuit for no-tx blocks with messages (A-1375) feat(fast-inbox): add block_root_msgs_only_rollup circuit for no-tx blocks with messages (A-1375) Jul 17, 2026
@spalladino
spalladino force-pushed the spl/a-1374-per-block-bundles branch from 4f4bbc5 to 6a5308f Compare July 17, 2026 19:38
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch 3 times, most recently from 5f7c796 to 225af28 Compare July 19, 2026 14:05
@spalladino
spalladino force-pushed the spl/a-1374-per-block-bundles branch 2 times, most recently from 2182e4a to d833027 Compare July 19, 2026 17:57
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch 2 times, most recently from 71e0c1b to f0ea9e4 Compare July 19, 2026 20:48
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch 3 times, most recently from 415a05a to aacbdb1 Compare July 20, 2026 21:21
@spalladino
spalladino force-pushed the spl/a-1374-per-block-bundles branch 2 times, most recently from 2051695 to 444c427 Compare July 21, 2026 02:58
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from aacbdb1 to 00a27bf Compare July 21, 2026 02:59
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from 00a27bf to 8f692f1 Compare July 21, 2026 03:39
@spalladino
spalladino force-pushed the spl/a-1374-per-block-bundles branch 2 times, most recently from 6a7ffee to 85bfeba Compare July 27, 2026 20:53
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from 8f692f1 to 7d1183e Compare July 27, 2026 20:53
…essages (A-1375)

Adds the block_root_msgs_only_rollup variant (crate rollup-block-root-msgs-only,
VK index BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX) — a non-first, transaction-less block
that still inserts a non-empty L1-to-L2 message bundle, so a proposer can keep draining
the Inbox when the tx pool is dry (AZIP-22 Fast Inbox, FI-05).

The circuit asserts num_msgs > 0, inherits the sponge blob and message sponge from the
previous block, sets is_first_block = false, appends the bundle and absorbs the message
sponge, and threads the start sponge blob through unchanged (no tx effects). It is
deliberately unable to be leftmost: the checkpoint root requires the leftmost rollup's
is_first_block to be true.

Wires the new VK into the allowed-VK lists of the block merge and both checkpoint-root
variants, the vk tree, and the proving request / artifact / bb-prover registrations. Noir
tests prove a checkpoint [first block, msgs-only block, normal block] and cover the
num_msgs == 0, non-leftmost, and sponge-continuity failure cases.

The orchestrator selection (block-proving-state picking this variant) and its integration
test are deferred to FI-12/FI-15: driving a mid-checkpoint msgs-only block requires
reworking the transitional per-block message distribution (today the first block carries
the whole padded checkpoint bundle and non-first blocks are empty), which belongs with the
sequencer that actually produces these blocks. Nothing produces the shape pre-flip.
…s_first_block (A-1375)

The message-only block root is listed in the single-block checkpoint-root allowlist only for symmetry;
today the inputs validator's is_first_block assertion is the sole reason it cannot stand as a checkpoint's
only block. Note that if that assertion is ever relaxed, this entry must be dropped in the same change, so
the two decisions are not made independently.
…vingJobResult schema (A-1375)

BLOCK_ROOT_MSGS_ONLY_ROLLUP was added to the enum, the ProvingJobInputs union, and the
result type map, but omitted from the ProvingJobResult discriminated union. A checkpoint
that builds a message-only block produces this proof output, which the proof store then
fails to decode with an invalid-discriminator error, stalling proving. Add the missing
union member, mirroring the other block-root results. Adds a schema round-trip regression
test.
…375)

Persisted broker jobs are keyed by the numeric ProvingRequestType, and this branch
inserts BLOCK_ROOT_MSGS_ONLY_ROLLUP into the middle of the enum, shifting every later
value. A prover restarted in place over an existing data directory would otherwise
dequeue a stale job and hand it to the wrong prover method; the version check already
discards a database whose schema version does not match.
@spalladino

Copy link
Copy Markdown
Contributor Author

Superseded by #25036.

The Fast Inbox stack has been regrouped from 20 per-issue PRs (plus 2 umbrellas) down to 3 area PRs plus an umbrella, and rebased onto merge-train/spartan including #25007 (the noir-projects fnd//labs/ split). This PR's diff is preserved verbatim as a single squashed commit in #25036, and this description is preserved in that commit's message.

New structure: #25036 (circuits + L1) → #25037 (node + flip) → #25038 (cleanup), with #25039 as the full-stack umbrella. The original branch for this PR is left on the remote as a recovery point.

Closing here to cut the rebase and review overhead of maintaining 22 PRs; the work is not abandoned.

@spalladino spalladino closed this Jul 28, 2026
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