@aztec/prover-client 0.56.0 → 0.58.0

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 (48) hide show
  1. package/dest/config.d.ts +4 -5
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +11 -2
  4. package/dest/index.d.ts +1 -1
  5. package/dest/index.d.ts.map +1 -1
  6. package/dest/mocks/fixtures.d.ts +6 -6
  7. package/dest/mocks/fixtures.d.ts.map +1 -1
  8. package/dest/mocks/fixtures.js +8 -4
  9. package/dest/mocks/test_context.d.ts +7 -7
  10. package/dest/mocks/test_context.d.ts.map +1 -1
  11. package/dest/mocks/test_context.js +15 -18
  12. package/dest/orchestrator/block-building-helpers.d.ts +12 -12
  13. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  14. package/dest/orchestrator/block-building-helpers.js +4 -2
  15. package/dest/orchestrator/block-proving-state.d.ts +7 -7
  16. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  17. package/dest/orchestrator/block-proving-state.js +11 -33
  18. package/dest/orchestrator/epoch-proving-state.d.ts +8 -2
  19. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  20. package/dest/orchestrator/epoch-proving-state.js +8 -16
  21. package/dest/orchestrator/orchestrator.d.ts +15 -19
  22. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  23. package/dest/orchestrator/orchestrator.js +161 -106
  24. package/dest/prover-agent/memory-proving-queue.d.ts +5 -8
  25. package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
  26. package/dest/prover-agent/memory-proving-queue.js +3 -3
  27. package/dest/prover-agent/prover-agent.js +4 -4
  28. package/dest/prover-agent/rpc.js +4 -4
  29. package/dest/test/mock_prover.d.ts +10 -16
  30. package/dest/test/mock_prover.d.ts.map +1 -1
  31. package/dest/test/mock_prover.js +18 -24
  32. package/dest/tx-prover/tx-prover.d.ts +3 -4
  33. package/dest/tx-prover/tx-prover.d.ts.map +1 -1
  34. package/dest/tx-prover/tx-prover.js +2 -2
  35. package/package.json +14 -10
  36. package/src/config.ts +20 -11
  37. package/src/index.ts +1 -1
  38. package/src/mocks/fixtures.ts +21 -7
  39. package/src/mocks/test_context.ts +26 -22
  40. package/src/orchestrator/block-building-helpers.ts +21 -12
  41. package/src/orchestrator/block-proving-state.ts +11 -35
  42. package/src/orchestrator/epoch-proving-state.ts +9 -20
  43. package/src/orchestrator/orchestrator.ts +205 -140
  44. package/src/prover-agent/memory-proving-queue.ts +8 -7
  45. package/src/prover-agent/prover-agent.ts +4 -4
  46. package/src/prover-agent/rpc.ts +3 -3
  47. package/src/test/mock_prover.ts +26 -28
  48. package/src/tx-prover/tx-prover.ts +5 -5
@@ -1,20 +1,14 @@
1
1
  import {
2
- BlockProofError,
3
2
  Body,
4
3
  EncryptedNoteTxL2Logs,
5
4
  EncryptedTxL2Logs,
6
5
  L2Block,
7
6
  MerkleTreeId,
8
- PROVING_STATUS,
9
7
  type PaddingProcessedTx,
10
8
  type ProcessedTx,
11
- type ProvingBlockResult,
12
9
  ProvingRequestType,
13
- type ProvingResult,
14
- type ProvingTicket,
15
10
  type PublicInputsAndRecursiveProof,
16
11
  type ServerCircuitProver,
17
- Tx,
18
12
  type TxEffect,
19
13
  UnencryptedTxL2Logs,
20
14
  makeEmptyProcessedTx,
@@ -22,7 +16,7 @@ import {
22
16
  mapProvingRequestTypeToCircuitName,
23
17
  toTxEffect,
24
18
  } from '@aztec/circuit-types';
25
- import { type EpochProver } from '@aztec/circuit-types/interfaces';
19
+ import { type EpochProver, type MerkleTreeWriteOperations } from '@aztec/circuit-types/interfaces';
26
20
  import { type CircuitName } from '@aztec/circuit-types/stats';
27
21
  import {
28
22
  AvmCircuitInputs,
@@ -31,8 +25,10 @@ import {
31
25
  type BaseRollupInputs,
32
26
  type BlockRootOrBlockMergePublicInputs,
33
27
  BlockRootRollupInputs,
28
+ EmptyBlockRootRollupInputs,
34
29
  Fr,
35
30
  type GlobalVariables,
31
+ type Header,
36
32
  type KernelCircuitPublicInputs,
37
33
  L1_TO_L2_MSG_SUBTREE_HEIGHT,
38
34
  L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH,
@@ -46,6 +42,7 @@ import {
46
42
  type RecursiveProof,
47
43
  type RootParityInput,
48
44
  RootParityInputs,
45
+ TUBE_INDEX,
49
46
  type TUBE_PROOF_LENGTH,
50
47
  TubeInputs,
51
48
  type VMCircuitPublicInputs,
@@ -62,9 +59,9 @@ import { promiseWithResolvers } from '@aztec/foundation/promise';
62
59
  import { type Tuple } from '@aztec/foundation/serialize';
63
60
  import { pushTestData } from '@aztec/foundation/testing';
64
61
  import { elapsed } from '@aztec/foundation/timer';
65
- import { getVKIndex, getVKSiblingPath, getVKTreeRoot } from '@aztec/noir-protocol-circuits-types';
62
+ import { TubeVk, getVKIndex, getVKSiblingPath, getVKTreeRoot } from '@aztec/noir-protocol-circuits-types';
63
+ import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
66
64
  import { Attributes, type TelemetryClient, type Tracer, trackSpan, wrapCallbackInSpan } from '@aztec/telemetry-client';
67
- import { type MerkleTreeOperations } from '@aztec/world-state';
68
65
 
69
66
  import { inspect } from 'util';
70
67
 
@@ -83,7 +80,12 @@ import {
83
80
  validateTx,
84
81
  } from './block-building-helpers.js';
85
82
  import { type BlockProvingState, type MergeRollupInputData } from './block-proving-state.js';
86
- import { type BlockMergeRollupInputData, EpochProvingState, type TreeSnapshots } from './epoch-proving-state.js';
83
+ import {
84
+ type BlockMergeRollupInputData,
85
+ EpochProvingState,
86
+ type ProvingResult,
87
+ type TreeSnapshots,
88
+ } from './epoch-proving-state.js';
87
89
  import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
88
90
  import { TX_PROVING_CODE, type TxProvingInstruction, TxProvingState } from './tx-proving-state.js';
89
91
 
@@ -108,10 +110,11 @@ export class ProvingOrchestrator implements EpochProver {
108
110
  private pendingProvingJobs: AbortController[] = [];
109
111
  private paddingTx: PaddingProcessedTx | undefined = undefined;
110
112
 
113
+ private provingPromise: Promise<ProvingResult> | undefined = undefined;
111
114
  private metrics: ProvingOrchestratorMetrics;
112
115
 
113
116
  constructor(
114
- private db: MerkleTreeOperations,
117
+ private db: MerkleTreeWriteOperations,
115
118
  private prover: ServerCircuitProver,
116
119
  telemetryClient: TelemetryClient,
117
120
  private readonly proverId: Fr = Fr.ZERO,
@@ -134,26 +137,20 @@ export class ProvingOrchestrator implements EpochProver {
134
137
  this.paddingTx = undefined;
135
138
  }
136
139
 
137
- @trackSpan('ProvingOrchestrator.startNewEpoch', (epochNumber, totalNumBlocks) => ({
138
- [Attributes.EPOCH_SIZE]: totalNumBlocks,
139
- [Attributes.EPOCH_NUMBER]: epochNumber,
140
- }))
141
- public startNewEpoch(epochNumber: number, totalNumBlocks: number): ProvingTicket {
140
+ public startNewEpoch(epochNumber: number, totalNumBlocks: number) {
142
141
  const { promise: _promise, resolve, reject } = promiseWithResolvers<ProvingResult>();
143
- const promise = _promise.catch(
144
- (reason): ProvingResult => ({
145
- status: PROVING_STATUS.FAILURE,
146
- reason,
147
- }),
148
- );
149
-
142
+ const promise = _promise.catch((reason): ProvingResult => ({ status: 'failure', reason }));
143
+ if (totalNumBlocks <= 0 || !Number.isInteger(totalNumBlocks)) {
144
+ throw new Error(`Invalid number of blocks for epoch (got ${totalNumBlocks})`);
145
+ }
146
+ logger.info(`Starting epoch ${epochNumber} with ${totalNumBlocks} blocks`);
150
147
  this.provingState = new EpochProvingState(epochNumber, totalNumBlocks, resolve, reject);
151
- return { provingPromise: promise };
148
+ this.provingPromise = promise;
152
149
  }
153
150
 
154
151
  /**
155
152
  * Starts off a new block
156
- * @param numTxs - The total number of transactions in the block. Must be a power of 2
153
+ * @param numTxs - The total number of transactions in the block.
157
154
  * @param globalVariables - The global variables for the block
158
155
  * @param l1ToL2Messages - The l1 to l2 messages for the block
159
156
  * @param verificationKeys - The private kernel verification keys
@@ -163,14 +160,9 @@ export class ProvingOrchestrator implements EpochProver {
163
160
  [Attributes.BLOCK_SIZE]: numTxs,
164
161
  [Attributes.BLOCK_NUMBER]: globalVariables.blockNumber.toNumber(),
165
162
  }))
166
- public async startNewBlock(
167
- numTxs: number,
168
- globalVariables: GlobalVariables,
169
- l1ToL2Messages: Fr[],
170
- ): Promise<ProvingTicket> {
171
- // If no proving state, assume we only care about proving this block and initialize a 1-block epoch
163
+ public async startNewBlock(numTxs: number, globalVariables: GlobalVariables, l1ToL2Messages: Fr[]) {
172
164
  if (!this.provingState) {
173
- this.startNewEpoch(globalVariables.blockNumber.toNumber(), 1);
165
+ throw new Error(`Invalid proving state, call startNewEpoch before starting a block`);
174
166
  }
175
167
 
176
168
  if (!this.provingState?.isAcceptingBlocks()) {
@@ -178,10 +170,14 @@ export class ProvingOrchestrator implements EpochProver {
178
170
  }
179
171
 
180
172
  if (!Number.isInteger(numTxs) || numTxs < 2) {
181
- throw new Error(`Length of txs for the block should be at least two (got ${numTxs})`);
173
+ throw new Error(`Invalid number of txs for block (got ${numTxs})`);
174
+ }
175
+
176
+ if (this.provingState.currentBlock && !this.provingState.currentBlock.block) {
177
+ throw new Error(`Must end previous block before starting a new one`);
182
178
  }
183
179
 
184
- // TODO(palla/prover-node): Store block number in the db itself to make this check more reliable,
180
+ // TODO(palla/prover): Store block number in the db itself to make this check more reliable,
185
181
  // and turn this warning into an exception that we throw.
186
182
  const { blockNumber } = globalVariables;
187
183
  const dbBlockNumber = (await this.db.getTreeInfo(MerkleTreeId.ARCHIVE)).size - 1n;
@@ -234,9 +230,6 @@ export class ProvingOrchestrator implements EpochProver {
234
230
  BigInt(startArchiveSnapshot.nextAvailableLeafIndex - 1),
235
231
  );
236
232
 
237
- const { promise: _promise, resolve, reject } = promiseWithResolvers<ProvingResult>();
238
- const promise = _promise.catch((reason): ProvingResult => ({ status: PROVING_STATUS.FAILURE, reason }));
239
-
240
233
  this.provingState!.startNewBlock(
241
234
  numTxs,
242
235
  globalVariables,
@@ -247,16 +240,12 @@ export class ProvingOrchestrator implements EpochProver {
247
240
  startArchiveSnapshot,
248
241
  newArchiveSiblingPath,
249
242
  previousBlockHash!,
250
- resolve,
251
- reject,
252
243
  );
253
244
 
254
245
  // Enqueue base parity circuits for the block
255
246
  for (let i = 0; i < baseParityInputs.length; i++) {
256
247
  this.enqueueBaseParityCircuit(this.provingState!.currentBlock!, baseParityInputs[i], i);
257
248
  }
258
-
259
- return { provingPromise: promise };
260
249
  }
261
250
 
262
251
  /**
@@ -276,6 +265,10 @@ export class ProvingOrchestrator implements EpochProver {
276
265
  throw new Error(`Rollup not accepting further transactions`);
277
266
  }
278
267
 
268
+ if (!provingState.verifyState()) {
269
+ throw new Error(`Invalid proving state when adding a tx`);
270
+ }
271
+
279
272
  validateTx(tx);
280
273
 
281
274
  logger.info(`Received transaction: ${tx.hash}`);
@@ -289,10 +282,7 @@ export class ProvingOrchestrator implements EpochProver {
289
282
  this.enqueueFirstProofs(inputs, treeSnapshots, tx, provingState);
290
283
 
291
284
  if (provingState.transactionsReceived === provingState.totalNumTxs) {
292
- logger.verbose(
293
- `All transactions received for block ${provingState.globalVariables.blockNumber}. Assembling header.`,
294
- );
295
- await this.buildBlockHeader(provingState);
285
+ logger.verbose(`All transactions received for block ${provingState.globalVariables.blockNumber}.`);
296
286
  }
297
287
  }
298
288
 
@@ -311,53 +301,132 @@ export class ProvingOrchestrator implements EpochProver {
311
301
  [Attributes.BLOCK_TXS_COUNT]: block.transactionsReceived,
312
302
  };
313
303
  })
314
- public async setBlockCompleted() {
304
+ public async setBlockCompleted(expectedHeader?: Header): Promise<L2Block> {
315
305
  const provingState = this.provingState?.currentBlock;
316
306
  if (!provingState) {
317
307
  throw new Error(`Invalid proving state, call startNewBlock before adding transactions or completing the block`);
318
308
  }
319
309
 
320
- // we may need to pad the rollup with empty transactions
310
+ if (!provingState.verifyState()) {
311
+ throw new Error(`Block proving failed: ${provingState.error}`);
312
+ }
313
+
314
+ // We may need to pad the rollup with empty transactions
321
315
  const paddingTxCount = provingState.totalNumTxs - provingState.transactionsReceived;
322
- if (paddingTxCount === 0) {
323
- return;
324
- } else if (provingState.totalNumTxs > 2) {
316
+ if (paddingTxCount > 0 && provingState.totalNumTxs > 2) {
325
317
  throw new Error(`Block not ready for completion: expecting ${paddingTxCount} more transactions.`);
326
318
  }
327
319
 
328
- logger.debug(`Padding rollup with ${paddingTxCount} empty transactions`);
329
- // Make an empty padding transaction
330
- // Required for:
331
- // 0 (when we want an empty block, largely for testing), or
332
- // 1 (we need to pad with one tx as all rollup circuits require a pair of inputs) txs
333
- // Insert it into the tree the required number of times to get all of the
334
- // base rollup inputs
335
- // Then enqueue the proving of all the transactions
336
- const unprovenPaddingTx = makeEmptyProcessedTx(
337
- this.db.getInitialHeader(),
338
- provingState.globalVariables.chainId,
339
- provingState.globalVariables.version,
340
- getVKTreeRoot(),
341
- );
342
- const txInputs: Array<{ inputs: BaseRollupInputs; snapshot: TreeSnapshots }> = [];
343
- for (let i = 0; i < paddingTxCount; i++) {
344
- const [inputs, snapshot] = await this.prepareTransaction(unprovenPaddingTx, provingState);
345
- const txInput = {
346
- inputs,
347
- snapshot,
348
- };
349
- txInputs.push(txInput);
350
- }
320
+ if (paddingTxCount > 0) {
321
+ logger.debug(`Padding rollup with ${paddingTxCount} empty transactions`);
322
+ // Make an empty padding transaction
323
+ // Required for:
324
+ // 0 (when we want an empty block, largely for testing), or
325
+ // 1 (we need to pad with one tx as all rollup circuits require a pair of inputs) txs
326
+ // Insert it into the tree the required number of times to get all of the
327
+ // base rollup inputs
328
+ // Then enqueue the proving of all the transactions
329
+ const unprovenPaddingTx = makeEmptyProcessedTx(
330
+ this.db.getInitialHeader(),
331
+ provingState.globalVariables.chainId,
332
+ provingState.globalVariables.version,
333
+ getVKTreeRoot(),
334
+ protocolContractTreeRoot,
335
+ );
336
+ const txInputs: Array<{ inputs: BaseRollupInputs; snapshot: TreeSnapshots }> = [];
337
+ for (let i = 0; i < paddingTxCount; i++) {
338
+ const [inputs, snapshot] = await this.prepareTransaction(unprovenPaddingTx, provingState);
339
+ const txInput = {
340
+ inputs,
341
+ snapshot,
342
+ };
343
+ txInputs.push(txInput);
344
+ }
351
345
 
352
- // Now enqueue the proving
353
- this.enqueuePaddingTxs(provingState, txInputs, unprovenPaddingTx);
346
+ // Now enqueue the proving
347
+ this.enqueuePaddingTxs(provingState, txInputs, unprovenPaddingTx);
348
+ }
354
349
 
355
350
  // And build the block header
356
- logger.verbose(`Block ${provingState.globalVariables.blockNumber} padded with empty tx(s). Assembling header.`);
357
- await this.buildBlockHeader(provingState);
351
+ logger.verbose(`Block ${provingState.globalVariables.blockNumber} completed. Assembling header.`);
352
+ await this.buildBlock(provingState, expectedHeader);
353
+
354
+ // If the proofs were faster than the block building, then we need to try the block root rollup again here
355
+ this.checkAndEnqueueBlockRootRollup(provingState);
356
+ return provingState.block!;
358
357
  }
359
358
 
360
- private async buildBlockHeader(provingState: BlockProvingState) {
359
+ /** Returns the block as built for a given index. */
360
+ public getBlock(index: number): L2Block {
361
+ const block = this.provingState?.blocks[index].block;
362
+ if (!block) {
363
+ throw new Error(`Block at index ${index} not available`);
364
+ }
365
+ return block;
366
+ }
367
+
368
+ @trackSpan('ProvingOrchestrator.padEpoch', function () {
369
+ if (!this.provingState) {
370
+ return {};
371
+ }
372
+ return {
373
+ [Attributes.EPOCH_NUMBER]: this.provingState.epochNumber,
374
+ [Attributes.EPOCH_SIZE]: this.provingState.totalNumBlocks,
375
+ };
376
+ })
377
+ private padEpoch(): Promise<void> {
378
+ const provingState = this.provingState!;
379
+ const lastBlock = provingState.currentBlock?.block;
380
+ if (!lastBlock) {
381
+ return Promise.reject(new Error(`Epoch needs at least one completed block in order to be padded`));
382
+ }
383
+
384
+ const paddingBlockCount = Math.max(2, provingState.totalNumBlocks) - provingState.blocks.length;
385
+ if (paddingBlockCount === 0) {
386
+ return Promise.resolve();
387
+ }
388
+
389
+ logger.debug(`Padding epoch proof with ${paddingBlockCount} empty block proofs`);
390
+
391
+ const inputs = EmptyBlockRootRollupInputs.from({
392
+ archive: lastBlock.archive,
393
+ blockHash: lastBlock.header.hash(),
394
+ globalVariables: lastBlock.header.globalVariables,
395
+ vkTreeRoot: getVKTreeRoot(),
396
+ protocolContractTreeRoot,
397
+ proverId: this.proverId,
398
+ });
399
+
400
+ logger.debug(`Enqueuing deferred proving for padding block to enqueue ${paddingBlockCount} paddings`);
401
+ this.deferredProving(
402
+ provingState,
403
+ wrapCallbackInSpan(
404
+ this.tracer,
405
+ 'ProvingOrchestrator.prover.getEmptyBlockRootRollupProof',
406
+ {
407
+ [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
408
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'empty-block-root-rollup' satisfies CircuitName,
409
+ },
410
+ signal => this.prover.getEmptyBlockRootRollupProof(inputs, signal, provingState.epochNumber),
411
+ ),
412
+ result => {
413
+ logger.debug(`Completed proof for padding block`);
414
+ const currentLevel = provingState.numMergeLevels + 1n;
415
+ for (let i = 0; i < paddingBlockCount; i++) {
416
+ logger.debug(`Enqueuing padding block with index ${provingState.blocks.length + i}`);
417
+ const index = BigInt(provingState.blocks.length + i);
418
+ this.storeAndExecuteNextBlockMergeLevel(provingState, currentLevel, index, [
419
+ result.inputs,
420
+ result.proof,
421
+ result.verificationKey.keyAsFields,
422
+ ]);
423
+ }
424
+ },
425
+ );
426
+ return Promise.resolve();
427
+ }
428
+
429
+ private async buildBlock(provingState: BlockProvingState, expectedHeader?: Header) {
361
430
  // Collect all new nullifiers, commitments, and contracts from all txs in this block to build body
362
431
  const gasFees = provingState.globalVariables.gasFees;
363
432
  const nonEmptyTxEffects: TxEffect[] = provingState!.allTxs
@@ -374,12 +443,17 @@ export class ProvingOrchestrator implements EpochProver {
374
443
  this.db,
375
444
  );
376
445
 
446
+ if (expectedHeader && !header.equals(expectedHeader)) {
447
+ logger.error(`Block header mismatch: header=${header} expectedHeader=${expectedHeader}`);
448
+ throw new Error('Block header mismatch');
449
+ }
450
+
377
451
  logger.verbose(`Updating archive tree with block ${provingState.blockNumber} header ${header.hash().toString()}`);
378
452
  await this.db.updateArchive(header);
379
453
 
380
454
  // Assemble the L2 block
381
455
  const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.db);
382
- const l2Block = L2Block.fromFields({ archive: newArchive, header, body });
456
+ const l2Block = new L2Block(newArchive, header, body);
383
457
 
384
458
  if (!l2Block.body.getTxsEffectsHash().equals(header.contentCommitment.txsEffectsHash)) {
385
459
  throw new Error(
@@ -426,6 +500,7 @@ export class ProvingOrchestrator implements EpochProver {
426
500
  unprovenPaddingTx.data.constants.txContext.chainId,
427
501
  unprovenPaddingTx.data.constants.txContext.version,
428
502
  getVKTreeRoot(),
503
+ protocolContractTreeRoot,
429
504
  ),
430
505
  signal,
431
506
  provingState.epochNumber,
@@ -499,52 +574,29 @@ export class ProvingOrchestrator implements EpochProver {
499
574
  }
500
575
 
501
576
  /**
502
- * Returns the fully proven block. Requires proving to have been completed.
503
- * @param index - The index of the block to finalise. Defaults to the last block.
504
- * @returns The fully proven block and proof.
577
+ * Returns the proof for the current epoch.
505
578
  */
506
- public finaliseBlock(index?: number) {
507
- try {
508
- const block = this.provingState?.blocks[index ?? this.provingState?.blocks.length - 1];
509
-
510
- if (!block || !block.blockRootRollupPublicInputs || !block.finalProof || !block.block) {
511
- throw new Error(`Invalid proving state, a block must be proven before it can be finalised`);
512
- }
579
+ public async finaliseEpoch() {
580
+ if (!this.provingState || !this.provingPromise) {
581
+ throw new Error(`Invalid proving state, an epoch must be proven before it can be finalised`);
582
+ }
513
583
 
514
- const blockResult: ProvingBlockResult = {
515
- proof: block.finalProof,
516
- aggregationObject: block.finalProof.extractAggregationObject(),
517
- block: block.block!,
518
- };
519
-
520
- pushTestData('blockResults', {
521
- proverId: this.proverId.toString(),
522
- vkTreeRoot: getVKTreeRoot().toString(),
523
- block: blockResult.block.toString(),
524
- proof: blockResult.proof.toString(),
525
- aggregationObject: blockResult.aggregationObject.map(x => x.toString()),
526
- });
584
+ await this.padEpoch();
527
585
 
528
- return Promise.resolve(blockResult);
529
- } catch (err) {
530
- throw new BlockProofError(
531
- err && typeof err === 'object' && 'message' in err ? String(err.message) : String(err),
532
- this.provingState?.blocks[index ?? this.provingState?.blocks.length - 1]?.allTxs.map(x =>
533
- Tx.getHash(x.processedTx),
534
- ) ?? [],
535
- );
586
+ const result = await this.provingPromise!;
587
+ if (result.status === 'failure') {
588
+ throw new Error(`Epoch proving failed: ${result.reason}`);
536
589
  }
537
- }
538
590
 
539
- /**
540
- * Returns the proof for the current epoch.
541
- * Requires proving to have been completed.
542
- */
543
- public finaliseEpoch() {
544
- if (!this.provingState || !this.provingState.rootRollupPublicInputs || !this.provingState.finalProof) {
545
- throw new Error(`Invalid proving state, an epoch must be proven before it can be finalised`);
591
+ if (!this.provingState.rootRollupPublicInputs || !this.provingState.finalProof) {
592
+ throw new Error(`Invalid proving state, missing root rollup public inputs or final proof`);
546
593
  }
547
594
 
595
+ pushTestData('epochProofResult', {
596
+ proof: this.provingState.finalProof.toString(),
597
+ publicInputs: this.provingState.rootRollupPublicInputs.toString(),
598
+ });
599
+
548
600
  return { proof: this.provingState.finalProof, publicInputs: this.provingState.rootRollupPublicInputs };
549
601
  }
550
602
 
@@ -663,7 +715,7 @@ export class ProvingOrchestrator implements EpochProver {
663
715
  makeEmptyRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH),
664
716
  provingState.globalVariables,
665
717
  this.db,
666
- VerificationKeyData.makeFake(),
718
+ TubeVk,
667
719
  ),
668
720
  );
669
721
 
@@ -795,8 +847,14 @@ export class ProvingOrchestrator implements EpochProver {
795
847
  ),
796
848
  result => {
797
849
  logger.debug(`Completed tube proof for tx index: ${txIndex}`);
798
- const nextKernelRequest = txProvingState.getNextPublicKernelFromTubeProof(result.tubeProof, result.tubeVK);
799
- this.checkAndEnqueueNextTxCircuit(provingState, txIndex, result.tubeProof, result.tubeVK, nextKernelRequest);
850
+ const nextKernelRequest = txProvingState.getNextPublicKernelFromTubeProof(result.proof, result.verificationKey);
851
+ this.checkAndEnqueueNextTxCircuit(
852
+ provingState,
853
+ txIndex,
854
+ result.proof,
855
+ result.verificationKey,
856
+ nextKernelRequest,
857
+ );
800
858
  },
801
859
  );
802
860
  }
@@ -836,11 +894,17 @@ export class ProvingOrchestrator implements EpochProver {
836
894
  }
837
895
 
838
896
  // Executes the block root rollup circuit
839
- private enqueueBlockRootRollup(provingState: BlockProvingState | undefined) {
840
- if (!provingState?.verifyState()) {
897
+ private enqueueBlockRootRollup(provingState: BlockProvingState) {
898
+ if (!provingState.block) {
899
+ throw new Error(`Invalid proving state for block root rollup, block not available`);
900
+ }
901
+
902
+ if (!provingState.verifyState()) {
841
903
  logger.debug('Not running block root rollup, state no longer valid');
842
904
  return;
843
905
  }
906
+
907
+ provingState.blockRootRollupStarted = true;
844
908
  const mergeInputData = provingState.getMergeInputs(0);
845
909
  const rootParityInput = provingState.finalRootParityInput!;
846
910
 
@@ -868,8 +932,6 @@ export class ProvingOrchestrator implements EpochProver {
868
932
  proverId: this.proverId,
869
933
  });
870
934
 
871
- const shouldProveEpoch = this.provingState!.totalNumBlocks > 1;
872
-
873
935
  this.deferredProving(
874
936
  provingState,
875
937
  wrapCallbackInSpan(
@@ -879,10 +941,7 @@ export class ProvingOrchestrator implements EpochProver {
879
941
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
880
942
  [Attributes.PROTOCOL_CIRCUIT_NAME]: 'block-root-rollup' satisfies CircuitName,
881
943
  },
882
- signal =>
883
- shouldProveEpoch
884
- ? this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber)
885
- : this.prover.getBlockRootRollupFinalProof(inputs, signal, provingState.epochNumber),
944
+ signal => this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber),
886
945
  ),
887
946
  result => {
888
947
  const header = this.extractBlockHeaderFromPublicInputs(provingState, result.inputs);
@@ -895,17 +954,10 @@ export class ProvingOrchestrator implements EpochProver {
895
954
 
896
955
  provingState.blockRootRollupPublicInputs = result.inputs;
897
956
  provingState.finalProof = result.proof.binaryProof;
898
- provingState.resolve({ status: PROVING_STATUS.SUCCESS });
899
957
 
900
958
  logger.debug(`Completed proof for block root rollup for ${provingState.block?.number}`);
901
959
  // validatePartialState(result.inputs.end, tx.treeSnapshots); // TODO(palla/prover)
902
960
 
903
- // TODO(palla/prover): Remove this once we've dropped the flow for proving single blocks
904
- if (!shouldProveEpoch) {
905
- logger.verbose(`Skipping epoch rollup, only one block in epoch`);
906
- return;
907
- }
908
-
909
961
  const currentLevel = this.provingState!.numMergeLevels + 1n;
910
962
  this.storeAndExecuteNextBlockMergeLevel(this.provingState!, currentLevel, BigInt(provingState.index), [
911
963
  result.inputs,
@@ -1032,18 +1084,23 @@ export class ProvingOrchestrator implements EpochProver {
1032
1084
  signal => this.prover.getRootRollupProof(inputs, signal, provingState.epochNumber),
1033
1085
  ),
1034
1086
  result => {
1087
+ logger.verbose(`Orchestrator completed root rollup for epoch ${provingState.epochNumber}`);
1035
1088
  provingState.rootRollupPublicInputs = result.inputs;
1036
1089
  provingState.finalProof = result.proof.binaryProof;
1037
- provingState.resolve({ status: PROVING_STATUS.SUCCESS });
1090
+ provingState.resolve({ status: 'success' });
1038
1091
  },
1039
1092
  );
1040
1093
  }
1041
1094
 
1042
- private checkAndEnqueueBlockRootRollup(provingState: BlockProvingState | undefined) {
1095
+ private checkAndEnqueueBlockRootRollup(provingState: BlockProvingState) {
1043
1096
  if (!provingState?.isReadyForBlockRootRollup()) {
1044
1097
  logger.debug('Not ready for root rollup');
1045
1098
  return;
1046
1099
  }
1100
+ if (provingState.blockRootRollupStarted) {
1101
+ logger.debug('Block root rollup already started');
1102
+ return;
1103
+ }
1047
1104
  this.enqueueBlockRootRollup(provingState);
1048
1105
  }
1049
1106
 
@@ -1181,7 +1238,10 @@ export class ProvingOrchestrator implements EpochProver {
1181
1238
  logger.warn(
1182
1239
  `Error thrown when proving AVM circuit, but AVM_PROVING_STRICT is off, so faking AVM proof and carrying on. Error: ${err}.`,
1183
1240
  );
1184
- return { proof: makeEmptyProof(), verificationKey: VerificationKeyData.makeFake() };
1241
+ return {
1242
+ proof: makeEmptyProof(),
1243
+ verificationKey: VerificationKeyData.makeFakeHonk(),
1244
+ };
1185
1245
  }
1186
1246
  }
1187
1247
  },
@@ -1234,7 +1294,12 @@ export class ProvingOrchestrator implements EpochProver {
1234
1294
  // Take the final proof and assign it to the base rollup inputs
1235
1295
  txProvingState.baseRollupInputs.kernelData.proof = proof;
1236
1296
  txProvingState.baseRollupInputs.kernelData.vk = verificationKey;
1237
- txProvingState.baseRollupInputs.kernelData.vkIndex = getVKIndex(verificationKey);
1297
+ try {
1298
+ txProvingState.baseRollupInputs.kernelData.vkIndex = getVKIndex(verificationKey);
1299
+ } catch (_ignored) {
1300
+ // TODO(#7410) The VK for the tube won't be in the tree for now, so we manually set it to the tube vk index
1301
+ txProvingState.baseRollupInputs.kernelData.vkIndex = TUBE_INDEX;
1302
+ }
1238
1303
  txProvingState.baseRollupInputs.kernelData.vkPath = getVKSiblingPath(
1239
1304
  txProvingState.baseRollupInputs.kernelData.vkIndex,
1240
1305
  );
@@ -1,5 +1,5 @@
1
1
  import {
2
- type AvmProofAndVerificationKey,
2
+ type ProofAndVerificationKey,
3
3
  type ProvingJob,
4
4
  type ProvingJobSource,
5
5
  type ProvingRequest,
@@ -16,10 +16,12 @@ import type {
16
16
  BlockMergeRollupInputs,
17
17
  BlockRootOrBlockMergePublicInputs,
18
18
  BlockRootRollupInputs,
19
+ EmptyBlockRootRollupInputs,
19
20
  KernelCircuitPublicInputs,
20
21
  MergeRollupInputs,
21
22
  NESTED_RECURSIVE_PROOF_LENGTH,
22
23
  PrivateKernelEmptyInputData,
24
+ Proof,
23
25
  PublicKernelCircuitPrivateInputs,
24
26
  PublicKernelCircuitPublicInputs,
25
27
  PublicKernelInnerCircuitPrivateInputs,
@@ -32,7 +34,6 @@ import type {
32
34
  RootRollupPublicInputs,
33
35
  TubeInputs,
34
36
  VMCircuitPublicInputs,
35
- VerificationKeyData,
36
37
  } from '@aztec/circuits.js';
37
38
  import { randomBytes } from '@aztec/foundation/crypto';
38
39
  import { AbortError, TimeoutError } from '@aztec/foundation/error';
@@ -279,7 +280,7 @@ export class MemoryProvingQueue implements ServerCircuitProver, ProvingJobSource
279
280
  inputs: TubeInputs,
280
281
  signal?: AbortSignal,
281
282
  epochNumber?: number,
282
- ): Promise<{ tubeVK: VerificationKeyData; tubeProof: RecursiveProof<typeof RECURSIVE_PROOF_LENGTH> }> {
283
+ ): Promise<ProofAndVerificationKey<RecursiveProof<typeof RECURSIVE_PROOF_LENGTH>>> {
283
284
  return this.enqueue({ type: ProvingRequestType.TUBE_PROOF, inputs }, signal, epochNumber);
284
285
  }
285
286
 
@@ -351,12 +352,12 @@ export class MemoryProvingQueue implements ServerCircuitProver, ProvingJobSource
351
352
  return this.enqueue({ type: ProvingRequestType.BLOCK_ROOT_ROLLUP, inputs: input }, signal, epochNumber);
352
353
  }
353
354
 
354
- getBlockRootRollupFinalProof(
355
- input: BlockRootRollupInputs,
355
+ getEmptyBlockRootRollupProof(
356
+ input: EmptyBlockRootRollupInputs,
356
357
  signal?: AbortSignal,
357
358
  epochNumber?: number,
358
359
  ): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>> {
359
- return this.enqueue({ type: ProvingRequestType.BLOCK_ROOT_ROLLUP_FINAL, inputs: input }, signal, epochNumber);
360
+ return this.enqueue({ type: ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP, inputs: input }, signal, epochNumber);
360
361
  }
361
362
 
362
363
  /**
@@ -426,7 +427,7 @@ export class MemoryProvingQueue implements ServerCircuitProver, ProvingJobSource
426
427
  inputs: AvmCircuitInputs,
427
428
  signal?: AbortSignal,
428
429
  epochNumber?: number,
429
- ): Promise<AvmProofAndVerificationKey> {
430
+ ): Promise<ProofAndVerificationKey<Proof>> {
430
431
  return this.enqueue({ type: ProvingRequestType.PUBLIC_VM, inputs }, signal, epochNumber);
431
432
  }
432
433
 
@@ -181,12 +181,12 @@ export class ProverAgent {
181
181
  return this.circuitProver.getMergeRollupProof(inputs);
182
182
  }
183
183
 
184
- case ProvingRequestType.BLOCK_ROOT_ROLLUP: {
185
- return this.circuitProver.getBlockRootRollupProof(inputs);
184
+ case ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP: {
185
+ return this.circuitProver.getEmptyBlockRootRollupProof(inputs);
186
186
  }
187
187
 
188
- case ProvingRequestType.BLOCK_ROOT_ROLLUP_FINAL: {
189
- return this.circuitProver.getBlockRootRollupFinalProof(inputs);
188
+ case ProvingRequestType.BLOCK_ROOT_ROLLUP: {
189
+ return this.circuitProver.getBlockRootRollupProof(inputs);
190
190
  }
191
191
 
192
192
  case ProvingRequestType.BLOCK_MERGE_ROLLUP: {