@aztec/prover-client 1.0.0-nightly.20250607 → 1.0.0-nightly.20250610

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dest/block-factory/light.d.ts.map +1 -1
  2. package/dest/block-factory/light.js +2 -1
  3. package/dest/mocks/test_context.d.ts +1 -0
  4. package/dest/mocks/test_context.d.ts.map +1 -1
  5. package/dest/mocks/test_context.js +3 -0
  6. package/dest/orchestrator/block-building-helpers.d.ts +7 -7
  7. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  8. package/dest/orchestrator/block-building-helpers.js +36 -24
  9. package/dest/orchestrator/block-proving-state.d.ts +10 -2
  10. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  11. package/dest/orchestrator/block-proving-state.js +55 -18
  12. package/dest/orchestrator/epoch-proving-state.d.ts +9 -3
  13. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  14. package/dest/orchestrator/epoch-proving-state.js +33 -8
  15. package/dest/orchestrator/orchestrator.d.ts +3 -1
  16. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  17. package/dest/orchestrator/orchestrator.js +30 -10
  18. package/dest/prover-client/prover-client.d.ts +1 -1
  19. package/dest/prover-client/prover-client.d.ts.map +1 -1
  20. package/dest/prover-client/prover-client.js +2 -0
  21. package/dest/prover-client/server-epoch-prover.d.ts +3 -1
  22. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
  23. package/dest/prover-client/server-epoch-prover.js +2 -2
  24. package/package.json +15 -15
  25. package/src/block-factory/light.ts +2 -1
  26. package/src/mocks/test_context.ts +4 -0
  27. package/src/orchestrator/block-building-helpers.ts +42 -27
  28. package/src/orchestrator/block-proving-state.ts +69 -14
  29. package/src/orchestrator/epoch-proving-state.ts +34 -4
  30. package/src/orchestrator/orchestrator.ts +62 -11
  31. package/src/prover-client/prover-client.ts +11 -9
  32. package/src/prover-client/server-epoch-prover.ts +9 -3
@@ -1,4 +1,4 @@
1
- import { SpongeBlob } from '@aztec/blob-lib';
1
+ import { BatchedBlobAccumulator, SpongeBlob } from '@aztec/blob-lib';
2
2
  import {
3
3
  type ARCHIVE_HEIGHT,
4
4
  BLOBS_PER_BLOCK,
@@ -9,7 +9,7 @@ import {
9
9
  type RECURSIVE_PROOF_LENGTH,
10
10
  } from '@aztec/constants';
11
11
  import { padArrayEnd } from '@aztec/foundation/collection';
12
- import { Fr } from '@aztec/foundation/fields';
12
+ import { BLS12Point, Fr } from '@aztec/foundation/fields';
13
13
  import type { Tuple } from '@aztec/foundation/serialize';
14
14
  import { type TreeNodeLocation, UnbalancedTreeStore } from '@aztec/foundation/trees';
15
15
  import { getVKIndex, getVKSiblingPath, getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
@@ -19,11 +19,11 @@ import type { PublicInputsAndRecursiveProof } from '@aztec/stdlib/interfaces/ser
19
19
  import { type ParityPublicInputs, RootParityInput, RootParityInputs } from '@aztec/stdlib/parity';
20
20
  import {
21
21
  type BaseOrMergeRollupPublicInputs,
22
+ BlockConstantData,
22
23
  type BlockRootOrBlockMergePublicInputs,
23
24
  BlockRootRollupBlobData,
24
25
  BlockRootRollupData,
25
26
  BlockRootRollupInputs,
26
- ConstantRollupData,
27
27
  EmptyBlockRootRollupInputs,
28
28
  MergeRollupInputs,
29
29
  PreviousRollupData,
@@ -34,7 +34,7 @@ import type { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
34
34
  import { type BlockHeader, type GlobalVariables, StateReference } from '@aztec/stdlib/tx';
35
35
  import { VkData } from '@aztec/stdlib/vks';
36
36
 
37
- import { buildBlobHints, buildHeaderFromCircuitOutputs } from './block-building-helpers.js';
37
+ import { accumulateBlobs, buildBlobHints, buildHeaderFromCircuitOutputs } from './block-building-helpers.js';
38
38
  import type { EpochProvingState } from './epoch-proving-state.js';
39
39
  import type { TxProvingState } from './tx-proving-state.js';
40
40
 
@@ -56,6 +56,9 @@ export class BlockProvingState {
56
56
  public blockRootRollupStarted: boolean = false;
57
57
  public block: L2Block | undefined;
58
58
  public spongeBlobState: SpongeBlob | undefined;
59
+ public startBlobAccumulator: BatchedBlobAccumulator | undefined;
60
+ public endBlobAccumulator: BatchedBlobAccumulator | undefined;
61
+ public blobsHash: Buffer | undefined;
59
62
  public totalNumTxs: number;
60
63
  private txs: TxProvingState[] = [];
61
64
  public error: string | undefined;
@@ -64,6 +67,7 @@ export class BlockProvingState {
64
67
  public readonly index: number,
65
68
  public readonly globalVariables: GlobalVariables,
66
69
  public readonly newL1ToL2Messages: Fr[],
70
+ public readonly l1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot,
67
71
  private readonly l1ToL2MessageSubtreeSiblingPath: Tuple<Fr, typeof L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH>,
68
72
  private readonly l1ToL2MessageTreeSnapshotAfterInsertion: AppendOnlyTreeSnapshot,
69
73
  private readonly lastArchiveSnapshot: AppendOnlyTreeSnapshot,
@@ -74,6 +78,9 @@ export class BlockProvingState {
74
78
  ) {
75
79
  this.baseParityProvingOutputs = Array.from({ length: NUM_BASE_PARITY_PER_ROOT_PARITY }).map(_ => undefined);
76
80
  this.totalNumTxs = 0;
81
+ if (this.blockNumber == parentEpoch.firstBlockNumber) {
82
+ this.startBlobAccumulator = BatchedBlobAccumulator.newWithChallenges(parentEpoch.finalBlobBatchingChallenges);
83
+ }
77
84
  }
78
85
 
79
86
  public get blockNumber() {
@@ -97,7 +104,6 @@ export class BlockProvingState {
97
104
  if (!this.spongeBlobState) {
98
105
  throw new Error(`Invalid block proving state, call startNewBlock before adding transactions.`);
99
106
  }
100
-
101
107
  const txIndex = this.txs.length;
102
108
  this.txs[txIndex] = tx;
103
109
  return txIndex;
@@ -146,6 +152,30 @@ export class BlockProvingState {
146
152
  this.blockRootProvingOutput = provingOutput;
147
153
  }
148
154
 
155
+ public setBlock(block: L2Block) {
156
+ this.block = block;
157
+ }
158
+
159
+ public setStartBlobAccumulator(accumulator: BatchedBlobAccumulator) {
160
+ this.startBlobAccumulator = accumulator;
161
+ }
162
+
163
+ public setEndBlobAccumulator(accumulator: BatchedBlobAccumulator) {
164
+ this.endBlobAccumulator = accumulator;
165
+ }
166
+
167
+ public async accumulateBlobs() {
168
+ if (!this.block || !this.startBlobAccumulator) {
169
+ // We only want to accumulate once we have all txs, so we wait until the block is set.
170
+ return;
171
+ }
172
+ const endBlobAccumulator = await accumulateBlobs(
173
+ this.allTxs.map(t => t.processedTx),
174
+ this.startBlobAccumulator,
175
+ );
176
+ this.setEndBlobAccumulator(endBlobAccumulator);
177
+ }
178
+
149
179
  // Returns the complete set of transaction proving state objects
150
180
  public get allTxs() {
151
181
  return this.txs;
@@ -183,8 +213,9 @@ export class BlockProvingState {
183
213
  const data = this.#getBlockRootRollupData(proverId);
184
214
 
185
215
  if (this.totalNumTxs === 0) {
186
- const constants = ConstantRollupData.from({
216
+ const constants = BlockConstantData.from({
187
217
  lastArchive: this.lastArchiveSnapshot,
218
+ lastL1ToL2: this.l1ToL2MessageTreeSnapshot,
188
219
  globalVariables: this.globalVariables,
189
220
  vkTreeRoot: getVKTreeRoot(),
190
221
  protocolContractTreeRoot,
@@ -202,6 +233,7 @@ export class BlockProvingState {
202
233
 
203
234
  const previousRollupData = await Promise.all(nonEmptyProofs.map(p => this.#getPreviousRollupData(p!)));
204
235
  const blobData = await this.#getBlockRootRollupBlobData();
236
+ this.blobsHash = blobData.blobsHash.toBuffer();
205
237
 
206
238
  if (previousRollupData.length === 1) {
207
239
  return {
@@ -225,21 +257,29 @@ export class BlockProvingState {
225
257
  throw new Error('Root parity is not ready.');
226
258
  }
227
259
 
228
- // Use the new block header and archive of the current block as the previous header and archiver of the next padding block.
229
- const newBlockHeader = await this.buildHeaderFromProvingOutputs();
230
- const newArchive = this.blockRootProvingOutput!.inputs.newArchive;
260
+ if (!this.blockRootProvingOutput || !this.endBlobAccumulator) {
261
+ throw new Error('Block root not ready for padding.');
262
+ }
263
+
264
+ // Use the new block header, archive and l1toL2 of the current block as the previous header, archive and l1toL2 of the next padding block.
265
+ const previousBlockHeader = await this.buildHeaderFromProvingOutputs();
266
+ const lastArchive = this.blockRootProvingOutput!.inputs.newArchive;
267
+ const lastL1ToL2 = this.l1ToL2MessageTreeSnapshotAfterInsertion;
231
268
 
232
269
  const data = BlockRootRollupData.from({
233
270
  l1ToL2Roots: this.#getRootParityData(this.rootParityProvingOutput!),
234
271
  l1ToL2MessageSubtreeSiblingPath: this.l1ToL2MessageSubtreeSiblingPath,
235
272
  previousArchiveSiblingPath: this.lastArchiveSiblingPath,
236
273
  newArchiveSiblingPath: this.newArchiveSiblingPath,
237
- previousBlockHeader: newBlockHeader,
274
+ previousBlockHeader,
275
+ startBlobAccumulator: this.endBlobAccumulator.toBlobAccumulatorPublicInputs(),
276
+ finalBlobChallenges: this.endBlobAccumulator.finalBlobChallenges,
238
277
  proverId,
239
278
  });
240
279
 
241
- const constants = ConstantRollupData.from({
242
- lastArchive: newArchive,
280
+ const constants = BlockConstantData.from({
281
+ lastArchive,
282
+ lastL1ToL2,
243
283
  globalVariables: this.globalVariables,
244
284
  vkTreeRoot: getVKTreeRoot(),
245
285
  protocolContractTreeRoot,
@@ -285,10 +325,18 @@ export class BlockProvingState {
285
325
  }
286
326
  const endState = new StateReference(this.l1ToL2MessageTreeSnapshotAfterInsertion, endPartialState);
287
327
 
328
+ // TODO(MW): cleanup
329
+ if (!this.blobsHash) {
330
+ this.blobsHash = (
331
+ await buildBlobHints(this.txs.map(txProvingState => txProvingState.processedTx.txEffect))
332
+ ).blobsHash.toBuffer();
333
+ }
334
+
288
335
  return buildHeaderFromCircuitOutputs(
289
336
  previousRollupData.map(d => d.baseOrMergeRollupPublicInputs),
290
337
  this.rootParityProvingOutput!.inputs,
291
338
  this.blockRootProvingOutput!.inputs,
339
+ this.blobsHash,
292
340
  endState,
293
341
  );
294
342
  }
@@ -300,7 +348,12 @@ export class BlockProvingState {
300
348
  // Returns true if we have sufficient inputs to execute the block root rollup
301
349
  public isReadyForBlockRootRollup() {
302
350
  const childProofs = this.#getChildProofsForBlockRoot();
303
- return this.block !== undefined && this.rootParityProvingOutput !== undefined && childProofs.every(p => !!p);
351
+ return (
352
+ this.block !== undefined &&
353
+ this.rootParityProvingOutput !== undefined &&
354
+ this.endBlobAccumulator !== undefined &&
355
+ childProofs.every(p => !!p)
356
+ );
304
357
  }
305
358
 
306
359
  // Returns true if we have sufficient root parity inputs to execute the root parity circuit
@@ -329,6 +382,8 @@ export class BlockProvingState {
329
382
  previousArchiveSiblingPath: this.lastArchiveSiblingPath,
330
383
  newArchiveSiblingPath: this.newArchiveSiblingPath,
331
384
  previousBlockHeader: this.previousBlockHeader,
385
+ startBlobAccumulator: this.startBlobAccumulator!.toBlobAccumulatorPublicInputs(),
386
+ finalBlobChallenges: this.startBlobAccumulator!.finalBlobChallenges,
332
387
  proverId,
333
388
  });
334
389
  }
@@ -338,7 +393,7 @@ export class BlockProvingState {
338
393
  const { blobFields, blobCommitments, blobsHash } = await buildBlobHints(txEffects);
339
394
  return BlockRootRollupBlobData.from({
340
395
  blobFields: padArrayEnd(blobFields, Fr.ZERO, FIELDS_PER_BLOB * BLOBS_PER_BLOCK),
341
- blobCommitments: padArrayEnd(blobCommitments, [Fr.ZERO, Fr.ZERO], BLOBS_PER_BLOCK),
396
+ blobCommitments: padArrayEnd(blobCommitments, BLS12Point.ZERO, BLOBS_PER_BLOCK),
342
397
  blobsHash,
343
398
  });
344
399
  }
@@ -1,3 +1,4 @@
1
+ import { BatchedBlob, type FinalBlobBatchingChallenges } from '@aztec/blob-lib';
1
2
  import type {
2
3
  ARCHIVE_HEIGHT,
3
4
  L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH,
@@ -48,6 +49,7 @@ export class EpochProvingState {
48
49
  | PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>
49
50
  | undefined;
50
51
  private rootRollupProvingOutput: PublicInputsAndRecursiveProof<RootRollupPublicInputs> | undefined;
52
+ private finalBatchedBlob: BatchedBlob | undefined;
51
53
  private provingStateLifecycle = PROVING_STATE_LIFECYCLE.PROVING_STATE_CREATED;
52
54
 
53
55
  // Map from tx hash to tube proof promise. Used when kickstarting tube proofs before tx processing.
@@ -59,6 +61,7 @@ export class EpochProvingState {
59
61
  public readonly epochNumber: number,
60
62
  public readonly firstBlockNumber: number,
61
63
  public readonly totalNumBlocks: number,
64
+ public readonly finalBlobBatchingChallenges: FinalBlobBatchingChallenges,
62
65
  private completionCallback: (result: ProvingResult) => void,
63
66
  private rejectionCallback: (reason: string) => void,
64
67
  ) {
@@ -70,6 +73,7 @@ export class EpochProvingState {
70
73
  public startNewBlock(
71
74
  globalVariables: GlobalVariables,
72
75
  l1ToL2Messages: Fr[],
76
+ l1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot,
73
77
  l1ToL2MessageSubtreeSiblingPath: Tuple<Fr, typeof L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH>,
74
78
  l1ToL2MessageTreeSnapshotAfterInsertion: AppendOnlyTreeSnapshot,
75
79
  lastArchiveSnapshot: AppendOnlyTreeSnapshot,
@@ -82,6 +86,7 @@ export class EpochProvingState {
82
86
  index,
83
87
  globalVariables,
84
88
  l1ToL2Messages,
89
+ l1ToL2MessageTreeSnapshot,
85
90
  l1ToL2MessageSubtreeSiblingPath,
86
91
  l1ToL2MessageTreeSnapshotAfterInsertion,
87
92
  lastArchiveSnapshot,
@@ -143,6 +148,31 @@ export class EpochProvingState {
143
148
  this.paddingBlockRootProvingOutput = proof;
144
149
  }
145
150
 
151
+ public setFinalBatchedBlob(batchedBlob: BatchedBlob) {
152
+ this.finalBatchedBlob = batchedBlob;
153
+ }
154
+
155
+ public async setBlobAccumulators(toBlock?: number) {
156
+ let previousAccumulator;
157
+ const end = toBlock ? toBlock - this.firstBlockNumber : this.blocks.length;
158
+ // Accumulate blobs as far as we can for this epoch.
159
+ for (let i = 0; i <= end; i++) {
160
+ const block = this.blocks[i];
161
+ if (!block || !block.block) {
162
+ // If the block proving state does not have a .block property, it may be awaiting more txs.
163
+ break;
164
+ }
165
+ if (!block.startBlobAccumulator) {
166
+ // startBlobAccumulator always exists for firstBlockNumber, so the below should never assign an undefined:
167
+ block.setStartBlobAccumulator(previousAccumulator!);
168
+ }
169
+ if (block.startBlobAccumulator && !block.endBlobAccumulator) {
170
+ await block.accumulateBlobs();
171
+ }
172
+ previousAccumulator = block.endBlobAccumulator;
173
+ }
174
+ }
175
+
146
176
  public getParentLocation(location: TreeNodeLocation) {
147
177
  return this.blockRootOrMergeProvingOutputs.getParentLocation(location);
148
178
  }
@@ -156,7 +186,7 @@ export class EpochProvingState {
156
186
  return new BlockMergeRollupInputs([this.#getPreviousRollupData(left), this.#getPreviousRollupData(right)]);
157
187
  }
158
188
 
159
- public getRootRollupInputs(proverId: Fr) {
189
+ public getRootRollupInputs() {
160
190
  const [left, right] = this.#getChildProofsForRoot();
161
191
  if (!left || !right) {
162
192
  throw new Error('At lease one child is not ready.');
@@ -164,7 +194,6 @@ export class EpochProvingState {
164
194
 
165
195
  return RootRollupInputs.from({
166
196
  previousRollupData: [this.#getPreviousRollupData(left), this.#getPreviousRollupData(right)],
167
- proverId,
168
197
  });
169
198
  }
170
199
 
@@ -181,14 +210,15 @@ export class EpochProvingState {
181
210
  return this.blocks.find(block => block?.blockNumber === blockNumber);
182
211
  }
183
212
 
184
- public getEpochProofResult(): { proof: Proof; publicInputs: RootRollupPublicInputs } {
185
- if (!this.rootRollupProvingOutput) {
213
+ public getEpochProofResult(): { proof: Proof; publicInputs: RootRollupPublicInputs; batchedBlobInputs: BatchedBlob } {
214
+ if (!this.rootRollupProvingOutput || !this.finalBatchedBlob) {
186
215
  throw new Error('Unable to get epoch proof result. Root rollup is not ready.');
187
216
  }
188
217
 
189
218
  return {
190
219
  proof: this.rootRollupProvingOutput.proof.binaryProof,
191
220
  publicInputs: this.rootRollupProvingOutput.inputs,
221
+ batchedBlobInputs: this.finalBatchedBlob,
192
222
  };
193
223
  }
194
224
 
@@ -1,3 +1,4 @@
1
+ import { FinalBlobBatchingChallenges } from '@aztec/blob-lib';
1
2
  import {
2
3
  L1_TO_L2_MSG_SUBTREE_HEIGHT,
3
4
  L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH,
@@ -107,14 +108,26 @@ export class ProvingOrchestrator implements EpochProver {
107
108
  return Promise.resolve();
108
109
  }
109
110
 
110
- public startNewEpoch(epochNumber: number, firstBlockNumber: number, totalNumBlocks: number) {
111
+ public startNewEpoch(
112
+ epochNumber: number,
113
+ firstBlockNumber: number,
114
+ totalNumBlocks: number,
115
+ finalBlobBatchingChallenges: FinalBlobBatchingChallenges,
116
+ ) {
111
117
  const { promise: _promise, resolve, reject } = promiseWithResolvers<ProvingResult>();
112
118
  const promise = _promise.catch((reason): ProvingResult => ({ status: 'failure', reason }));
113
119
  if (totalNumBlocks <= 0 || !Number.isInteger(totalNumBlocks)) {
114
120
  throw new Error(`Invalid number of blocks for epoch (got ${totalNumBlocks})`);
115
121
  }
116
122
  logger.info(`Starting epoch ${epochNumber} with ${totalNumBlocks} blocks`);
117
- this.provingState = new EpochProvingState(epochNumber, firstBlockNumber, totalNumBlocks, resolve, reject);
123
+ this.provingState = new EpochProvingState(
124
+ epochNumber,
125
+ firstBlockNumber,
126
+ totalNumBlocks,
127
+ finalBlobBatchingChallenges,
128
+ resolve,
129
+ reject,
130
+ );
118
131
  this.provingPromise = promise;
119
132
  }
120
133
 
@@ -145,8 +158,12 @@ export class ProvingOrchestrator implements EpochProver {
145
158
  this.dbs.set(globalVariables.blockNumber.toNumber(), db);
146
159
 
147
160
  // we start the block by enqueueing all of the base parity circuits
148
- const { l1ToL2MessageSubtreeSiblingPath, l1ToL2MessageTreeSnapshotAfterInsertion, baseParityInputs } =
149
- await this.prepareBaseParityInputs(l1ToL2Messages, db);
161
+ const {
162
+ l1ToL2MessageTreeSnapshot,
163
+ l1ToL2MessageSubtreeSiblingPath,
164
+ l1ToL2MessageTreeSnapshotAfterInsertion,
165
+ baseParityInputs,
166
+ } = await this.prepareBaseParityInputs(l1ToL2Messages, db);
150
167
 
151
168
  // Get archive snapshot before this block lands
152
169
  const lastArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
@@ -156,6 +173,7 @@ export class ProvingOrchestrator implements EpochProver {
156
173
  const blockProvingState = this.provingState!.startNewBlock(
157
174
  globalVariables,
158
175
  l1ToL2Messages,
176
+ l1ToL2MessageTreeSnapshot,
159
177
  l1ToL2MessageSubtreeSiblingPath,
160
178
  l1ToL2MessageTreeSnapshotAfterInsertion,
161
179
  lastArchive,
@@ -184,7 +202,7 @@ export class ProvingOrchestrator implements EpochProver {
184
202
  logger.warn(`Provided no txs to orchestrator addTxs.`);
185
203
  return;
186
204
  }
187
- const blockNumber = txs[0].constants.globalVariables.blockNumber.toNumber();
205
+ const blockNumber = txs[0].globalVariables.blockNumber.toNumber();
188
206
  const provingState = this.provingState?.getBlockProvingStateByBlockNumber(blockNumber!);
189
207
  if (!provingState) {
190
208
  throw new Error(`Block proving state for ${blockNumber} not found`);
@@ -272,6 +290,9 @@ export class ProvingOrchestrator implements EpochProver {
272
290
  logger.verbose(`Block ${blockNumber} completed. Assembling header.`);
273
291
  await this.buildBlock(provingState, expectedHeader);
274
292
 
293
+ logger.debug(`Accumulating blobs for ${blockNumber}`);
294
+ await this.provingState?.setBlobAccumulators(blockNumber);
295
+
275
296
  // If the proofs were faster than the block building, then we need to try the block root rollup again here
276
297
  await this.checkAndEnqueueBlockRootRollup(provingState);
277
298
  return provingState.block!;
@@ -319,7 +340,7 @@ export class ProvingOrchestrator implements EpochProver {
319
340
  await this.verifyBuiltBlockAgainstSyncedState(l2Block, newArchive);
320
341
 
321
342
  logger.verbose(`Orchestrator finalised block ${l2Block.number}`);
322
- provingState.block = l2Block;
343
+ provingState.setBlock(l2Block);
323
344
  }
324
345
 
325
346
  // Flagged as protected to disable in certain unit tests
@@ -358,6 +379,15 @@ export class ProvingOrchestrator implements EpochProver {
358
379
  throw new Error(`Epoch proving failed: ${result.reason}`);
359
380
  }
360
381
 
382
+ // TODO(MW): Move this? Requires async and don't want to force root methods to be async
383
+ // TODO(MW): EpochProvingState uses this.blocks.filter(b => !!b).length as total blocks, use this below:
384
+ const finalBlock = this.provingState.blocks[this.provingState.totalNumBlocks - 1];
385
+ if (!finalBlock || !finalBlock.endBlobAccumulator) {
386
+ throw new Error(`Epoch's final block not ready for finalise`);
387
+ }
388
+ const finalBatchedBlob = await finalBlock.endBlobAccumulator.finalize();
389
+ this.provingState.setFinalBatchedBlob(finalBatchedBlob);
390
+
361
391
  const epochProofResult = this.provingState.getEpochProofResult();
362
392
 
363
393
  pushTestData('epochProofResult', {
@@ -455,6 +485,8 @@ export class ProvingOrchestrator implements EpochProver {
455
485
  BaseParityInputs.fromSlice(l1ToL2MessagesPadded, i, getVKTreeRoot()),
456
486
  );
457
487
 
488
+ const l1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
489
+
458
490
  const l1ToL2MessageSubtreeSiblingPath = assertLength(
459
491
  await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db),
460
492
  L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH,
@@ -465,6 +497,7 @@ export class ProvingOrchestrator implements EpochProver {
465
497
  const l1ToL2MessageTreeSnapshotAfterInsertion = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
466
498
 
467
499
  return {
500
+ l1ToL2MessageTreeSnapshot,
468
501
  l1ToL2MessageSubtreeSiblingPath,
469
502
  l1ToL2MessageTreeSnapshotAfterInsertion,
470
503
  baseParityInputs,
@@ -489,7 +522,13 @@ export class ProvingOrchestrator implements EpochProver {
489
522
  // We build the base rollup inputs using a mock proof and verification key.
490
523
  // These will be overwritten later once we have proven the tube circuit and any public kernels
491
524
  const [ms, hints] = await elapsed(
492
- insertSideEffectsAndBuildBaseRollupHints(tx, provingState.globalVariables, db, provingState.spongeBlobState),
525
+ insertSideEffectsAndBuildBaseRollupHints(
526
+ tx,
527
+ provingState.globalVariables,
528
+ provingState.l1ToL2MessageTreeSnapshot,
529
+ db,
530
+ provingState.spongeBlobState,
531
+ ),
493
532
  );
494
533
 
495
534
  this.metrics.recordBaseRollupInputs(ms);
@@ -687,6 +726,17 @@ export class ProvingOrchestrator implements EpochProver {
687
726
  provingState.reject(`New archive root mismatch.`);
688
727
  }
689
728
 
729
+ const endBlobAccumulator = provingState.endBlobAccumulator!;
730
+ const circuitEndBlobAccumulatorState = result.inputs.blobPublicInputs.endBlobAccumulator;
731
+ if (!circuitEndBlobAccumulatorState.equals(endBlobAccumulator.toBlobAccumulatorPublicInputs())) {
732
+ logger.error(
733
+ `Blob accumulator state mismatch.\nCircuit: ${inspect(circuitEndBlobAccumulatorState)}\nComputed: ${inspect(
734
+ endBlobAccumulator.toBlobAccumulatorPublicInputs(),
735
+ )}`,
736
+ );
737
+ provingState.reject(`Blob accumulator state mismatch.`);
738
+ }
739
+
690
740
  logger.debug(`Completed ${rollupType} proof for block ${provingState.block!.number}`);
691
741
  // validatePartialState(result.inputs.end, tx.treeSnapshots); // TODO(palla/prover)
692
742
 
@@ -770,7 +820,6 @@ export class ProvingOrchestrator implements EpochProver {
770
820
  }
771
821
 
772
822
  const inputs = provingState.getBlockMergeRollupInputs(location);
773
-
774
823
  this.deferredProving(
775
824
  provingState,
776
825
  wrapCallbackInSpan(
@@ -825,7 +874,7 @@ export class ProvingOrchestrator implements EpochProver {
825
874
 
826
875
  logger.debug(`Preparing root rollup`);
827
876
 
828
- const inputs = provingState.getRootRollupInputs(this.proverId);
877
+ const inputs = provingState.getRootRollupInputs();
829
878
 
830
879
  this.deferredProving(
831
880
  provingState,
@@ -859,15 +908,17 @@ export class ProvingOrchestrator implements EpochProver {
859
908
  }
860
909
 
861
910
  private async checkAndEnqueueBlockRootRollup(provingState: BlockProvingState) {
911
+ const blockNumber = provingState.blockNumber;
912
+ // Accumulate as far as we can, in case blocks came in out of order and we are behind:
913
+ await this.provingState?.setBlobAccumulators(blockNumber);
862
914
  if (!provingState.isReadyForBlockRootRollup()) {
863
- logger.debug('Not ready for root rollup');
915
+ logger.debug('Not ready for block root rollup');
864
916
  return;
865
917
  }
866
918
  if (provingState.blockRootRollupStarted) {
867
919
  logger.debug('Block root rollup already started');
868
920
  return;
869
921
  }
870
- const blockNumber = provingState.blockNumber;
871
922
 
872
923
  // TODO(palla/prover): This closes the fork only on the happy path. If this epoch orchestrator
873
924
  // is aborted and never reaches this point, it will leak the fork. We need to add a global cleanup,
@@ -3,15 +3,16 @@ import { times } from '@aztec/foundation/collection';
3
3
  import { Fr } from '@aztec/foundation/fields';
4
4
  import { createLogger } from '@aztec/foundation/log';
5
5
  import { NativeACVMSimulator } from '@aztec/simulator/server';
6
- import type {
7
- ActualProverConfig,
8
- EpochProver,
9
- EpochProverManager,
10
- ForkMerkleTreeOperations,
11
- ProvingJobBroker,
12
- ProvingJobConsumer,
13
- ProvingJobProducer,
14
- ServerCircuitProver,
6
+ import {
7
+ type ActualProverConfig,
8
+ type EpochProver,
9
+ type EpochProverManager,
10
+ type ForkMerkleTreeOperations,
11
+ type ProvingJobBroker,
12
+ type ProvingJobConsumer,
13
+ type ProvingJobProducer,
14
+ type ServerCircuitProver,
15
+ tryStop,
15
16
  } from '@aztec/stdlib/interfaces/server';
16
17
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
17
18
 
@@ -87,6 +88,7 @@ export class ProverClient implements EpochProverManager {
87
88
  }
88
89
  this.running = false;
89
90
  await this.stopAgents();
91
+ await tryStop(this.orchestratorClient);
90
92
  }
91
93
 
92
94
  /**
@@ -1,3 +1,4 @@
1
+ import type { BatchedBlob, FinalBlobBatchingChallenges } from '@aztec/blob-lib';
1
2
  import type { Fr } from '@aztec/foundation/fields';
2
3
  import type { L2Block } from '@aztec/stdlib/block';
3
4
  import type { EpochProver } from '@aztec/stdlib/interfaces/server';
@@ -15,8 +16,13 @@ export class ServerEpochProver implements EpochProver {
15
16
  private orchestrator: ProvingOrchestrator,
16
17
  ) {}
17
18
 
18
- startNewEpoch(epochNumber: number, firstBlockNumber: number, totalNumBlocks: number): void {
19
- this.orchestrator.startNewEpoch(epochNumber, firstBlockNumber, totalNumBlocks);
19
+ startNewEpoch(
20
+ epochNumber: number,
21
+ firstBlockNumber: number,
22
+ totalNumBlocks: number,
23
+ finalBlobBatchingChallenges: FinalBlobBatchingChallenges,
24
+ ): void {
25
+ this.orchestrator.startNewEpoch(epochNumber, firstBlockNumber, totalNumBlocks, finalBlobBatchingChallenges);
20
26
  this.facade.start();
21
27
  }
22
28
  startTubeCircuits(txs: Tx[]): Promise<void> {
@@ -25,7 +31,7 @@ export class ServerEpochProver implements EpochProver {
25
31
  setBlockCompleted(blockNumber: number, expectedBlockHeader?: BlockHeader): Promise<L2Block> {
26
32
  return this.orchestrator.setBlockCompleted(blockNumber, expectedBlockHeader);
27
33
  }
28
- finaliseEpoch(): Promise<{ publicInputs: RootRollupPublicInputs; proof: Proof }> {
34
+ finaliseEpoch(): Promise<{ publicInputs: RootRollupPublicInputs; proof: Proof; batchedBlobInputs: BatchedBlob }> {
29
35
  return this.orchestrator.finaliseEpoch();
30
36
  }
31
37
  cancel(): void {