Skip to content

Commit 1aa7d2f

Browse files
committed
refactor(fast-inbox): name the checkpoint sub-tree proof bundle for what it holds (A-1427)
The top tree's per-checkpoint `blockProofs` promise stopped holding just block proofs when parity moved to the checkpoint root: it now carries the block-rollup proof outputs plus the checkpoint's InboxParity proof. Rename it to `subTreeProofs`, typed by a single exported `CheckpointSubTreeProofs` in prover-client (dropping the duplicate alias in prover-node), and rename the block-proof-array parameters in the orchestrator so `blockProofOutputs` means the same thing everywhere. `CheckpointProver.whenBlockProofsReady` follows suit.
1 parent 5853876 commit 1aa7d2f

10 files changed

Lines changed: 97 additions & 88 deletions

yarn-project/prover-client/src/orchestrator/checkpoint-sub-tree-orchestrator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ export type SubTreeResult = {
9090
previousArchiveSiblingPath: Tuple<Fr, typeof ARCHIVE_HEIGHT>;
9191
};
9292

93+
/**
94+
* The proofs a checkpoint's sub-tree hands to the top tree: the per-block rollup proofs plus the checkpoint's single
95+
* variable-size InboxParity proof (parity moved from the first block root to the checkpoint root in AZIP-22 Fast Inbox).
96+
*/
97+
export type CheckpointSubTreeProofs = Pick<SubTreeResult, 'blockProofOutputs' | 'inboxParityProof'>;
98+
9399
type TreeSnapshots = Map<MerkleTreeId, AppendOnlyTreeSnapshot>;
94100

95101
/**

yarn-project/prover-client/src/orchestrator/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
export { CheckpointSubTreeOrchestrator, type SubTreeResult } from './checkpoint-sub-tree-orchestrator.js';
1+
export {
2+
CheckpointSubTreeOrchestrator,
3+
type CheckpointSubTreeProofs,
4+
type SubTreeResult,
5+
} from './checkpoint-sub-tree-orchestrator.js';
26
export { ChonkCache, type ChonkVerifierProofResult } from './chonk-cache.js';
37
export {
48
TopTreeOrchestrator,

yarn-project/prover-client/src/orchestrator/top-tree-orchestrator.test.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ describe('prover/orchestrator/top-tree', () => {
8585
await subTree.stop();
8686

8787
const topTreeData: CheckpointTopTreeData = {
88-
blockProofs: Promise.resolve({
88+
subTreeProofs: Promise.resolve({
8989
blockProofOutputs: result.blockProofOutputs,
9090
inboxParityProof: result.inboxParityProof,
9191
}),
@@ -170,9 +170,9 @@ describe('prover/orchestrator/top-tree', () => {
170170
const b = await driveSubTree(1, 1);
171171
const challenges = await context.getFinalBlobChallenges();
172172

173-
// Replace ckpt1's blockProofs with a deferred promise that resolves later.
174-
const deferred = promiseWithResolvers<typeof b.topTreeData.blockProofs extends Promise<infer T> ? T : never>();
175-
const ckpt1 = { ...b.topTreeData, blockProofs: deferred.promise } as CheckpointTopTreeData;
173+
// Replace ckpt1's subTreeProofs with a deferred promise that resolves later.
174+
const deferred = promiseWithResolvers<typeof b.topTreeData.subTreeProofs extends Promise<infer T> ? T : never>();
175+
const ckpt1 = { ...b.topTreeData, subTreeProofs: deferred.promise } as CheckpointTopTreeData;
176176

177177
const topTree = new TopTreeOrchestrator(context.prover, EthAddress.ZERO, makeTestDeferredJobQueue());
178178
try {
@@ -184,7 +184,7 @@ describe('prover/orchestrator/top-tree', () => {
184184
await new Promise(resolve => setTimeout(resolve, 50));
185185

186186
// Now resolve ckpt1 — the orchestrator should pick it up and continue.
187-
deferred.resolve((await b.topTreeData.blockProofs) as any);
187+
deferred.resolve((await b.topTreeData.subTreeProofs) as any);
188188

189189
const result = await provePromise;
190190
expect(result.proof).toBeDefined();
@@ -197,9 +197,9 @@ describe('prover/orchestrator/top-tree', () => {
197197
const { topTreeData } = await driveSubTree(1, 1);
198198
const challenges = await context.getFinalBlobChallenges();
199199

200-
// Block ckpt0's blockProofs forever so prove() can't finish.
201-
const stuck = new Promise<typeof topTreeData.blockProofs extends Promise<infer T> ? T : never>(() => {});
202-
const stuckData = { ...topTreeData, blockProofs: stuck } as CheckpointTopTreeData;
200+
// Block ckpt0's subTreeProofs forever so prove() can't finish.
201+
const stuck = new Promise<typeof topTreeData.subTreeProofs extends Promise<infer T> ? T : never>(() => {});
202+
const stuckData = { ...topTreeData, subTreeProofs: stuck } as CheckpointTopTreeData;
203203

204204
const topTree = new TopTreeOrchestrator(context.prover, EthAddress.ZERO, makeTestDeferredJobQueue());
205205
const provePromise = topTree.prove(EpochNumber(1), 1, challenges, [stuckData]);
@@ -258,7 +258,7 @@ describe('prover/orchestrator/top-tree', () => {
258258
// A malformed block proof makes toProofData (inside buildCheckpointRootInputs) throw.
259259
const badData = {
260260
...topTreeData,
261-
blockProofs: Promise.resolve({ blockProofOutputs: [{} as any], inboxParityProof: {} as any }),
261+
subTreeProofs: Promise.resolve({ blockProofOutputs: [{} as any], inboxParityProof: {} as any }),
262262
} as CheckpointTopTreeData;
263263

264264
const topTree = new TopTreeOrchestrator(context.prover, EthAddress.ZERO, makeTestDeferredJobQueue());
@@ -288,23 +288,23 @@ describe('prover/orchestrator/top-tree', () => {
288288
const { topTreeData } = await driveSubTree(1, 1);
289289
const challenges = await context.getFinalBlobChallenges();
290290

291-
const deferred = promiseWithResolvers<typeof topTreeData.blockProofs extends Promise<infer T> ? T : never>();
292-
// Observe exactly when prove() attaches its blockProofs handler, so we can sequence the
291+
const deferred = promiseWithResolvers<typeof topTreeData.subTreeProofs extends Promise<infer T> ? T : never>();
292+
// Observe exactly when prove() attaches its subTreeProofs handler, so we can sequence the
293293
// genuine rejection and the cancel deterministically rather than racing a fixed timeout.
294294
let handlerAttached = false;
295-
const observableBlockProofs = {
295+
const observableSubTreeProofs = {
296296
then: (onF: any, onR: any) => {
297297
handlerAttached = true;
298298
return deferred.promise.then(onF, onR);
299299
},
300300
};
301-
const failingData = { ...topTreeData, blockProofs: observableBlockProofs as any } as CheckpointTopTreeData;
301+
const failingData = { ...topTreeData, subTreeProofs: observableSubTreeProofs as any } as CheckpointTopTreeData;
302302

303303
const topTree = new TopTreeOrchestrator(context.prover, EthAddress.ZERO, makeTestDeferredJobQueue());
304304
const provePromise = topTree.prove(EpochNumber(1), 1, challenges, [failingData]);
305305

306-
// Wait until prove() has finished its pre-loop setup and registered the blockProofs handler.
307-
await retryUntil(() => handlerAttached, 'prove() attaches blockProofs handler', 5, 0.005);
306+
// Wait until prove() has finished its pre-loop setup and registered the subTreeProofs handler.
307+
await retryUntil(() => handlerAttached, 'prove() attaches subTreeProofs handler', 5, 0.005);
308308

309309
// Register a cancel reaction on the rejection, after prove()'s own handler (registered
310310
// first, so it runs first). On rejection the ordering is: prove's handler rejects the

yarn-project/prover-client/src/orchestrator/top-tree-orchestrator.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,19 @@ import type { BlockHeader } from '@aztec/stdlib/tx';
3333
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
3434

3535
import { buildBlobHints, toProofData } from './block-building-helpers.js';
36+
import type { CheckpointSubTreeProofs } from './checkpoint-sub-tree-orchestrator.js';
3637
import { ProvingScheduler } from './proving-scheduler.js';
3738
import { TopTreeProvingState } from './top-tree-proving-state.js';
3839

3940
/** Per-checkpoint data fed into the top tree. */
4041
export type CheckpointTopTreeData = {
4142
/**
42-
* Block-rollup proof outputs and the parity root proof from the checkpoint's sub-tree. Passed as a Promise so the
43-
* top tree can start (compute hints, pipeline merges) while sub-trees are still proving. `blockProofOutputs`
44-
* resolves to 1 entry for a single-block checkpoint, 2 for multi-block. The parity root proof feeds the checkpoint
45-
* root rollup (parity moved there from the first block root in AZIP-22 Fast Inbox).
43+
* The checkpoint sub-tree's proofs. Passed as a Promise so the top tree can start (compute hints, pipeline merges)
44+
* while sub-trees are still proving. `blockProofOutputs` resolves to 1 entry for a single-block checkpoint, 2 for
45+
* multi-block; `inboxParityProof` feeds the checkpoint root rollup (parity moved there from the first block root in
46+
* AZIP-22 Fast Inbox).
4647
*/
47-
blockProofs: Promise<{
48-
blockProofOutputs: PublicInputsAndRecursiveProof<
49-
BlockRollupPublicInputs,
50-
typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
51-
>[];
52-
inboxParityProof: PublicInputsAndRecursiveProof<ParityPublicInputs>;
53-
}>;
48+
subTreeProofs: Promise<CheckpointSubTreeProofs>;
5449
/** L2-to-L1 messages per block in the checkpoint, used to compute the out hash. */
5550
l2ToL1MsgsPerBlock: Fr[][][];
5651
/** Blob fields encoding the checkpoint's tx effects, used to compute the blob accumulator. */
@@ -90,7 +85,7 @@ type OutHashHint = {
9085
*
9186
* Pipelined start: `prove()` does not wait for block-level proving. It pre-computes the
9287
* out-hash and blob-accumulator hint chains immediately from archiver-derivable data,
93-
* and each checkpoint's root rollup fires the moment its sub-tree's `blockProofs`
88+
* and each checkpoint's root rollup fires the moment its sub-tree's `subTreeProofs`
9489
* promise resolves. Later checkpoints can still be block-level proving in parallel.
9590
*/
9691
export class TopTreeOrchestrator extends ProvingScheduler {
@@ -172,7 +167,7 @@ export class TopTreeOrchestrator extends ProvingScheduler {
172167
for (let i = 0; i < checkpointData.length; i++) {
173168
const cd = checkpointData[i];
174169
const checkpointIndex = i;
175-
void cd.blockProofs.then(
170+
void cd.subTreeProofs.then(
176171
subTreeProofs => {
177172
if (this.cancelled || !this.state?.verifyState()) {
178173
return;
@@ -227,7 +222,7 @@ export class TopTreeOrchestrator extends ProvingScheduler {
227222
private enqueueCheckpointRoot(
228223
state: TopTreeProvingState,
229224
checkpointIndex: number,
230-
blockProofs: PublicInputsAndRecursiveProof<
225+
blockProofOutputs: PublicInputsAndRecursiveProof<
231226
BlockRollupPublicInputs,
232227
typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
233228
>[],
@@ -236,7 +231,13 @@ export class TopTreeOrchestrator extends ProvingScheduler {
236231
outHashHint: OutHashHint,
237232
startBlobAccumulator: BatchedBlobAccumulator,
238233
) {
239-
void this.buildCheckpointRootInputs(blockProofs, inboxParityProof, cd, outHashHint, startBlobAccumulator).then(
234+
void this.buildCheckpointRootInputs(
235+
blockProofOutputs,
236+
inboxParityProof,
237+
cd,
238+
outHashHint,
239+
startBlobAccumulator,
240+
).then(
240241
inputs => {
241242
this.deferredProving(
242243
state,
@@ -269,7 +270,7 @@ export class TopTreeOrchestrator extends ProvingScheduler {
269270
}
270271

271272
private async buildCheckpointRootInputs(
272-
blockProofs: PublicInputsAndRecursiveProof<
273+
blockProofOutputs: PublicInputsAndRecursiveProof<
273274
BlockRollupPublicInputs,
274275
typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
275276
>[],
@@ -293,7 +294,7 @@ export class TopTreeOrchestrator extends ProvingScheduler {
293294
});
294295

295296
const inboxParity = toProofData(inboxParityProof);
296-
const proofDatas = blockProofs.map(p => toProofData(p));
297+
const proofDatas = blockProofOutputs.map(p => toProofData(p));
297298
return proofDatas.length === 1
298299
? new CheckpointRootSingleBlockRollupPrivateInputs(proofDatas[0], inboxParity, hints)
299300
: new CheckpointRootRollupPrivateInputs([proofDatas[0], proofDatas[1]], inboxParity, hints);

yarn-project/prover-client/src/test/bb_prover_full_rollup.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ describe('prover/bb_prover/full-rollup', () => {
103103
}
104104

105105
topTreeData.push({
106-
blockProofs: subTree
106+
subTreeProofs: subTree
107107
.getSubTreeResult()
108108
.then(r => ({ blockProofOutputs: r.blockProofOutputs, inboxParityProof: r.inboxParityProof })),
109109
l2ToL1MsgsPerBlock: blocks.map(b => b.txs.map(tx => tx.txEffect.l2ToL1Msgs)),

yarn-project/prover-client/src/test/regenerate_rollup_sample_inputs.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ describeOrSkip('prover/regenerate-rollup-sample-inputs', () => {
154154
}
155155

156156
topTreeData.push({
157-
blockProofs: subTree
157+
subTreeProofs: subTree
158158
.getSubTreeResult()
159159
.then(r => ({ blockProofOutputs: r.blockProofOutputs, inboxParityProof: r.inboxParityProof })),
160160
l2ToL1MsgsPerBlock: blocks.map(b => b.txs.map(tx => tx.txEffect.l2ToL1Msgs)),

yarn-project/prover-node/src/job/checkpoint-prover.test.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,11 @@ describe('CheckpointProver', () => {
156156
await prover.whenDone();
157157
});
158158

159-
it('rejects whenBlockProofsReady()', async () => {
159+
it('rejects whenSubTreeProofsReady()', async () => {
160160
const prover = makeProver();
161-
const blockProofs = prover.whenBlockProofsReady();
161+
const subTreeProofs = prover.whenSubTreeProofsReady();
162162
prover.cancel();
163-
await expect(blockProofs).rejects.toThrow(/cancelled/);
163+
await expect(subTreeProofs).rejects.toThrow(/cancelled/);
164164
await prover.whenDone();
165165
});
166166

@@ -179,19 +179,19 @@ describe('CheckpointProver', () => {
179179

180180
it('routine cancel still aborts and rejects block proofs (only log level differs)', async () => {
181181
const prover = makeProver();
182-
const blockProofs = prover.whenBlockProofsReady();
182+
const subTreeProofs = prover.whenSubTreeProofsReady();
183183
prover.cancel({ routine: true });
184184
expect(prover.isCancelled()).toBe(true);
185185
expect(prover.getAbortSignal().aborted).toBe(true);
186-
await expect(blockProofs).rejects.toThrow(/cancelled/);
186+
await expect(subTreeProofs).rejects.toThrow(/cancelled/);
187187
await prover.whenDone();
188188
});
189189
});
190190

191191
// ---------------- gather failure ----------------
192192

193193
describe('gather failures', () => {
194-
it('rejects whenBlockProofsReady when txProvider returns missing txs', async () => {
194+
it('rejects whenSubTreeProofsReady when txProvider returns missing txs', async () => {
195195
const missingHash = checkpoint.blocks[0].body.txEffects[0]?.txHash;
196196
// Without a real missing hash the per-block payload would be empty and the prover
197197
// would happily proceed; only checkpoints with txs can exercise this branch.
@@ -202,7 +202,7 @@ describe('CheckpointProver', () => {
202202
txProvider.getTxsForBlock.mockResolvedValue({ txs: [], missingTxs: [missingHash] });
203203

204204
const prover = makeProver();
205-
await expect(prover.whenBlockProofsReady()).rejects.toThrow(/Txs not found/);
205+
await expect(prover.whenSubTreeProofsReady()).rejects.toThrow(/Txs not found/);
206206
await prover.whenDone();
207207
});
208208

@@ -215,19 +215,19 @@ describe('CheckpointProver', () => {
215215
txProvider.getTxsForBlock.mockReturnValue(gate.promise);
216216

217217
const prover = makeProver();
218-
const blockProofs = prover.whenBlockProofsReady();
218+
const subTreeProofs = prover.whenSubTreeProofsReady();
219219
prover.cancel();
220220
gate.reject(new Error('gather aborted by test'));
221-
await expect(blockProofs).rejects.toThrow(/cancelled/);
221+
await expect(subTreeProofs).rejects.toThrow(/cancelled/);
222222
await expect(prover.whenDone()).resolves.toBeUndefined();
223223
});
224224

225-
it('lets a second whenBlockProofsReady caller observe the same rejection', async () => {
225+
it('lets a second whenSubTreeProofsReady caller observe the same rejection', async () => {
226226
// Two callers awaiting the same promise both see the rejection — neither leaks an
227227
// unhandled rejection (the constructor pre-attaches a noop catch handler).
228228
const prover = makeProver();
229-
const a = prover.whenBlockProofsReady();
230-
const b = prover.whenBlockProofsReady();
229+
const a = prover.whenSubTreeProofsReady();
230+
const b = prover.whenSubTreeProofsReady();
231231
prover.cancel();
232232
await Promise.all([expect(a).rejects.toThrow(/cancelled/), expect(b).rejects.toThrow(/cancelled/)]);
233233
await prover.whenDone();
@@ -244,7 +244,7 @@ describe('CheckpointProver', () => {
244244

245245
const prover = makeProver();
246246
failure.resolve({ txs: [], missingTxs: [missingHash] });
247-
await expect(prover.whenBlockProofsReady()).rejects.toThrow(/Txs not found/);
247+
await expect(prover.whenSubTreeProofsReady()).rejects.toThrow(/Txs not found/);
248248
// Subsequent cancel is a no-op; no throws.
249249
prover.cancel();
250250
expect(prover.isCancelled()).toBe(true);

0 commit comments

Comments
 (0)