Skip to content

Commit c84a6cc

Browse files
committed
chore: regenerate rollup sample inputs for inbox rolling hash ABI (A-1373)
Exposing the inbox rolling hash on the parity-root and rollup public inputs changed the ABI of the block-root-first variants, block-merge, checkpoint-merge and root circuits, but their committed crates/rollup-*/Prover.toml sample inputs were not refreshed. CI runs `nargo execute` against these fixtures, so all six failed to deserialize (e.g. missing parity_root.public_inputs.start_rolling_hash and previous_rollups[].public_inputs.start_inbox_rolling_hash). Regenerate the six stale fixtures. The circuits push their serialized inputs via pushTestData when run through the prover, so a new prover-client test drives representative epochs through the simulated orchestrator and dumps the captured inputs, replacing the dead orchestrator_single_checkpoint.test.ts regeneration path. The suite is skipped unless AZTEC_GENERATE_TEST_DATA=1 is set.
1 parent 172d7b0 commit c84a6cc

7 files changed

Lines changed: 1770 additions & 1578 deletions

File tree

noir-projects/noir-protocol-circuits/crates/rollup-block-merge/Prover.toml

Lines changed: 237 additions & 233 deletions
Large diffs are not rendered by default.

noir-projects/noir-protocol-circuits/crates/rollup-block-root-first-empty-tx/Prover.toml

Lines changed: 117 additions & 114 deletions
Large diffs are not rendered by default.

noir-projects/noir-protocol-circuits/crates/rollup-block-root-first-single-tx/Prover.toml

Lines changed: 165 additions & 162 deletions
Large diffs are not rendered by default.

noir-projects/noir-protocol-circuits/crates/rollup-block-root-first/Prover.toml

Lines changed: 401 additions & 398 deletions
Large diffs are not rendered by default.

noir-projects/noir-protocol-circuits/crates/rollup-checkpoint-merge/Prover.toml

Lines changed: 340 additions & 336 deletions
Large diffs are not rendered by default.

noir-projects/noir-protocol-circuits/crates/rollup-root/Prover.toml

Lines changed: 339 additions & 335 deletions
Large diffs are not rendered by default.
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2+
import { EpochNumber } from '@aztec/foundation/branded-types';
3+
import { timesAsync } from '@aztec/foundation/collection';
4+
import { Fr } from '@aztec/foundation/curves/bn254';
5+
import { EthAddress } from '@aztec/foundation/eth-address';
6+
import { type Logger, createLogger } from '@aztec/foundation/log';
7+
import { getTestData, isGenerateTestDataEnabled } from '@aztec/foundation/testing';
8+
import { updateProtocolCircuitSampleInputs } from '@aztec/foundation/testing/files';
9+
import type { CircuitName } from '@aztec/stdlib/stats';
10+
11+
import TOML from '@iarna/toml';
12+
13+
import { TestContext, makeTestDeferredJobQueue } from '../mocks/test_context.js';
14+
import { CheckpointSubTreeOrchestrator } from '../orchestrator/checkpoint-sub-tree-orchestrator.js';
15+
import { ChonkCache } from '../orchestrator/chonk-cache.js';
16+
import { type CheckpointTopTreeData, TopTreeOrchestrator } from '../orchestrator/top-tree-orchestrator.js';
17+
18+
// Regenerates the committed `crates/rollup-*/Prover.toml` sample inputs that CI runs `nargo execute`
19+
// against. The rollup circuits push their serialized inputs via `pushTestData` whenever they run
20+
// through the prover, so driving representative epochs through the (simulated) orchestrator and then
21+
// dumping `getTestData(circuitName)` produces fresh, ABI-current fixtures. Run with:
22+
// AZTEC_GENERATE_TEST_DATA=1 yarn workspace @aztec/prover-client test regenerate_rollup_sample_inputs
23+
// Without that flag the whole suite is skipped, so it is a no-op (no prover setup) in normal CI.
24+
//
25+
// The four scenarios are chosen to exercise each block-root variant the orchestrator selects (see
26+
// BlockProvingState#getBlockRootRollupTypeAndInputs): a first block with 0 txs, with >=2 txs, a
27+
// three-block checkpoint (first block with 1 tx plus a block-merge), and a three-checkpoint epoch
28+
// (for the checkpoint-merge). A merge node only exists above the tree root, so both merges need
29+
// three leaves — two would pair directly at the root. Every scenario also produces the root rollup.
30+
const describeOrSkip = isGenerateTestDataEnabled() ? describe : describe.skip;
31+
32+
describeOrSkip('prover/regenerate-rollup-sample-inputs', () => {
33+
let context: TestContext;
34+
let log: Logger;
35+
36+
interface Scenario {
37+
numCheckpoints: number;
38+
numBlocksPerCheckpoint: number;
39+
numTxsPerBlock: number;
40+
numL1ToL2Messages: number;
41+
/** Circuits whose sample inputs this scenario is responsible for regenerating. */
42+
dump: CircuitName[];
43+
}
44+
45+
const withMessages = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP;
46+
47+
const scenarios: Scenario[] = [
48+
{
49+
numCheckpoints: 1,
50+
numBlocksPerCheckpoint: 1,
51+
numTxsPerBlock: 0,
52+
numL1ToL2Messages: withMessages,
53+
dump: ['rollup-block-root-first-empty-tx'],
54+
},
55+
{
56+
numCheckpoints: 1,
57+
numBlocksPerCheckpoint: 1,
58+
numTxsPerBlock: 2,
59+
numL1ToL2Messages: withMessages,
60+
dump: ['rollup-block-root-first', 'rollup-root'],
61+
},
62+
{
63+
numCheckpoints: 1,
64+
numBlocksPerCheckpoint: 3,
65+
numTxsPerBlock: 1,
66+
numL1ToL2Messages: withMessages,
67+
dump: ['rollup-block-root-first-single-tx', 'rollup-block-merge'],
68+
},
69+
// The checkpoint-merge only appears with three checkpoints. Independently-built checkpoints do
70+
// not carry the inbox message state forward, so this scenario runs with no L1-to-L2 messages and
71+
// a zero previous rolling hash, matching the multi-checkpoint case in top-tree-orchestrator.test.
72+
{
73+
numCheckpoints: 3,
74+
numBlocksPerCheckpoint: 1,
75+
numTxsPerBlock: 1,
76+
numL1ToL2Messages: 0,
77+
dump: ['rollup-checkpoint-merge'],
78+
},
79+
];
80+
81+
beforeEach(async () => {
82+
log = createLogger('prover-client:test:regenerate-rollup-sample-inputs');
83+
context = await TestContext.new(log, { proverCount: 1 });
84+
});
85+
86+
afterEach(async () => {
87+
await context.cleanup();
88+
});
89+
90+
it.each(scenarios)(
91+
'regenerates $dump from an epoch with $numCheckpoints checkpoints, $numBlocksPerCheckpoint blocks, $numTxsPerBlock txs',
92+
async ({ numCheckpoints, numBlocksPerCheckpoint, numTxsPerBlock, numL1ToL2Messages, dump }) => {
93+
const checkpoints = await timesAsync(numCheckpoints, () =>
94+
context.makeCheckpoint(numBlocksPerCheckpoint, {
95+
numTxsPerBlock,
96+
numL1ToL2Messages,
97+
makeProcessedTxOpts: (_, txIndex) => ({ privateOnly: txIndex % 2 === 0 }),
98+
}),
99+
);
100+
101+
const finalBlobChallenges = await context.getFinalBlobChallenges();
102+
const chonkCache = new ChonkCache();
103+
const subTrees: CheckpointSubTreeOrchestrator[] = [];
104+
const topTreeData: CheckpointTopTreeData[] = [];
105+
106+
try {
107+
for (let checkpointIndex = 0; checkpointIndex < numCheckpoints; checkpointIndex++) {
108+
const { constants, blocks, l1ToL2Messages, previousBlockHeader, checkpoint } = checkpoints[checkpointIndex];
109+
110+
// First checkpoint starts from genesis; the multi-checkpoint scenario carries no messages,
111+
// so every checkpoint's previous rolling hash is zero.
112+
const previousInboxRollingHash = Fr.ZERO;
113+
114+
const subTree = await CheckpointSubTreeOrchestrator.start(
115+
context.worldState,
116+
context.prover,
117+
EthAddress.ZERO,
118+
chonkCache,
119+
EpochNumber(1),
120+
/* cancelJobsOnStop */ false,
121+
makeTestDeferredJobQueue(),
122+
constants,
123+
l1ToL2Messages,
124+
previousInboxRollingHash,
125+
numBlocksPerCheckpoint,
126+
previousBlockHeader,
127+
);
128+
subTrees.push(subTree);
129+
130+
for (let i = 0; i < numBlocksPerCheckpoint; i++) {
131+
const { header, txs } = blocks[i];
132+
const { blockNumber, timestamp } = header.globalVariables;
133+
134+
await subTree.startNewBlock(blockNumber, timestamp, txs.length);
135+
if (txs.length > 0) {
136+
await subTree.addTxs(txs);
137+
}
138+
await subTree.setBlockCompleted(blockNumber, header);
139+
}
140+
141+
topTreeData.push({
142+
blockProofs: subTree.getSubTreeResult().then(r => r.blockProofOutputs),
143+
l2ToL1MsgsPerBlock: blocks.map(b => b.txs.map(tx => tx.txEffect.l2ToL1Msgs)),
144+
blobFields: checkpoint.toBlobFields(),
145+
previousBlockHeader,
146+
previousArchiveSiblingPath: subTree.getPreviousArchiveSiblingPath(),
147+
});
148+
}
149+
150+
const topTree = new TopTreeOrchestrator(context.prover, EthAddress.ZERO, makeTestDeferredJobQueue());
151+
try {
152+
await topTree.prove(EpochNumber(1), numCheckpoints, finalBlobChallenges, topTreeData);
153+
} finally {
154+
await topTree.stop();
155+
}
156+
157+
for (const circuitName of dump) {
158+
const data = getTestData(circuitName);
159+
if (!data || data.length === 0) {
160+
throw new Error(`No test data captured for ${circuitName}; scenario does not exercise it.`);
161+
}
162+
updateProtocolCircuitSampleInputs(circuitName, TOML.stringify(data[0] as any));
163+
log.info(`Regenerated sample inputs for ${circuitName}`);
164+
}
165+
} finally {
166+
await Promise.all(subTrees.map(s => s.stop()));
167+
}
168+
},
169+
300_000,
170+
);
171+
});

0 commit comments

Comments
 (0)