@aztec/prover-client 0.69.0-devnet → 0.69.1-devnet

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 (90) hide show
  1. package/dest/block_builder/light.d.ts +0 -1
  2. package/dest/block_builder/light.d.ts.map +1 -1
  3. package/dest/block_builder/light.js +4 -14
  4. package/dest/config.d.ts +2 -1
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +3 -2
  7. package/dest/mocks/test_context.d.ts +2 -2
  8. package/dest/mocks/test_context.d.ts.map +1 -1
  9. package/dest/mocks/test_context.js +6 -6
  10. package/dest/orchestrator/block-building-helpers.d.ts +10 -25
  11. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  12. package/dest/orchestrator/block-building-helpers.js +33 -44
  13. package/dest/orchestrator/block-proving-state.d.ts +40 -44
  14. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  15. package/dest/orchestrator/block-proving-state.js +149 -85
  16. package/dest/orchestrator/epoch-proving-state.d.ts +23 -30
  17. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  18. package/dest/orchestrator/epoch-proving-state.js +92 -65
  19. package/dest/orchestrator/orchestrator.d.ts +16 -47
  20. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  21. package/dest/orchestrator/orchestrator.js +204 -341
  22. package/dest/orchestrator/tx-proving-state.d.ts +10 -6
  23. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  24. package/dest/orchestrator/tx-proving-state.js +57 -46
  25. package/dest/prover-agent/memory-proving-queue.d.ts +3 -3
  26. package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
  27. package/dest/prover-agent/memory-proving-queue.js +4 -4
  28. package/dest/prover-agent/prover-agent.js +4 -4
  29. package/dest/prover-client/prover-client.d.ts.map +1 -1
  30. package/dest/prover-client/prover-client.js +5 -2
  31. package/dest/prover-client/server-epoch-prover.d.ts +25 -0
  32. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -0
  33. package/dest/prover-client/server-epoch-prover.js +40 -0
  34. package/dest/proving_broker/broker_prover_facade.d.ts +15 -4
  35. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  36. package/dest/proving_broker/broker_prover_facade.js +247 -44
  37. package/dest/proving_broker/config.d.ts +61 -0
  38. package/dest/proving_broker/config.d.ts.map +1 -0
  39. package/dest/proving_broker/config.js +83 -0
  40. package/dest/proving_broker/factory.d.ts +1 -1
  41. package/dest/proving_broker/factory.d.ts.map +1 -1
  42. package/dest/proving_broker/factory.js +2 -5
  43. package/dest/proving_broker/fixtures.d.ts +5 -0
  44. package/dest/proving_broker/fixtures.d.ts.map +1 -0
  45. package/dest/proving_broker/fixtures.js +12 -0
  46. package/dest/proving_broker/index.d.ts +1 -0
  47. package/dest/proving_broker/index.d.ts.map +1 -1
  48. package/dest/proving_broker/index.js +2 -1
  49. package/dest/proving_broker/proving_broker.d.ts +16 -12
  50. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  51. package/dest/proving_broker/proving_broker.js +306 -273
  52. package/dest/proving_broker/proving_broker_database/memory.d.ts +4 -2
  53. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
  54. package/dest/proving_broker/proving_broker_database/memory.js +17 -4
  55. package/dest/proving_broker/proving_broker_database/persisted.d.ts +10 -6
  56. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  57. package/dest/proving_broker/proving_broker_database/persisted.js +105 -13
  58. package/dest/proving_broker/proving_broker_database.d.ts +7 -3
  59. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
  60. package/dest/proving_broker/proving_job_controller.js +4 -4
  61. package/dest/proving_broker/rpc.d.ts.map +1 -1
  62. package/dest/proving_broker/rpc.js +4 -4
  63. package/dest/test/mock_prover.d.ts +6 -6
  64. package/dest/test/mock_prover.d.ts.map +1 -1
  65. package/dest/test/mock_prover.js +6 -6
  66. package/package.json +11 -11
  67. package/src/block_builder/light.ts +3 -21
  68. package/src/config.ts +4 -4
  69. package/src/mocks/test_context.ts +3 -6
  70. package/src/orchestrator/block-building-helpers.ts +44 -118
  71. package/src/orchestrator/block-proving-state.ts +251 -121
  72. package/src/orchestrator/epoch-proving-state.ts +159 -88
  73. package/src/orchestrator/orchestrator.ts +251 -527
  74. package/src/orchestrator/tx-proving-state.ts +35 -19
  75. package/src/prover-agent/memory-proving-queue.ts +11 -12
  76. package/src/prover-agent/prover-agent.ts +4 -4
  77. package/src/prover-client/prover-client.ts +4 -6
  78. package/src/prover-client/server-epoch-prover.ts +44 -0
  79. package/src/proving_broker/broker_prover_facade.ts +321 -61
  80. package/src/proving_broker/config.ts +93 -0
  81. package/src/proving_broker/factory.ts +2 -5
  82. package/src/proving_broker/fixtures.ts +14 -0
  83. package/src/proving_broker/index.ts +1 -0
  84. package/src/proving_broker/proving_broker.ts +114 -71
  85. package/src/proving_broker/proving_broker_database/memory.ts +24 -4
  86. package/src/proving_broker/proving_broker_database/persisted.ts +141 -19
  87. package/src/proving_broker/proving_broker_database.ts +8 -3
  88. package/src/proving_broker/proving_job_controller.ts +5 -5
  89. package/src/proving_broker/rpc.ts +2 -3
  90. package/src/test/mock_prover.ts +9 -11
@@ -3,7 +3,7 @@ import {
3
3
  MerkleTreeId,
4
4
  type ProcessedTx,
5
5
  type ServerCircuitProver,
6
- makeEmptyProcessedTx,
6
+ type Tx,
7
7
  toNumBlobFields,
8
8
  } from '@aztec/circuit-types';
9
9
  import {
@@ -17,46 +17,38 @@ import {
17
17
  AVM_PROOF_LENGTH_IN_FIELDS,
18
18
  AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS,
19
19
  type AppendOnlyTreeSnapshot,
20
- BLOBS_PER_BLOCK,
21
20
  BaseParityInputs,
22
- type BlockHeader,
23
- FIELDS_PER_BLOB,
21
+ BlockHeader,
22
+ ContentCommitment,
24
23
  Fr,
25
- type GlobalVariables,
24
+ GlobalVariables,
26
25
  L1_TO_L2_MSG_SUBTREE_HEIGHT,
27
26
  L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH,
28
- type NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH,
29
27
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
30
28
  NUM_BASE_PARITY_PER_ROOT_PARITY,
31
- PrivateKernelEmptyInputData,
32
- type RECURSIVE_PROOF_LENGTH,
33
- type RecursiveProof,
34
- RootParityInput,
35
- RootParityInputs,
36
- type VerificationKeyAsFields,
29
+ PartialStateReference,
30
+ StateReference,
31
+ type TUBE_PROOF_LENGTH,
37
32
  VerificationKeyData,
38
33
  makeEmptyRecursiveProof,
39
34
  } from '@aztec/circuits.js';
40
- import { BlobPublicInputs } from '@aztec/circuits.js/blobs';
41
35
  import {
42
- type BaseOrMergeRollupPublicInputs,
43
36
  type BaseRollupHints,
44
- type BlockRootOrBlockMergePublicInputs,
45
- BlockRootRollupInputs,
46
37
  EmptyBlockRootRollupInputs,
38
+ PrivateBaseRollupInputs,
39
+ SingleTxBlockRootRollupInputs,
40
+ TubeInputs,
47
41
  } from '@aztec/circuits.js/rollup';
48
42
  import { makeTuple } from '@aztec/foundation/array';
49
- import { Blob } from '@aztec/foundation/blob';
50
- import { maxBy, padArrayEnd } from '@aztec/foundation/collection';
51
- import { sha256ToField } from '@aztec/foundation/crypto';
43
+ import { padArrayEnd } from '@aztec/foundation/collection';
52
44
  import { AbortError } from '@aztec/foundation/error';
53
45
  import { createLogger } from '@aztec/foundation/log';
54
46
  import { promiseWithResolvers } from '@aztec/foundation/promise';
55
47
  import { type Tuple } from '@aztec/foundation/serialize';
56
48
  import { pushTestData } from '@aztec/foundation/testing';
57
49
  import { elapsed } from '@aztec/foundation/timer';
58
- import { getVKIndex, getVKSiblingPath, getVKTreeRoot } from '@aztec/noir-protocol-circuits-types';
59
- import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
50
+ import { type TreeNodeLocation } from '@aztec/foundation/trees';
51
+ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vks';
60
52
  import { Attributes, type TelemetryClient, type Tracer, trackSpan, wrapCallbackInSpan } from '@aztec/telemetry-client';
61
53
 
62
54
  import { inspect } from 'util';
@@ -64,24 +56,14 @@ import { inspect } from 'util';
64
56
  import {
65
57
  buildBaseRollupHints,
66
58
  buildHeaderAndBodyFromTxs,
67
- buildHeaderFromCircuitOutputs,
68
- createBlockMergeRollupInputs,
69
- createMergeRollupInputs,
70
- getPreviousRollupDataFromPublicInputs,
71
- getRootRollupInput,
72
59
  getRootTreeSiblingPath,
73
60
  getSubtreeSiblingPath,
74
61
  getTreeSnapshot,
75
62
  validatePartialState,
76
63
  validateTx,
77
64
  } from './block-building-helpers.js';
78
- import { type BlockProvingState, type MergeRollupInputData } from './block-proving-state.js';
79
- import {
80
- type BlockMergeRollupInputData,
81
- EpochProvingState,
82
- type ProvingResult,
83
- type TreeSnapshots,
84
- } from './epoch-proving-state.js';
65
+ import { type BlockProvingState } from './block-proving-state.js';
66
+ import { EpochProvingState, type ProvingResult, type TreeSnapshots } from './epoch-proving-state.js';
85
67
  import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
86
68
  import { TxProvingState } from './tx-proving-state.js';
87
69
 
@@ -104,7 +86,6 @@ const logger = createLogger('prover-client:orchestrator');
104
86
  export class ProvingOrchestrator implements EpochProver {
105
87
  private provingState: EpochProvingState | undefined = undefined;
106
88
  private pendingProvingJobs: AbortController[] = [];
107
- private paddingTxProof?: ProofAndVerificationKey<typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>;
108
89
 
109
90
  private provingPromise: Promise<ProvingResult> | undefined = undefined;
110
91
  private metrics: ProvingOrchestratorMetrics;
@@ -127,11 +108,9 @@ export class ProvingOrchestrator implements EpochProver {
127
108
  return this.proverId;
128
109
  }
129
110
 
130
- /**
131
- * Resets the orchestrator's cached padding tx.
132
- */
133
- public reset() {
134
- this.paddingTxProof = undefined;
111
+ public stop(): Promise<void> {
112
+ this.cancel();
113
+ return Promise.resolve();
135
114
  }
136
115
 
137
116
  public startNewEpoch(epochNumber: number, firstBlockNumber: number, totalNumBlocks: number) {
@@ -210,6 +189,22 @@ export class ProvingOrchestrator implements EpochProver {
210
189
  BigInt(startArchiveSnapshot.nextAvailableLeafIndex - 1),
211
190
  );
212
191
 
192
+ const partial = new PartialStateReference(
193
+ await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db),
194
+ await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db),
195
+ await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db),
196
+ );
197
+ const state = new StateReference(messageTreeSnapshot, partial);
198
+ // TODO: Construct the full previousBlockHeader.
199
+ const previousBlockHeader = BlockHeader.from({
200
+ lastArchive: startArchiveSnapshot,
201
+ contentCommitment: ContentCommitment.empty(),
202
+ state,
203
+ globalVariables: GlobalVariables.empty(),
204
+ totalFees: Fr.ZERO,
205
+ totalManaUsed: Fr.ZERO,
206
+ });
207
+
213
208
  const blockProvingState = this.provingState!.startNewBlock(
214
209
  globalVariables,
215
210
  l1ToL2MessagesPadded,
@@ -218,6 +213,7 @@ export class ProvingOrchestrator implements EpochProver {
218
213
  messageTreeSnapshotAfterInsertion,
219
214
  startArchiveSnapshot,
220
215
  newArchiveSiblingPath,
216
+ previousBlockHeader,
221
217
  previousBlockHash!,
222
218
  );
223
219
 
@@ -228,7 +224,7 @@ export class ProvingOrchestrator implements EpochProver {
228
224
  }
229
225
 
230
226
  /**
231
- * The interface to add simulated transactions to the scheduler
227
+ * The interface to add simulated transactions to the scheduler. This can only be called once per block.
232
228
  * @param txs - The transactions to be proven
233
229
  */
234
230
  @trackSpan('ProvingOrchestrator.addTxs', txs => ({
@@ -247,11 +243,15 @@ export class ProvingOrchestrator implements EpochProver {
247
243
  throw new Error(`Block proving state for ${blockNumber} not found`);
248
244
  }
249
245
 
246
+ if (provingState.totalNumTxs) {
247
+ throw new Error(`Block ${blockNumber} has been initialized with transactions.`);
248
+ }
249
+
250
250
  const numBlobFields = toNumBlobFields(txs);
251
- provingState.startNewBlock(Math.max(2, txs.length), numBlobFields);
251
+ provingState.startNewBlock(txs.length, numBlobFields);
252
252
 
253
253
  logger.info(
254
- `Adding ${txs.length} transactions with ${numBlobFields} blob fields to block ${provingState?.blockNumber}`,
254
+ `Adding ${txs.length} transactions with ${numBlobFields} blob fields to block ${provingState.blockNumber}`,
255
255
  );
256
256
  for (const tx of txs) {
257
257
  try {
@@ -269,20 +269,42 @@ export class ProvingOrchestrator implements EpochProver {
269
269
  }
270
270
 
271
271
  const [hints, treeSnapshots] = await this.prepareTransaction(tx, provingState);
272
- this.enqueueFirstProofs(hints, treeSnapshots, tx, provingState);
272
+ const txProvingState = new TxProvingState(tx, hints, treeSnapshots);
273
+ const txIndex = provingState.addNewTx(txProvingState);
274
+ this.getOrEnqueueTube(provingState, txIndex);
275
+ if (txProvingState.requireAvmProof) {
276
+ logger.debug(`Enqueueing public VM for tx ${txIndex}`);
277
+ this.enqueueVM(provingState, txIndex);
278
+ }
273
279
  } catch (err: any) {
274
280
  throw new Error(`Error adding transaction ${tx.hash.toString()} to block ${blockNumber}: ${err.message}`, {
275
281
  cause: err,
276
282
  });
277
283
  }
278
284
  }
279
- if (provingState.transactionsReceived === provingState.totalNumTxs) {
280
- logger.verbose(`All transactions received for block ${provingState.globalVariables.blockNumber}.`);
285
+ }
286
+
287
+ /**
288
+ * Kickstarts tube circuits for the specified txs. These will be used during epoch proving.
289
+ * Note that if the tube circuits are not started this way, they will be started nontheless after processing.
290
+ */
291
+ @trackSpan('ProvingOrchestrator.startTubeCircuits')
292
+ public startTubeCircuits(txs: Tx[]) {
293
+ if (!this.provingState?.verifyState()) {
294
+ throw new Error(`Invalid proving state, call startNewEpoch before starting tube circuits`);
295
+ }
296
+ for (const tx of txs) {
297
+ const txHash = tx.getTxHash().toString();
298
+ const tubeInputs = new TubeInputs(tx.clientIvcProof);
299
+ const tubeProof = promiseWithResolvers<ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>>();
300
+ logger.debug(`Starting tube circuit for tx ${txHash}`);
301
+ this.doEnqueueTube(txHash, tubeInputs, proof => tubeProof.resolve(proof));
302
+ this.provingState?.cachedTubeProofs.set(txHash, tubeProof.promise);
281
303
  }
282
304
  }
283
305
 
284
306
  /**
285
- * Marks the block as full and pads it if required, no more transactions will be accepted.
307
+ * Marks the block as completed.
286
308
  * Computes the block header and updates the archive tree.
287
309
  */
288
310
  @trackSpan('ProvingOrchestrator.setBlockCompleted', (blockNumber: number) => ({
@@ -296,50 +318,14 @@ export class ProvingOrchestrator implements EpochProver {
296
318
 
297
319
  if (!provingState.spongeBlobState) {
298
320
  // If we are completing an empty block, initialise the provingState.
299
- // We will have 2 padding txs, and => no blob fields.
300
- provingState.startNewBlock(2, 0);
321
+ // We will have 0 txs and no blob fields.
322
+ provingState.startNewBlock(0, 0);
301
323
  }
302
324
 
303
325
  if (!provingState.verifyState()) {
304
326
  throw new Error(`Block proving failed: ${provingState.error}`);
305
327
  }
306
328
 
307
- // We may need to pad the rollup with empty transactions
308
- const paddingTxCount = provingState.totalNumTxs - provingState.transactionsReceived;
309
- if (paddingTxCount > 0 && provingState.totalNumTxs > 2) {
310
- throw new Error(`Block not ready for completion: expecting ${paddingTxCount} more transactions.`);
311
- }
312
-
313
- if (paddingTxCount > 0) {
314
- logger.debug(`Padding rollup with ${paddingTxCount} empty transactions`);
315
- // Make an empty padding transaction
316
- // Required for:
317
- // 0 (when we want an empty block, largely for testing), or
318
- // 1 (we need to pad with one tx as all rollup circuits require a pair of inputs) txs
319
- // Insert it into the tree the required number of times to get all of the
320
- // base rollup inputs
321
- // Then enqueue the proving of all the transactions
322
- const unprovenPaddingTx = makeEmptyProcessedTx(
323
- this.dbs.get(blockNumber)!.getInitialHeader(),
324
- provingState.globalVariables.chainId,
325
- provingState.globalVariables.version,
326
- getVKTreeRoot(),
327
- protocolContractTreeRoot,
328
- );
329
- const txInputs: Array<{ hints: BaseRollupHints; snapshot: TreeSnapshots }> = [];
330
- for (let i = 0; i < paddingTxCount; i++) {
331
- const [hints, snapshot] = await this.prepareTransaction(unprovenPaddingTx, provingState);
332
- const txInput = {
333
- hints,
334
- snapshot,
335
- };
336
- txInputs.push(txInput);
337
- }
338
-
339
- // Now enqueue the proving
340
- this.enqueuePaddingTxs(provingState, txInputs, unprovenPaddingTx);
341
- }
342
-
343
329
  // And build the block header
344
330
  logger.verbose(`Block ${blockNumber} completed. Assembling header.`);
345
331
  await this.buildBlock(provingState, expectedHeader);
@@ -358,73 +344,9 @@ export class ProvingOrchestrator implements EpochProver {
358
344
  return block;
359
345
  }
360
346
 
361
- @trackSpan('ProvingOrchestrator.padEpoch', function () {
362
- if (!this.provingState) {
363
- return {};
364
- }
365
- return {
366
- [Attributes.EPOCH_NUMBER]: this.provingState.epochNumber,
367
- [Attributes.EPOCH_SIZE]: this.provingState.totalNumBlocks,
368
- };
369
- })
370
- private padEpoch(): Promise<void> {
371
- const provingState = this.provingState!;
372
- const lastBlock = maxBy(
373
- provingState.blocks.filter(b => !!b),
374
- b => b!.blockNumber,
375
- )?.block;
376
- if (!lastBlock) {
377
- return Promise.reject(new Error(`Epoch needs at least one completed block in order to be padded`));
378
- }
379
-
380
- const paddingBlockCount = Math.max(2, provingState.totalNumBlocks) - provingState.blocks.length;
381
- if (paddingBlockCount === 0) {
382
- return Promise.resolve();
383
- }
384
-
385
- logger.debug(`Padding epoch proof with ${paddingBlockCount} empty block proofs`);
386
-
387
- const inputs = EmptyBlockRootRollupInputs.from({
388
- archive: lastBlock.archive,
389
- blockHash: lastBlock.header.hash(),
390
- globalVariables: lastBlock.header.globalVariables,
391
- vkTreeRoot: getVKTreeRoot(),
392
- protocolContractTreeRoot,
393
- proverId: this.proverId,
394
- });
395
-
396
- logger.debug(`Enqueuing deferred proving for padding block to enqueue ${paddingBlockCount} paddings`);
397
- this.deferredProving(
398
- provingState,
399
- wrapCallbackInSpan(
400
- this.tracer,
401
- 'ProvingOrchestrator.prover.getEmptyBlockRootRollupProof',
402
- {
403
- [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
404
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'empty-block-root-rollup' satisfies CircuitName,
405
- },
406
- signal => this.prover.getEmptyBlockRootRollupProof(inputs, signal, provingState.epochNumber),
407
- ),
408
- result => {
409
- logger.debug(`Completed proof for padding block`);
410
- const currentLevel = provingState.numMergeLevels + 1n;
411
- for (let i = 0; i < paddingBlockCount; i++) {
412
- logger.debug(`Enqueuing padding block with index ${provingState.blocks.length + i}`);
413
- const index = BigInt(provingState.blocks.length + i);
414
- this.storeAndExecuteNextBlockMergeLevel(provingState, currentLevel, index, [
415
- result.inputs,
416
- result.proof,
417
- result.verificationKey.keyAsFields,
418
- ]);
419
- }
420
- },
421
- );
422
- return Promise.resolve();
423
- }
424
-
425
347
  private async buildBlock(provingState: BlockProvingState, expectedHeader?: BlockHeader) {
426
348
  // Collect all new nullifiers, commitments, and contracts from all txs in this block to build body
427
- const txs = provingState!.allTxs.map(a => a.processedTx);
349
+ const txs = provingState.allTxs.map(a => a.processedTx);
428
350
 
429
351
  // Get db for this block
430
352
  const db = this.dbs.get(provingState.blockNumber)!;
@@ -468,77 +390,6 @@ export class ProvingOrchestrator implements EpochProver {
468
390
  }
469
391
  }
470
392
 
471
- // Enqueues the proving of the required padding transactions
472
- // If the fully proven padding transaction is not available, this will first be proven
473
- private enqueuePaddingTxs(
474
- provingState: BlockProvingState,
475
- txInputs: Array<{ hints: BaseRollupHints; snapshot: TreeSnapshots }>,
476
- paddingTx: ProcessedTx,
477
- ) {
478
- if (this.paddingTxProof) {
479
- // We already have the padding transaction
480
- logger.debug(`Enqueuing ${txInputs.length} padding transactions using existing padding tx`);
481
- this.provePaddingTransactions(txInputs, paddingTx, this.paddingTxProof, provingState);
482
- return;
483
- }
484
- logger.debug(`Enqueuing deferred proving for padding txs to enqueue ${txInputs.length} paddings`);
485
- this.deferredProving(
486
- provingState,
487
- wrapCallbackInSpan(
488
- this.tracer,
489
- 'ProvingOrchestrator.prover.getEmptyPrivateKernelProof',
490
- {
491
- [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
492
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'private-kernel-empty' satisfies CircuitName,
493
- },
494
- signal =>
495
- this.prover.getEmptyPrivateKernelProof(
496
- new PrivateKernelEmptyInputData(
497
- paddingTx.constants.historicalHeader,
498
- // Chain id and version should not change even if the proving state does, so it's safe to use them for the padding tx
499
- // which gets cached across multiple runs of the orchestrator with different proving states. If they were to change,
500
- // we'd have to clear out the paddingTx here and regenerate it when they do.
501
- paddingTx.constants.txContext.chainId,
502
- paddingTx.constants.txContext.version,
503
- paddingTx.constants.vkTreeRoot,
504
- paddingTx.constants.protocolContractTreeRoot,
505
- ),
506
- signal,
507
- provingState.epochNumber,
508
- ),
509
- ),
510
- result => {
511
- logger.debug(`Completed proof for padding tx, now enqueuing ${txInputs.length} padding txs`);
512
- this.paddingTxProof = { proof: result.proof, verificationKey: result.verificationKey };
513
- this.provePaddingTransactions(txInputs, paddingTx, this.paddingTxProof, provingState);
514
- },
515
- );
516
- }
517
-
518
- /**
519
- * Prepares the cached sets of base rollup inputs for padding transactions and proves them
520
- * @param txInputs - The base rollup inputs, start and end hash paths etc
521
- * @param paddingTx - The padding tx, contains the header and public inputs used in the proof
522
- * @param proofAndVk - The proof and vk of the paddingTx.
523
- * @param provingState - The block proving state
524
- */
525
- private provePaddingTransactions(
526
- txInputs: Array<{ hints: BaseRollupHints; snapshot: TreeSnapshots }>,
527
- paddingTx: ProcessedTx,
528
- proofAndVk: ProofAndVerificationKey<typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>,
529
- provingState: BlockProvingState,
530
- ) {
531
- // The padding tx contains the proof and vk, generated separately from the base inputs
532
- // Copy these into the base rollup inputs and enqueue the base rollup proof
533
- for (let i = 0; i < txInputs.length; i++) {
534
- const { hints, snapshot } = txInputs[i];
535
- const txProvingState = new TxProvingState(paddingTx, hints, snapshot);
536
- txProvingState.assignTubeProof(proofAndVk);
537
- const txIndex = provingState.addNewTx(txProvingState);
538
- this.enqueueBaseRollup(provingState, txIndex);
539
- }
540
- }
541
-
542
393
  /**
543
394
  * Cancel any further proving
544
395
  */
@@ -550,45 +401,6 @@ export class ProvingOrchestrator implements EpochProver {
550
401
  this.provingState?.cancel();
551
402
  }
552
403
 
553
- /**
554
- * Extract the block header from public inputs.
555
- * @returns The header of this proving state's block.
556
- */
557
- private extractBlockHeaderFromPublicInputs(
558
- provingState: BlockProvingState,
559
- rootRollupOutputs: BlockRootOrBlockMergePublicInputs,
560
- ) {
561
- const previousMergeData = provingState.getMergeInputs(0).inputs;
562
-
563
- if (!previousMergeData[0] || !previousMergeData[1]) {
564
- throw new Error(`Invalid proving state, final merge inputs before block root circuit missing.`);
565
- }
566
-
567
- return buildHeaderFromCircuitOutputs(
568
- [previousMergeData[0], previousMergeData[1]],
569
- provingState.finalRootParityInput!.publicInputs,
570
- rootRollupOutputs,
571
- provingState.messageTreeSnapshotAfterInsertion,
572
- logger,
573
- );
574
- }
575
-
576
- /**
577
- * Collect all new nullifiers, commitments, and contracts from all txs in a block
578
- * @returns The array of non empty tx effects.
579
- */
580
- private extractTxEffects(provingState: BlockProvingState) {
581
- // Note: this check should ensure that we have all txs and their effects ready.
582
- if (!provingState.finalRootParityInput?.publicInputs.shaRoot) {
583
- throw new Error(`Invalid proving state, a block must be ready to be proven before its effects can be extracted.`);
584
- }
585
- const nonEmptyTxEffects = provingState.allTxs
586
- .map(txProvingState => txProvingState.processedTx.txEffect)
587
- .filter(txEffect => !txEffect.isEmpty());
588
-
589
- return nonEmptyTxEffects;
590
- }
591
-
592
404
  /**
593
405
  * Returns the proof for the current epoch.
594
406
  */
@@ -597,23 +409,19 @@ export class ProvingOrchestrator implements EpochProver {
597
409
  throw new Error(`Invalid proving state, an epoch must be proven before it can be finalised`);
598
410
  }
599
411
 
600
- await this.padEpoch();
601
-
602
412
  const result = await this.provingPromise!;
603
413
  if (result.status === 'failure') {
604
414
  throw new Error(`Epoch proving failed: ${result.reason}`);
605
415
  }
606
416
 
607
- if (!this.provingState.rootRollupPublicInputs || !this.provingState.finalProof) {
608
- throw new Error(`Invalid proving state, missing root rollup public inputs or final proof`);
609
- }
417
+ const epochProofResult = this.provingState.getEpochProofResult();
610
418
 
611
419
  pushTestData('epochProofResult', {
612
- proof: this.provingState.finalProof.toString(),
613
- publicInputs: this.provingState.rootRollupPublicInputs.toString(),
420
+ proof: epochProofResult.proof.toString(),
421
+ publicInputs: epochProofResult.publicInputs.toString(),
614
422
  });
615
423
 
616
- return { proof: this.provingState.finalProof, publicInputs: this.provingState.rootRollupPublicInputs };
424
+ return epochProofResult;
617
425
  }
618
426
 
619
427
  /**
@@ -630,21 +438,6 @@ export class ProvingOrchestrator implements EpochProver {
630
438
  return txInputs;
631
439
  }
632
440
 
633
- private enqueueFirstProofs(
634
- hints: BaseRollupHints,
635
- treeSnapshots: TreeSnapshots,
636
- tx: ProcessedTx,
637
- provingState: BlockProvingState,
638
- ) {
639
- const txProvingState = new TxProvingState(tx, hints, treeSnapshots);
640
- const txIndex = provingState.addNewTx(txProvingState);
641
- this.enqueueTube(provingState, txIndex);
642
- if (txProvingState.requireAvmProof) {
643
- logger.debug(`Enqueueing public VM for tx ${txIndex}`);
644
- this.enqueueVM(provingState, txIndex);
645
- }
646
- }
647
-
648
441
  /**
649
442
  * Enqueue a job to be scheduled
650
443
  * @param provingState - The proving state object being operated on
@@ -712,10 +505,10 @@ export class ProvingOrchestrator implements EpochProver {
712
505
  [Attributes.TX_HASH]: tx.hash.toString(),
713
506
  }))
714
507
  private async prepareBaseRollupInputs(
715
- provingState: BlockProvingState | undefined,
508
+ provingState: BlockProvingState,
716
509
  tx: ProcessedTx,
717
510
  ): Promise<[BaseRollupHints, TreeSnapshots] | undefined> {
718
- if (!provingState?.verifyState() || !provingState.spongeBlobState) {
511
+ if (!provingState.verifyState() || !provingState.spongeBlobState) {
719
512
  logger.debug('Not preparing base rollup inputs, state invalid');
720
513
  return;
721
514
  }
@@ -739,7 +532,7 @@ export class ProvingOrchestrator implements EpochProver {
739
532
  );
740
533
  const treeSnapshots: TreeSnapshots = new Map((await Promise.all(promises)).map(obj => [obj.key, obj.value]));
741
534
 
742
- if (!provingState?.verifyState()) {
535
+ if (!provingState.verifyState()) {
743
536
  logger.debug(`Discarding proving job, state no longer valid`);
744
537
  return;
745
538
  }
@@ -748,15 +541,15 @@ export class ProvingOrchestrator implements EpochProver {
748
541
 
749
542
  // Executes the base rollup circuit and stored the output as intermediate state for the parent merge/root circuit
750
543
  // Executes the next level of merge if all inputs are available
751
- private enqueueBaseRollup(provingState: BlockProvingState | undefined, txIndex: number) {
752
- if (!provingState?.verifyState()) {
544
+ private enqueueBaseRollup(provingState: BlockProvingState, txIndex: number) {
545
+ if (!provingState.verifyState()) {
753
546
  logger.debug('Not running base rollup, state invalid');
754
547
  return;
755
548
  }
756
549
 
757
550
  const txProvingState = provingState.getTxProvingState(txIndex);
758
551
  const { processedTx } = txProvingState;
759
- const rollupType = txProvingState.requireAvmProof ? 'public-base-rollup' : 'private-base-rollup';
552
+ const { rollupType, inputs } = txProvingState.getBaseRollupTypeAndInputs();
760
553
 
761
554
  logger.debug(
762
555
  `Enqueuing deferred proving base rollup${
@@ -769,19 +562,17 @@ export class ProvingOrchestrator implements EpochProver {
769
562
  wrapCallbackInSpan(
770
563
  this.tracer,
771
564
  `ProvingOrchestrator.prover.${
772
- rollupType === 'private-base-rollup' ? 'getPrivateBaseRollupProof' : 'getPublicBaseRollupProof'
565
+ inputs instanceof PrivateBaseRollupInputs ? 'getPrivateBaseRollupProof' : 'getPublicBaseRollupProof'
773
566
  }`,
774
567
  {
775
568
  [Attributes.TX_HASH]: processedTx.hash.toString(),
776
569
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
777
- [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType satisfies CircuitName,
570
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
778
571
  },
779
572
  signal => {
780
- if (rollupType === 'private-base-rollup') {
781
- const inputs = txProvingState.getPrivateBaseInputs();
573
+ if (inputs instanceof PrivateBaseRollupInputs) {
782
574
  return this.prover.getPrivateBaseRollupProof(inputs, signal, provingState.epochNumber);
783
575
  } else {
784
- const inputs = txProvingState.getPublicBaseInputs();
785
576
  return this.prover.getPublicBaseRollupProof(inputs, signal, provingState.epochNumber);
786
577
  }
787
578
  },
@@ -789,26 +580,54 @@ export class ProvingOrchestrator implements EpochProver {
789
580
  result => {
790
581
  logger.debug(`Completed proof for ${rollupType} for tx ${processedTx.hash.toString()}`);
791
582
  validatePartialState(result.inputs.end, txProvingState.treeSnapshots);
792
- const currentLevel = provingState.numMergeLevels + 1n;
793
- this.storeAndExecuteNextMergeLevel(provingState, currentLevel, BigInt(txIndex), [
794
- result.inputs,
795
- result.proof,
796
- result.verificationKey.keyAsFields,
797
- ]);
583
+ const leafLocation = provingState.setBaseRollupProof(txIndex, result);
584
+ if (provingState.totalNumTxs === 1) {
585
+ this.checkAndEnqueueBlockRootRollup(provingState);
586
+ } else {
587
+ this.checkAndEnqueueNextMergeRollup(provingState, leafLocation);
588
+ }
798
589
  },
799
590
  );
800
591
  }
801
592
 
802
- // Enqueues the tube circuit for a given transaction index
593
+ // Enqueues the tube circuit for a given transaction index, or reuses the one already enqueued
803
594
  // Once completed, will enqueue the next circuit, either a public kernel or the base rollup
804
- private enqueueTube(provingState: BlockProvingState, txIndex: number) {
805
- if (!provingState?.verifyState()) {
595
+ private getOrEnqueueTube(provingState: BlockProvingState, txIndex: number) {
596
+ if (!provingState.verifyState()) {
806
597
  logger.debug('Not running tube circuit, state invalid');
807
598
  return;
808
599
  }
809
600
 
810
601
  const txProvingState = provingState.getTxProvingState(txIndex);
602
+ const txHash = txProvingState.processedTx.hash.toString();
603
+
604
+ const handleResult = (result: ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>) => {
605
+ logger.debug(`Got tube proof for tx index: ${txIndex}`, { txHash });
606
+ txProvingState.setTubeProof(result);
607
+ this.provingState?.cachedTubeProofs.delete(txHash);
608
+ this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
609
+ };
610
+
611
+ if (this.provingState?.cachedTubeProofs.has(txHash)) {
612
+ logger.debug(`Tube proof already enqueued for tx index: ${txIndex}`, { txHash });
613
+ void this.provingState!.cachedTubeProofs.get(txHash)!.then(handleResult);
614
+ return;
615
+ }
616
+
811
617
  logger.debug(`Enqueuing tube circuit for tx index: ${txIndex}`);
618
+ this.doEnqueueTube(txHash, txProvingState.getTubeInputs(), handleResult);
619
+ }
620
+
621
+ private doEnqueueTube(
622
+ txHash: string,
623
+ inputs: TubeInputs,
624
+ handler: (result: ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>) => void,
625
+ provingState: EpochProvingState | BlockProvingState = this.provingState!,
626
+ ) {
627
+ if (!provingState?.verifyState()) {
628
+ logger.debug('Not running tube circuit, state invalid');
629
+ return;
630
+ }
812
631
 
813
632
  this.deferredProving(
814
633
  provingState,
@@ -816,35 +635,25 @@ export class ProvingOrchestrator implements EpochProver {
816
635
  this.tracer,
817
636
  'ProvingOrchestrator.prover.getTubeProof',
818
637
  {
819
- [Attributes.TX_HASH]: txProvingState.processedTx.hash.toString(),
638
+ [Attributes.TX_HASH]: txHash,
820
639
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
821
640
  [Attributes.PROTOCOL_CIRCUIT_NAME]: 'tube-circuit' satisfies CircuitName,
822
641
  },
823
- signal => {
824
- const inputs = txProvingState.getTubeInputs();
825
- return this.prover.getTubeProof(inputs, signal, provingState.epochNumber);
826
- },
642
+ signal => this.prover.getTubeProof(inputs, signal, this.provingState!.epochNumber),
827
643
  ),
828
- result => {
829
- logger.debug(`Completed tube proof for tx index: ${txIndex}`);
830
- txProvingState.assignTubeProof(result);
831
- this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
832
- },
644
+ handler,
833
645
  );
834
646
  }
835
647
 
836
648
  // Executes the merge rollup circuit and stored the output as intermediate state for the parent merge/block root circuit
837
649
  // Enqueues the next level of merge if all inputs are available
838
- private enqueueMergeRollup(
839
- provingState: BlockProvingState,
840
- level: bigint,
841
- index: bigint,
842
- mergeInputData: MergeRollupInputData,
843
- ) {
844
- const inputs = createMergeRollupInputs(
845
- [mergeInputData.inputs[0]!, mergeInputData.proofs[0]!, mergeInputData.verificationKeys[0]!],
846
- [mergeInputData.inputs[1]!, mergeInputData.proofs[1]!, mergeInputData.verificationKeys[1]!],
847
- );
650
+ private enqueueMergeRollup(provingState: BlockProvingState, location: TreeNodeLocation) {
651
+ if (!provingState.verifyState()) {
652
+ logger.debug('Not running merge rollup. State no longer valid.');
653
+ return;
654
+ }
655
+
656
+ const inputs = provingState.getMergeRollupInputs(location);
848
657
 
849
658
  this.deferredProving(
850
659
  provingState,
@@ -858,66 +667,27 @@ export class ProvingOrchestrator implements EpochProver {
858
667
  signal => this.prover.getMergeRollupProof(inputs, signal, provingState.epochNumber),
859
668
  ),
860
669
  result => {
861
- this.storeAndExecuteNextMergeLevel(provingState, level, index, [
862
- result.inputs,
863
- result.proof,
864
- result.verificationKey.keyAsFields,
865
- ]);
670
+ provingState.setMergeRollupProof(location, result);
671
+ this.checkAndEnqueueNextMergeRollup(provingState, location);
866
672
  },
867
673
  );
868
674
  }
869
675
 
870
676
  // Executes the block root rollup circuit
871
677
  private enqueueBlockRootRollup(provingState: BlockProvingState) {
872
- if (!provingState.block) {
873
- throw new Error(`Invalid proving state for block root rollup, block not available`);
874
- }
875
-
876
678
  if (!provingState.verifyState()) {
877
679
  logger.debug('Not running block root rollup, state no longer valid');
878
680
  return;
879
681
  }
880
682
 
881
683
  provingState.blockRootRollupStarted = true;
882
- const mergeInputData = provingState.getMergeInputs(0);
883
- const rootParityInput = provingState.finalRootParityInput!;
884
- const blobFields = this.extractTxEffects(provingState)
885
- .map(tx => tx.toBlobFields())
886
- .flat();
887
- const blobs = Blob.getBlobs(blobFields);
888
- const blobsHash = sha256ToField(blobs.map(b => b.getEthVersionedBlobHash()));
889
684
 
890
- logger.debug(
891
- `Enqueuing block root rollup for block ${provingState.blockNumber} with ${provingState.newL1ToL2Messages.length} l1 to l2 msgs and ${blobs.length} blobs.`,
892
- );
685
+ const { rollupType, inputs } = provingState.getBlockRootRollupTypeAndInputs(this.proverId);
893
686
 
894
- const previousRollupData: BlockRootRollupInputs['previousRollupData'] = makeTuple(2, i =>
895
- getPreviousRollupDataFromPublicInputs(
896
- mergeInputData.inputs[i]!,
897
- mergeInputData.proofs[i]!,
898
- mergeInputData.verificationKeys[i]!,
899
- ),
687
+ logger.debug(
688
+ `Enqueuing ${rollupType} for block ${provingState.blockNumber} with ${provingState.newL1ToL2Messages.length} l1 to l2 msgs.`,
900
689
  );
901
690
 
902
- const inputs = BlockRootRollupInputs.from({
903
- previousRollupData,
904
- l1ToL2Roots: rootParityInput,
905
- newL1ToL2Messages: provingState.newL1ToL2Messages,
906
- newL1ToL2MessageTreeRootSiblingPath: provingState.messageTreeRootSiblingPath,
907
- startL1ToL2MessageTreeSnapshot: provingState.messageTreeSnapshot,
908
- startArchiveSnapshot: provingState.archiveTreeSnapshot,
909
- newArchiveSiblingPath: provingState.archiveTreeRootSiblingPath,
910
- previousBlockHash: provingState.previousBlockHash,
911
- proverId: this.proverId,
912
- blobFields: padArrayEnd(blobFields, Fr.ZERO, FIELDS_PER_BLOB * BLOBS_PER_BLOCK),
913
- blobCommitments: padArrayEnd(
914
- blobs.map(b => b.commitmentToFields()),
915
- [Fr.ZERO, Fr.ZERO],
916
- BLOBS_PER_BLOCK,
917
- ),
918
- blobsHash: blobsHash,
919
- });
920
-
921
691
  this.deferredProving(
922
692
  provingState,
923
693
  wrapCallbackInSpan(
@@ -925,12 +695,21 @@ export class ProvingOrchestrator implements EpochProver {
925
695
  'ProvingOrchestrator.prover.getBlockRootRollupProof',
926
696
  {
927
697
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
928
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'block-root-rollup' satisfies CircuitName,
698
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
699
+ },
700
+ signal => {
701
+ if (inputs instanceof EmptyBlockRootRollupInputs) {
702
+ return this.prover.getEmptyBlockRootRollupProof(inputs, signal, provingState.epochNumber);
703
+ } else if (inputs instanceof SingleTxBlockRootRollupInputs) {
704
+ return this.prover.getSingleTxBlockRootRollupProof(inputs, signal, provingState.epochNumber);
705
+ } else {
706
+ return this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber);
707
+ }
929
708
  },
930
- signal => this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber),
931
709
  ),
932
710
  result => {
933
- const header = this.extractBlockHeaderFromPublicInputs(provingState, result.inputs);
711
+ provingState.setBlockRootRollupProof(result);
712
+ const header = provingState.buildHeaderFromProvingOutputs(logger);
934
713
  if (!header.hash().equals(provingState.block!.header.hash())) {
935
714
  logger.error(
936
715
  `Block header mismatch\nCircuit:${inspect(header)}\nComputed:${inspect(provingState.block!.header)}`,
@@ -938,29 +717,16 @@ export class ProvingOrchestrator implements EpochProver {
938
717
  provingState.reject(`Block header hash mismatch`);
939
718
  }
940
719
 
941
- provingState.blockRootRollupPublicInputs = result.inputs;
942
- provingState.finalProof = result.proof.binaryProof;
943
- const blobOutputs = result.inputs.blobPublicInputs[0];
944
- blobOutputs.inner.forEach((blobOutput, i) => {
945
- if (!blobOutput.isEmpty() && !blobOutput.equals(BlobPublicInputs.fromBlob(blobs[i]))) {
946
- throw new Error(
947
- `Rollup circuits produced mismatched blob evaluation:
948
- z: ${blobOutput.z} == ${blobs[i].challengeZ},
949
- y: ${blobOutput.y.toString(16)} == ${blobs[i].evaluationY.toString('hex')},
950
- C: ${blobOutput.kzgCommitment} == ${blobs[i].commitmentToFields()}`,
951
- );
952
- }
953
- });
954
-
955
- logger.debug(`Completed proof for block root rollup for ${provingState.block?.number}`);
720
+ logger.debug(`Completed ${rollupType} proof for block ${provingState.block!.number}`);
956
721
  // validatePartialState(result.inputs.end, tx.treeSnapshots); // TODO(palla/prover)
957
722
 
958
- const currentLevel = this.provingState!.numMergeLevels + 1n;
959
- this.storeAndExecuteNextBlockMergeLevel(this.provingState!, currentLevel, BigInt(provingState.index), [
960
- result.inputs,
961
- result.proof,
962
- result.verificationKey.keyAsFields,
963
- ]);
723
+ const epochProvingState = this.provingState!;
724
+ const leafLocation = epochProvingState.setBlockRootRollupProof(provingState.index, result);
725
+ if (epochProvingState.totalNumBlocks === 1) {
726
+ this.enqueueEpochPadding(epochProvingState);
727
+ } else {
728
+ this.checkAndEnqueueNextBlockMergeRollup(epochProvingState, leafLocation);
729
+ }
964
730
  },
965
731
  );
966
732
  }
@@ -968,6 +734,11 @@ export class ProvingOrchestrator implements EpochProver {
968
734
  // Executes the base parity circuit and stores the intermediate state for the root parity circuit
969
735
  // Enqueues the root parity circuit if all inputs are available
970
736
  private enqueueBaseParityCircuit(provingState: BlockProvingState, inputs: BaseParityInputs, index: number) {
737
+ if (!provingState.verifyState()) {
738
+ logger.debug('Not running base parity. State no longer valid.');
739
+ return;
740
+ }
741
+
971
742
  this.deferredProving(
972
743
  provingState,
973
744
  wrapCallbackInSpan(
@@ -980,29 +751,30 @@ export class ProvingOrchestrator implements EpochProver {
980
751
  signal => this.prover.getBaseParityProof(inputs, signal, provingState.epochNumber),
981
752
  ),
982
753
  provingOutput => {
983
- const rootParityInput = new RootParityInput(
984
- provingOutput.proof,
985
- provingOutput.verificationKey.keyAsFields,
986
- getVKSiblingPath(getVKIndex(provingOutput.verificationKey)),
987
- provingOutput.inputs,
988
- );
989
- provingState.setRootParityInputs(rootParityInput, index);
990
- if (provingState.areRootParityInputsReady()) {
991
- const rootParityInputs = new RootParityInputs(
992
- provingState.rootParityInput as Tuple<
993
- RootParityInput<typeof RECURSIVE_PROOF_LENGTH>,
994
- typeof NUM_BASE_PARITY_PER_ROOT_PARITY
995
- >,
996
- );
997
- this.enqueueRootParityCircuit(provingState, rootParityInputs);
998
- }
754
+ provingState.setBaseParityProof(index, provingOutput);
755
+ this.checkAndEnqueueRootParityCircuit(provingState);
999
756
  },
1000
757
  );
1001
758
  }
1002
759
 
760
+ private checkAndEnqueueRootParityCircuit(provingState: BlockProvingState) {
761
+ if (!provingState.isReadyForRootParity()) {
762
+ return;
763
+ }
764
+
765
+ this.enqueueRootParityCircuit(provingState);
766
+ }
767
+
1003
768
  // Runs the root parity circuit ans stored the outputs
1004
769
  // Enqueues the root rollup proof if all inputs are available
1005
- private enqueueRootParityCircuit(provingState: BlockProvingState, inputs: RootParityInputs) {
770
+ private enqueueRootParityCircuit(provingState: BlockProvingState) {
771
+ if (!provingState.verifyState()) {
772
+ logger.debug('Not running root parity. State no longer valid.');
773
+ return;
774
+ }
775
+
776
+ const inputs = provingState.getRootParityInputs();
777
+
1006
778
  this.deferredProving(
1007
779
  provingState,
1008
780
  wrapCallbackInSpan(
@@ -1014,14 +786,8 @@ export class ProvingOrchestrator implements EpochProver {
1014
786
  },
1015
787
  signal => this.prover.getRootParityProof(inputs, signal, provingState.epochNumber),
1016
788
  ),
1017
- provingOutput => {
1018
- const rootParityInput = new RootParityInput(
1019
- provingOutput.proof,
1020
- provingOutput.verificationKey.keyAsFields,
1021
- getVKSiblingPath(getVKIndex(provingOutput.verificationKey)),
1022
- provingOutput.inputs,
1023
- );
1024
- provingState!.finalRootParityInput = rootParityInput;
789
+ result => {
790
+ provingState.setRootParityProof(result);
1025
791
  this.checkAndEnqueueBlockRootRollup(provingState);
1026
792
  },
1027
793
  );
@@ -1029,16 +795,13 @@ export class ProvingOrchestrator implements EpochProver {
1029
795
 
1030
796
  // Executes the block merge rollup circuit and stored the output as intermediate state for the parent merge/block root circuit
1031
797
  // Enqueues the next level of merge if all inputs are available
1032
- private enqueueBlockMergeRollup(
1033
- provingState: EpochProvingState,
1034
- level: bigint,
1035
- index: bigint,
1036
- mergeInputData: BlockMergeRollupInputData,
1037
- ) {
1038
- const inputs = createBlockMergeRollupInputs(
1039
- [mergeInputData.inputs[0]!, mergeInputData.proofs[0]!, mergeInputData.verificationKeys[0]!],
1040
- [mergeInputData.inputs[1]!, mergeInputData.proofs[1]!, mergeInputData.verificationKeys[1]!],
1041
- );
798
+ private enqueueBlockMergeRollup(provingState: EpochProvingState, location: TreeNodeLocation) {
799
+ if (!provingState.verifyState()) {
800
+ logger.debug('Not running block merge rollup. State no longer valid.');
801
+ return;
802
+ }
803
+
804
+ const inputs = provingState.getBlockMergeRollupInputs(location);
1042
805
 
1043
806
  this.deferredProving(
1044
807
  provingState,
@@ -1052,34 +815,51 @@ export class ProvingOrchestrator implements EpochProver {
1052
815
  signal => this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber),
1053
816
  ),
1054
817
  result => {
1055
- this.storeAndExecuteNextBlockMergeLevel(provingState, level, index, [
1056
- result.inputs,
1057
- result.proof,
1058
- result.verificationKey.keyAsFields,
1059
- ]);
818
+ provingState.setBlockMergeRollupProof(location, result);
819
+ this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
820
+ },
821
+ );
822
+ }
823
+
824
+ private enqueueEpochPadding(provingState: EpochProvingState) {
825
+ if (!provingState.verifyState()) {
826
+ logger.debug('Not running epoch padding. State no longer valid.');
827
+ return;
828
+ }
829
+
830
+ logger.debug('Padding epoch proof with an empty block root proof.');
831
+
832
+ const inputs = provingState.getPaddingBlockRootInputs(this.proverId);
833
+
834
+ this.deferredProving(
835
+ provingState,
836
+ wrapCallbackInSpan(
837
+ this.tracer,
838
+ 'ProvingOrchestrator.prover.getEmptyBlockRootRollupProof',
839
+ {
840
+ [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
841
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'empty-block-root-rollup' satisfies CircuitName,
842
+ },
843
+ signal => this.prover.getEmptyBlockRootRollupProof(inputs, signal, provingState.epochNumber),
844
+ ),
845
+ result => {
846
+ logger.debug('Completed proof for padding block root.');
847
+ provingState.setPaddingBlockRootProof(result);
848
+ this.checkAndEnqueueRootRollup(provingState);
1060
849
  },
1061
850
  );
1062
851
  }
1063
852
 
1064
853
  // Executes the root rollup circuit
1065
- private enqueueRootRollup(provingState: EpochProvingState | undefined) {
1066
- if (!provingState?.verifyState()) {
854
+ private enqueueRootRollup(provingState: EpochProvingState) {
855
+ if (!provingState.verifyState()) {
1067
856
  logger.debug('Not running root rollup, state no longer valid');
1068
857
  return;
1069
858
  }
1070
859
 
1071
860
  logger.debug(`Preparing root rollup`);
1072
- const mergeInputData = provingState.getMergeInputs(0);
1073
-
1074
- const inputs = getRootRollupInput(
1075
- mergeInputData.inputs[0]!,
1076
- mergeInputData.proofs[0]!,
1077
- mergeInputData.verificationKeys[0]!,
1078
- mergeInputData.inputs[1]!,
1079
- mergeInputData.proofs[1]!,
1080
- mergeInputData.verificationKeys[1]!,
1081
- this.proverId,
1082
- );
861
+
862
+ const inputs = provingState.getRootRollupInputs(this.proverId);
1083
863
 
1084
864
  this.deferredProving(
1085
865
  provingState,
@@ -1094,15 +874,27 @@ export class ProvingOrchestrator implements EpochProver {
1094
874
  ),
1095
875
  result => {
1096
876
  logger.verbose(`Orchestrator completed root rollup for epoch ${provingState.epochNumber}`);
1097
- provingState.rootRollupPublicInputs = result.inputs;
1098
- provingState.finalProof = result.proof.binaryProof;
877
+ provingState.setRootRollupProof(result);
1099
878
  provingState.resolve({ status: 'success' });
1100
879
  },
1101
880
  );
1102
881
  }
1103
882
 
883
+ private checkAndEnqueueNextMergeRollup(provingState: BlockProvingState, currentLocation: TreeNodeLocation) {
884
+ if (!provingState.isReadyForMergeRollup(currentLocation)) {
885
+ return;
886
+ }
887
+
888
+ const parentLocation = provingState.getParentLocation(currentLocation);
889
+ if (parentLocation.level === 0) {
890
+ this.checkAndEnqueueBlockRootRollup(provingState);
891
+ } else {
892
+ this.enqueueMergeRollup(provingState, parentLocation);
893
+ }
894
+ }
895
+
1104
896
  private checkAndEnqueueBlockRootRollup(provingState: BlockProvingState) {
1105
- if (!provingState?.isReadyForBlockRootRollup()) {
897
+ if (!provingState.isReadyForBlockRootRollup()) {
1106
898
  logger.debug('Not ready for root rollup');
1107
899
  return;
1108
900
  }
@@ -1126,94 +918,26 @@ export class ProvingOrchestrator implements EpochProver {
1126
918
  this.enqueueBlockRootRollup(provingState);
1127
919
  }
1128
920
 
1129
- private checkAndEnqueueRootRollup(provingState: EpochProvingState | undefined) {
1130
- if (!provingState?.isReadyForRootRollup()) {
1131
- logger.debug('Not ready for root rollup');
921
+ private checkAndEnqueueNextBlockMergeRollup(provingState: EpochProvingState, currentLocation: TreeNodeLocation) {
922
+ if (!provingState.isReadyForBlockMerge(currentLocation)) {
1132
923
  return;
1133
924
  }
1134
- this.enqueueRootRollup(provingState);
1135
- }
1136
925
 
1137
- /**
1138
- * Stores the inputs to a merge/root circuit and enqueues the circuit if ready
1139
- * @param provingState - The proving state being operated on
1140
- * @param currentLevel - The level of the merge/root circuit
1141
- * @param currentIndex - The index of the merge/root circuit
1142
- * @param mergeInputData - The inputs to be stored
1143
- */
1144
- private storeAndExecuteNextMergeLevel(
1145
- provingState: BlockProvingState,
1146
- currentLevel: bigint,
1147
- currentIndex: bigint,
1148
- mergeInputData: [
1149
- BaseOrMergeRollupPublicInputs,
1150
- RecursiveProof<typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>,
1151
- VerificationKeyAsFields,
1152
- ],
1153
- ) {
1154
- const [mergeLevel, indexWithinMergeLevel, indexWithinMerge] = provingState.findMergeLevel(
1155
- currentLevel,
1156
- currentIndex,
1157
- );
1158
- const mergeIndex = 2n ** mergeLevel - 1n + indexWithinMergeLevel;
1159
- const ready = provingState.storeMergeInputs(mergeInputData, Number(indexWithinMerge), Number(mergeIndex));
1160
- const nextMergeInputData = provingState.getMergeInputs(Number(mergeIndex));
1161
-
1162
- // Are we ready to execute the next circuit?
1163
- if (!ready) {
1164
- return;
1165
- }
1166
-
1167
- if (mergeLevel === 0n) {
1168
- this.checkAndEnqueueBlockRootRollup(provingState);
926
+ const parentLocation = provingState.getParentLocation(currentLocation);
927
+ if (parentLocation.level === 0) {
928
+ this.checkAndEnqueueRootRollup(provingState);
1169
929
  } else {
1170
- // onto the next merge level
1171
- this.enqueueMergeRollup(provingState, mergeLevel, indexWithinMergeLevel, nextMergeInputData);
930
+ this.enqueueBlockMergeRollup(provingState, parentLocation);
1172
931
  }
1173
932
  }
1174
933
 
1175
- /**
1176
- * Stores the inputs to a block merge/root circuit and enqueues the circuit if ready
1177
- * @param provingState - The proving state being operated on
1178
- * @param currentLevel - The level of the merge/root circuit
1179
- * @param currentIndex - The index of the merge/root circuit
1180
- * @param mergeInputData - The inputs to be stored
1181
- */
1182
- private storeAndExecuteNextBlockMergeLevel(
1183
- provingState: EpochProvingState,
1184
- currentLevel: bigint,
1185
- currentIndex: bigint,
1186
- mergeInputData: [
1187
- BlockRootOrBlockMergePublicInputs,
1188
- RecursiveProof<typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>,
1189
- VerificationKeyAsFields,
1190
- ],
1191
- ) {
1192
- const [mergeLevel, indexWithinMergeLevel, indexWithinMerge] = provingState.findMergeLevel(
1193
- currentLevel,
1194
- currentIndex,
1195
- );
1196
- logger.debug(`Computed merge for ${currentLevel}.${currentIndex} as ${mergeLevel}.${indexWithinMergeLevel}`);
1197
- if (mergeLevel < 0n) {
1198
- throw new Error(`Invalid merge level ${mergeLevel}`);
1199
- }
1200
-
1201
- const mergeIndex = 2n ** mergeLevel - 1n + indexWithinMergeLevel;
1202
- const ready = provingState.storeMergeInputs(mergeInputData, Number(indexWithinMerge), Number(mergeIndex));
1203
- const nextMergeInputData = provingState.getMergeInputs(Number(mergeIndex));
1204
-
1205
- // Are we ready to execute the next circuit?
1206
- if (!ready) {
1207
- logger.debug(`Not ready to execute next block merge for level ${mergeLevel} index ${indexWithinMergeLevel}`);
934
+ private checkAndEnqueueRootRollup(provingState: EpochProvingState) {
935
+ if (!provingState.isReadyForRootRollup()) {
936
+ logger.debug('Not ready for root rollup');
1208
937
  return;
1209
938
  }
1210
939
 
1211
- if (mergeLevel === 0n) {
1212
- this.checkAndEnqueueRootRollup(provingState);
1213
- } else {
1214
- // onto the next merge level
1215
- this.enqueueBlockMergeRollup(provingState, mergeLevel, indexWithinMergeLevel, nextMergeInputData);
1216
- }
940
+ this.enqueueRootRollup(provingState);
1217
941
  }
1218
942
 
1219
943
  /**
@@ -1222,8 +946,8 @@ export class ProvingOrchestrator implements EpochProver {
1222
946
  * @param provingState - The proving state being operated on
1223
947
  * @param txIndex - The index of the transaction being proven
1224
948
  */
1225
- private enqueueVM(provingState: BlockProvingState | undefined, txIndex: number) {
1226
- if (!provingState?.verifyState()) {
949
+ private enqueueVM(provingState: BlockProvingState, txIndex: number) {
950
+ if (!provingState.verifyState()) {
1227
951
  logger.debug(`Not running VM circuit as state is no longer valid`);
1228
952
  return;
1229
953
  }
@@ -1263,7 +987,7 @@ export class ProvingOrchestrator implements EpochProver {
1263
987
 
1264
988
  this.deferredProving(provingState, doAvmProving, proofAndVk => {
1265
989
  logger.debug(`Proven VM for tx index: ${txIndex}`);
1266
- txProvingState.assignAvmProof(proofAndVk);
990
+ txProvingState.setAvmProof(proofAndVk);
1267
991
  this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
1268
992
  });
1269
993
  }