Skip to content

test(prover): select the rollup sample block by message shape - #178

Draft
spalladino wants to merge 1 commit into
spl/fi-s06-insertion-block-bisectfrom
spl/fi-s07-continuation-sample-selector
Draft

spalladino wants to merge 1 commit into
spl/fi-s06-insertion-block-bisectfrom
spl/fi-s07-continuation-sample-selector

Conversation

@spalladino

@spalladino spalladino commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

prover-client/src/test/regenerate_rollup_sample_inputs.test.ts drives representative epochs through the simulated
orchestrator and commits the serialized circuit inputs each rollup circuit pushed, so that CI can run nargo execute
against a current fixture. Two of its scenarios exist specifically to capture a block-root run whose start message
sponge is inherited from an earlier block of the same checkpoint rather than the initial empty one — that is what
exercises the circuit's per-block sponge continuity asserts.

They were not doing that. The scenario splits two messages into the first block and three into the second, and then
committed data[0]: the first block, whose inherited sponge is empty. The sample never covered the shape it was
written for.

Capture order cannot identify a block here — blocks are proven concurrently, so which run lands in data[0] is not a
property of the scenario. A scenario that runs a block-root circuit more than once now declares the block it means by
its message shape ({ inherited, bundle }), and a new selectSample resolves that shape against the captured runs.
It throws rather than guessing in every ambiguous case: nothing captured, several runs captured with no declared
shape, or a declared shape matching zero runs or more than one. Each message names the circuit and prints the shapes
actually captured.

Three scenarios declare a shape: the single-tx block root (the block that carries the whole bundle, {0, 256}, out of
three runs), the two-input block root ({2, 3}, replacing the empty-sponge first block), and the tx-less block root
({2, 3}). Circuits that take no message bundle are captured once per scenario and still resolve as the sole
candidate without declaring anything.

The committed sample artifact is deliberately left stale

This rung ports the selector only. It does not regenerate the sample.

The generated Prover.toml fixtures live in noir-projects/fnd/noir-protocol-circuits/crates/<circuit>/, which this
repository does not carry at all — running the generator here fails at the write with
ENOENT: .../noir-projects/fnd/noir-protocol-circuits/crates/rollup-block-root/Prover.toml. The committed
rollup-block-root sample in the repository that does own it still has start_msg_sponge.num_absorbed = 0, i.e. the
old empty-sponge capture, on both the old stack head and current next. The selector now demands
{ inherited: 2, bundle: 3 }, so once the owning generator workflow is run the sample will change.

Correcting it is a separate aztec-packages change that runs the generator with AZTEC_GENERATE_TEST_DATA=1, checks
the result has a non-empty inherited sponge, and runs nargo execute. That companion change also has to account for
the generator resolving noir-projects/... under the wrong repository root after the repository split. This PR is
useful on its own but the fixture repair is not complete until that circuit artifact lands.

Stack position

This is rung 15 of 25 in the Fast Inbox node stack, stacked on spl/fi-s06-insertion-block-bisect.

Source

Reconstructs the regenerate_rollup_sample_inputs.test.ts hunks of 4ef9a73073 from old PR #25440. The destination
file was byte-identical to that commit's pre-image apart from the @aztec/ -> @aztec-labs/ package scope and one
import blank line, so this is the source's final state. The same commit's archiver hunks landed as FI-S05 and its
streaming_inbox.test.ts hunks as FI-S06; neither is touched again here.

Test-only. No production source, no generated artifact, no Noir change. The diff is 69 added and 7 removed lines in
one file, matching the source hunk exactly.

Does this run in CI?

No. The whole suite is describe.skip unless AZTEC_GENERATE_TEST_DATA=1 is set — a plain run reports
1 skipped, 6 skipped, 6 total and does no prover setup. Nothing in ordinary CI exercises the selector; it runs only
when a developer regenerates the samples, which is exactly the moment the wrong block would otherwise be committed.
The evidence below therefore comes from driving the generator directly with the flag set.

Tests run

  • yarn build — green.
  • yarn format, yarn lint — clean, no changes to the file.
  • yarn workspace @aztec-labs/prover-client test src/test/regenerate_rollup_sample_inputs.test.ts — 1 suite skipped,
    6 tests skipped, as expected without the flag.
  • yarn workspace @aztec-labs/prover-client test --testPathIgnorePatterns bb_prover_ — 16 suites, 256 passed,
    6 skipped, exit 0: exact parity with the base branch. The two bb_prover_* files drive real barretenberg proving
    and are left to CI.
  • No e2e suites were run.

Red/green

The generator was run directly with AZTEC_GENERATE_TEST_DATA=1 (about 14s for all six scenarios), with the write
replaced by a probe so nothing was written anywhere.

The shape correction, against real captured data:

PROBE captured rollup-block-root:      [{"inherited":0,"bundle":2},{"inherited":2,"bundle":3}]
PROBE old data[0] rollup-block-root:   {"inherited":0,"bundle":2}
PROBE new selected rollup-block-root:  {"inherited":2,"bundle":3}

That is the bug and the fix in one line: the old code committed the block with the empty inherited sponge; the new
code commits the continuation block. The single-tx scenario captures three runs
([{0,256},{256,0},{256,0}]), so its data[0] was correct only by accident of ordering; the declared shape now pins
it.

Each guard was then made to fire by mutating the declarations:

  • declared shape matching more than one run — sampleFrom: { 'rollup-block-root-single-tx': { inherited: 256, bundle: 0 } }:
    Expected exactly one rollup-block-root-single-tx run inheriting 256 messages and inserting 0, found 2 of 3 runs ({"inherited":0,"bundle":256}, {"inherited":256,"bundle":0}, {"inherited":256,"bundle":0}).
  • declared shape matching no run — { inherited: 7, bundle: 9 } on rollup-block-root:
    Expected exactly one rollup-block-root run inheriting 7 messages and inserting 9, found 0 of 2 runs ({"inherited":0,"bundle":2}, {"inherited":2,"bundle":3}).
  • several runs with no declared shape — deleting the single-tx sampleFrom:
    rollup-block-root-single-tx ran 3 times ({"inherited":0,"bundle":256}, {"inherited":256,"bundle":0}, {"inherited":256,"bundle":0}); declare in sampleFrom which run to commit.

The "nothing captured" branch is the pre-existing check and is preserved verbatim.

Left out

  • The regenerated Prover.toml sample, per the section above: it belongs to aztec-packages and this repository does
    not contain the protocol circuit crates.
  • The other two parts of 4ef9a73073 — archiver re-mining fixture (FI-S05) and findInsertingBlock bisection
    (FI-S06) — which landed on earlier rungs.
  • The seven deferred work families. The old Noir-fixture cleanup is adjacent to this area and was
    explicitly kept out. The diff touches one test file and contains none of it.

The rollup sample scenario splits 2 then 3 messages across two blocks but committed `data[0]`, the first block,
whose inherited message sponge is empty. That is the wrong sample: the block-root variant these scenarios exist to
cover is one that continues a non-empty sponge from an earlier block of the same checkpoint.

Blocks are proven concurrently, so capture order does not identify a block. A scenario that runs a block-root
circuit more than once now declares the shape it means — how many messages the block inherits and how many its own
bundle inserts — and the selector resolves that against the captured runs. It throws when nothing was captured,
when several runs were captured with no declared shape, and when a declared shape matches no run or more than one,
rather than silently pinning whichever input arrived first.

The committed sample artifact still holds the old capture. It lives in the protocol circuit crates, which this
repository does not carry, so correcting it is a separate change in the repository that owns the generator
workflow.
@spalladino
spalladino added this pull request to stack #188 September 12, 2026 04:52
@spalladino spalladino added the ci-draft Run CI on this draft PR label Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on this draft PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant