@aztec/prover-client 0.69.1 → 0.71.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 (130) hide show
  1. package/dest/bin/get-proof-inputs.d.ts +2 -0
  2. package/dest/bin/get-proof-inputs.d.ts.map +1 -0
  3. package/dest/bin/get-proof-inputs.js +50 -0
  4. package/dest/block_builder/light.d.ts +3 -5
  5. package/dest/block_builder/light.d.ts.map +1 -1
  6. package/dest/block_builder/light.js +9 -22
  7. package/dest/config.d.ts +2 -1
  8. package/dest/config.d.ts.map +1 -1
  9. package/dest/config.js +3 -2
  10. package/dest/mocks/fixtures.d.ts +1 -1
  11. package/dest/mocks/fixtures.d.ts.map +1 -1
  12. package/dest/mocks/fixtures.js +2 -2
  13. package/dest/mocks/test_context.d.ts +1 -1
  14. package/dest/mocks/test_context.d.ts.map +1 -1
  15. package/dest/mocks/test_context.js +11 -12
  16. package/dest/orchestrator/block-building-helpers.d.ts +15 -29
  17. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  18. package/dest/orchestrator/block-building-helpers.js +51 -58
  19. package/dest/orchestrator/block-proving-state.d.ts +40 -44
  20. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  21. package/dest/orchestrator/block-proving-state.js +149 -85
  22. package/dest/orchestrator/epoch-proving-state.d.ts +23 -30
  23. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  24. package/dest/orchestrator/epoch-proving-state.js +92 -65
  25. package/dest/orchestrator/orchestrator.d.ts +17 -48
  26. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  27. package/dest/orchestrator/orchestrator.js +208 -351
  28. package/dest/orchestrator/tx-proving-state.d.ts +10 -6
  29. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  30. package/dest/orchestrator/tx-proving-state.js +57 -46
  31. package/dest/prover-agent/memory-proving-queue.d.ts +4 -4
  32. package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
  33. package/dest/prover-agent/memory-proving-queue.js +5 -5
  34. package/dest/prover-agent/prover-agent.d.ts +0 -2
  35. package/dest/prover-agent/prover-agent.d.ts.map +1 -1
  36. package/dest/prover-agent/prover-agent.js +7 -9
  37. package/dest/prover-client/factory.d.ts.map +1 -1
  38. package/dest/prover-client/factory.js +3 -3
  39. package/dest/prover-client/prover-client.d.ts +4 -2
  40. package/dest/prover-client/prover-client.d.ts.map +1 -1
  41. package/dest/prover-client/prover-client.js +16 -15
  42. package/dest/prover-client/server-epoch-prover.d.ts +25 -0
  43. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -0
  44. package/dest/prover-client/server-epoch-prover.js +40 -0
  45. package/dest/proving_broker/broker_prover_facade.d.ts +19 -7
  46. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  47. package/dest/proving_broker/broker_prover_facade.js +271 -49
  48. package/dest/proving_broker/config.d.ts +61 -0
  49. package/dest/proving_broker/config.d.ts.map +1 -0
  50. package/dest/proving_broker/config.js +83 -0
  51. package/dest/proving_broker/factory.d.ts +1 -1
  52. package/dest/proving_broker/factory.d.ts.map +1 -1
  53. package/dest/proving_broker/factory.js +4 -7
  54. package/dest/proving_broker/fixtures.d.ts +5 -0
  55. package/dest/proving_broker/fixtures.d.ts.map +1 -0
  56. package/dest/proving_broker/fixtures.js +12 -0
  57. package/dest/proving_broker/index.d.ts +2 -1
  58. package/dest/proving_broker/index.d.ts.map +1 -1
  59. package/dest/proving_broker/index.js +3 -2
  60. package/dest/proving_broker/proof_store/factory.d.ts +6 -0
  61. package/dest/proving_broker/proof_store/factory.d.ts.map +1 -0
  62. package/dest/proving_broker/proof_store/factory.js +39 -0
  63. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +13 -0
  64. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +1 -0
  65. package/dest/proving_broker/proof_store/gcs_proof_store.js +46 -0
  66. package/dest/proving_broker/proof_store/index.d.ts +4 -0
  67. package/dest/proving_broker/proof_store/index.d.ts.map +1 -0
  68. package/dest/proving_broker/proof_store/index.js +4 -0
  69. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +14 -0
  70. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -0
  71. package/dest/proving_broker/proof_store/inline_proof_store.js +37 -0
  72. package/dest/proving_broker/{proof_store.d.ts → proof_store/proof_store.d.ts} +1 -12
  73. package/dest/proving_broker/proof_store/proof_store.d.ts.map +1 -0
  74. package/dest/proving_broker/proof_store/proof_store.js +2 -0
  75. package/dest/proving_broker/proving_agent.d.ts +4 -4
  76. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  77. package/dest/proving_broker/proving_agent.js +5 -5
  78. package/dest/proving_broker/proving_broker.d.ts +16 -12
  79. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  80. package/dest/proving_broker/proving_broker.js +307 -274
  81. package/dest/proving_broker/proving_broker_database/memory.d.ts +4 -2
  82. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
  83. package/dest/proving_broker/proving_broker_database/memory.js +17 -4
  84. package/dest/proving_broker/proving_broker_database/persisted.d.ts +10 -6
  85. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  86. package/dest/proving_broker/proving_broker_database/persisted.js +106 -14
  87. package/dest/proving_broker/proving_broker_database.d.ts +7 -3
  88. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
  89. package/dest/proving_broker/proving_job_controller.js +4 -4
  90. package/dest/proving_broker/rpc.d.ts.map +1 -1
  91. package/dest/proving_broker/rpc.js +4 -4
  92. package/dest/test/mock_prover.d.ts +8 -8
  93. package/dest/test/mock_prover.d.ts.map +1 -1
  94. package/dest/test/mock_prover.js +9 -10
  95. package/package.json +14 -12
  96. package/src/bin/get-proof-inputs.ts +60 -0
  97. package/src/block_builder/light.ts +7 -31
  98. package/src/config.ts +4 -4
  99. package/src/mocks/fixtures.ts +1 -1
  100. package/src/mocks/test_context.ts +9 -11
  101. package/src/orchestrator/block-building-helpers.ts +360 -402
  102. package/src/orchestrator/block-proving-state.ts +251 -121
  103. package/src/orchestrator/epoch-proving-state.ts +159 -88
  104. package/src/orchestrator/orchestrator.ts +262 -542
  105. package/src/orchestrator/tx-proving-state.ts +30 -18
  106. package/src/prover-agent/memory-proving-queue.ts +12 -16
  107. package/src/prover-agent/prover-agent.ts +14 -8
  108. package/src/prover-client/factory.ts +2 -3
  109. package/src/prover-client/prover-client.ts +17 -20
  110. package/src/prover-client/server-epoch-prover.ts +44 -0
  111. package/src/proving_broker/broker_prover_facade.ts +347 -67
  112. package/src/proving_broker/config.ts +93 -0
  113. package/src/proving_broker/factory.ts +11 -10
  114. package/src/proving_broker/fixtures.ts +14 -0
  115. package/src/proving_broker/index.ts +2 -1
  116. package/src/proving_broker/proof_store/factory.ts +42 -0
  117. package/src/proving_broker/proof_store/gcs_proof_store.ts +72 -0
  118. package/src/proving_broker/proof_store/index.ts +3 -0
  119. package/src/proving_broker/{proof_store.ts → proof_store/inline_proof_store.ts} +1 -44
  120. package/src/proving_broker/proof_store/proof_store.ts +54 -0
  121. package/src/proving_broker/proving_agent.ts +11 -5
  122. package/src/proving_broker/proving_broker.ts +122 -73
  123. package/src/proving_broker/proving_broker_database/memory.ts +24 -4
  124. package/src/proving_broker/proving_broker_database/persisted.ts +142 -20
  125. package/src/proving_broker/proving_broker_database.ts +8 -3
  126. package/src/proving_broker/proving_job_controller.ts +5 -5
  127. package/src/proving_broker/rpc.ts +2 -3
  128. package/src/test/mock_prover.ts +12 -18
  129. package/dest/proving_broker/proof_store.d.ts.map +0 -1
  130. package/dest/proving_broker/proof_store.js +0 -37
@@ -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,71 +17,60 @@ 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';
60
- import { Attributes, type TelemetryClient, type Tracer, trackSpan, wrapCallbackInSpan } from '@aztec/telemetry-client';
50
+ import { type TreeNodeLocation } from '@aztec/foundation/trees';
51
+ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vks';
52
+ import {
53
+ Attributes,
54
+ type TelemetryClient,
55
+ type Tracer,
56
+ getTelemetryClient,
57
+ trackSpan,
58
+ wrapCallbackInSpan,
59
+ } from '@aztec/telemetry-client';
61
60
 
62
61
  import { inspect } from 'util';
63
62
 
64
63
  import {
65
64
  buildBaseRollupHints,
66
65
  buildHeaderAndBodyFromTxs,
67
- buildHeaderFromCircuitOutputs,
68
- createBlockMergeRollupInputs,
69
- createMergeRollupInputs,
70
- getPreviousRollupDataFromPublicInputs,
71
- getRootRollupInput,
72
66
  getRootTreeSiblingPath,
73
67
  getSubtreeSiblingPath,
74
68
  getTreeSnapshot,
75
69
  validatePartialState,
76
70
  validateTx,
77
71
  } 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';
72
+ import { type BlockProvingState } from './block-proving-state.js';
73
+ import { EpochProvingState, type ProvingResult, type TreeSnapshots } from './epoch-proving-state.js';
85
74
  import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
86
75
  import { TxProvingState } from './tx-proving-state.js';
87
76
 
@@ -104,7 +93,6 @@ const logger = createLogger('prover-client:orchestrator');
104
93
  export class ProvingOrchestrator implements EpochProver {
105
94
  private provingState: EpochProvingState | undefined = undefined;
106
95
  private pendingProvingJobs: AbortController[] = [];
107
- private paddingTxProof?: ProofAndVerificationKey<typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>;
108
96
 
109
97
  private provingPromise: Promise<ProvingResult> | undefined = undefined;
110
98
  private metrics: ProvingOrchestratorMetrics;
@@ -113,8 +101,8 @@ export class ProvingOrchestrator implements EpochProver {
113
101
  constructor(
114
102
  private dbProvider: ForkMerkleTreeOperations,
115
103
  private prover: ServerCircuitProver,
116
- telemetryClient: TelemetryClient,
117
104
  private readonly proverId: Fr = Fr.ZERO,
105
+ telemetryClient: TelemetryClient = getTelemetryClient(),
118
106
  ) {
119
107
  this.metrics = new ProvingOrchestratorMetrics(telemetryClient, 'ProvingOrchestrator');
120
108
  }
@@ -127,11 +115,9 @@ export class ProvingOrchestrator implements EpochProver {
127
115
  return this.proverId;
128
116
  }
129
117
 
130
- /**
131
- * Resets the orchestrator's cached padding tx.
132
- */
133
- public reset() {
134
- this.paddingTxProof = undefined;
118
+ public stop(): Promise<void> {
119
+ this.cancel();
120
+ return Promise.resolve();
135
121
  }
136
122
 
137
123
  public startNewEpoch(epochNumber: number, firstBlockNumber: number, totalNumBlocks: number) {
@@ -210,6 +196,22 @@ export class ProvingOrchestrator implements EpochProver {
210
196
  BigInt(startArchiveSnapshot.nextAvailableLeafIndex - 1),
211
197
  );
212
198
 
199
+ const partial = new PartialStateReference(
200
+ await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db),
201
+ await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db),
202
+ await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db),
203
+ );
204
+ const state = new StateReference(messageTreeSnapshot, partial);
205
+ // TODO: Construct the full previousBlockHeader.
206
+ const previousBlockHeader = BlockHeader.from({
207
+ lastArchive: startArchiveSnapshot,
208
+ contentCommitment: ContentCommitment.empty(),
209
+ state,
210
+ globalVariables: GlobalVariables.empty(),
211
+ totalFees: Fr.ZERO,
212
+ totalManaUsed: Fr.ZERO,
213
+ });
214
+
213
215
  const blockProvingState = this.provingState!.startNewBlock(
214
216
  globalVariables,
215
217
  l1ToL2MessagesPadded,
@@ -218,6 +220,7 @@ export class ProvingOrchestrator implements EpochProver {
218
220
  messageTreeSnapshotAfterInsertion,
219
221
  startArchiveSnapshot,
220
222
  newArchiveSiblingPath,
223
+ previousBlockHeader,
221
224
  previousBlockHash!,
222
225
  );
223
226
 
@@ -228,7 +231,7 @@ export class ProvingOrchestrator implements EpochProver {
228
231
  }
229
232
 
230
233
  /**
231
- * The interface to add simulated transactions to the scheduler
234
+ * The interface to add simulated transactions to the scheduler. This can only be called once per block.
232
235
  * @param txs - The transactions to be proven
233
236
  */
234
237
  @trackSpan('ProvingOrchestrator.addTxs', txs => ({
@@ -247,11 +250,15 @@ export class ProvingOrchestrator implements EpochProver {
247
250
  throw new Error(`Block proving state for ${blockNumber} not found`);
248
251
  }
249
252
 
253
+ if (provingState.totalNumTxs) {
254
+ throw new Error(`Block ${blockNumber} has been initialized with transactions.`);
255
+ }
256
+
250
257
  const numBlobFields = toNumBlobFields(txs);
251
- provingState.startNewBlock(Math.max(2, txs.length), numBlobFields);
258
+ provingState.startNewBlock(txs.length, numBlobFields);
252
259
 
253
260
  logger.info(
254
- `Adding ${txs.length} transactions with ${numBlobFields} blob fields to block ${provingState?.blockNumber}`,
261
+ `Adding ${txs.length} transactions with ${numBlobFields} blob fields to block ${provingState.blockNumber}`,
255
262
  );
256
263
  for (const tx of txs) {
257
264
  try {
@@ -263,26 +270,43 @@ export class ProvingOrchestrator implements EpochProver {
263
270
 
264
271
  logger.info(`Received transaction: ${tx.hash}`);
265
272
 
266
- if (tx.isEmpty) {
267
- logger.warn(`Ignoring empty transaction ${tx.hash} - it will not be added to this block`);
268
- continue;
269
- }
270
-
271
273
  const [hints, treeSnapshots] = await this.prepareTransaction(tx, provingState);
272
- this.enqueueFirstProofs(hints, treeSnapshots, tx, provingState);
274
+ const txProvingState = new TxProvingState(tx, hints, treeSnapshots);
275
+ const txIndex = provingState.addNewTx(txProvingState);
276
+ this.getOrEnqueueTube(provingState, txIndex);
277
+ if (txProvingState.requireAvmProof) {
278
+ logger.debug(`Enqueueing public VM for tx ${txIndex}`);
279
+ this.enqueueVM(provingState, txIndex);
280
+ }
273
281
  } catch (err: any) {
274
282
  throw new Error(`Error adding transaction ${tx.hash.toString()} to block ${blockNumber}: ${err.message}`, {
275
283
  cause: err,
276
284
  });
277
285
  }
278
286
  }
279
- if (provingState.transactionsReceived === provingState.totalNumTxs) {
280
- logger.verbose(`All transactions received for block ${provingState.globalVariables.blockNumber}.`);
287
+ }
288
+
289
+ /**
290
+ * Kickstarts tube circuits for the specified txs. These will be used during epoch proving.
291
+ * Note that if the tube circuits are not started this way, they will be started nontheless after processing.
292
+ */
293
+ @trackSpan('ProvingOrchestrator.startTubeCircuits')
294
+ public startTubeCircuits(txs: Tx[]) {
295
+ if (!this.provingState?.verifyState()) {
296
+ throw new Error(`Invalid proving state, call startNewEpoch before starting tube circuits`);
297
+ }
298
+ for (const tx of txs) {
299
+ const txHash = tx.getTxHash().toString();
300
+ const tubeInputs = new TubeInputs(tx.clientIvcProof);
301
+ const tubeProof = promiseWithResolvers<ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>>();
302
+ logger.debug(`Starting tube circuit for tx ${txHash}`);
303
+ this.doEnqueueTube(txHash, tubeInputs, proof => tubeProof.resolve(proof));
304
+ this.provingState?.cachedTubeProofs.set(txHash, tubeProof.promise);
281
305
  }
282
306
  }
283
307
 
284
308
  /**
285
- * Marks the block as full and pads it if required, no more transactions will be accepted.
309
+ * Marks the block as completed.
286
310
  * Computes the block header and updates the archive tree.
287
311
  */
288
312
  @trackSpan('ProvingOrchestrator.setBlockCompleted', (blockNumber: number) => ({
@@ -296,50 +320,14 @@ export class ProvingOrchestrator implements EpochProver {
296
320
 
297
321
  if (!provingState.spongeBlobState) {
298
322
  // 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);
323
+ // We will have 0 txs and no blob fields.
324
+ provingState.startNewBlock(0, 0);
301
325
  }
302
326
 
303
327
  if (!provingState.verifyState()) {
304
328
  throw new Error(`Block proving failed: ${provingState.error}`);
305
329
  }
306
330
 
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
331
  // And build the block header
344
332
  logger.verbose(`Block ${blockNumber} completed. Assembling header.`);
345
333
  await this.buildBlock(provingState, expectedHeader);
@@ -358,73 +346,9 @@ export class ProvingOrchestrator implements EpochProver {
358
346
  return block;
359
347
  }
360
348
 
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
349
  private async buildBlock(provingState: BlockProvingState, expectedHeader?: BlockHeader) {
426
350
  // 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);
351
+ const txs = provingState.allTxs.map(a => a.processedTx);
428
352
 
429
353
  // Get db for this block
430
354
  const db = this.dbs.get(provingState.blockNumber)!;
@@ -468,77 +392,6 @@ export class ProvingOrchestrator implements EpochProver {
468
392
  }
469
393
  }
470
394
 
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
395
  /**
543
396
  * Cancel any further proving
544
397
  */
@@ -550,45 +403,6 @@ export class ProvingOrchestrator implements EpochProver {
550
403
  this.provingState?.cancel();
551
404
  }
552
405
 
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
406
  /**
593
407
  * Returns the proof for the current epoch.
594
408
  */
@@ -597,23 +411,19 @@ export class ProvingOrchestrator implements EpochProver {
597
411
  throw new Error(`Invalid proving state, an epoch must be proven before it can be finalised`);
598
412
  }
599
413
 
600
- await this.padEpoch();
601
-
602
414
  const result = await this.provingPromise!;
603
415
  if (result.status === 'failure') {
604
416
  throw new Error(`Epoch proving failed: ${result.reason}`);
605
417
  }
606
418
 
607
- if (!this.provingState.rootRollupPublicInputs || !this.provingState.finalProof) {
608
- throw new Error(`Invalid proving state, missing root rollup public inputs or final proof`);
609
- }
419
+ const epochProofResult = this.provingState.getEpochProofResult();
610
420
 
611
421
  pushTestData('epochProofResult', {
612
- proof: this.provingState.finalProof.toString(),
613
- publicInputs: this.provingState.rootRollupPublicInputs.toString(),
422
+ proof: epochProofResult.proof.toString(),
423
+ publicInputs: epochProofResult.publicInputs.toString(),
614
424
  });
615
425
 
616
- return { proof: this.provingState.finalProof, publicInputs: this.provingState.rootRollupPublicInputs };
426
+ return epochProofResult;
617
427
  }
618
428
 
619
429
  /**
@@ -630,21 +440,6 @@ export class ProvingOrchestrator implements EpochProver {
630
440
  return txInputs;
631
441
  }
632
442
 
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
443
  /**
649
444
  * Enqueue a job to be scheduled
650
445
  * @param provingState - The proving state object being operated on
@@ -712,10 +507,10 @@ export class ProvingOrchestrator implements EpochProver {
712
507
  [Attributes.TX_HASH]: tx.hash.toString(),
713
508
  }))
714
509
  private async prepareBaseRollupInputs(
715
- provingState: BlockProvingState | undefined,
510
+ provingState: BlockProvingState,
716
511
  tx: ProcessedTx,
717
512
  ): Promise<[BaseRollupHints, TreeSnapshots] | undefined> {
718
- if (!provingState?.verifyState() || !provingState.spongeBlobState) {
513
+ if (!provingState.verifyState() || !provingState.spongeBlobState) {
719
514
  logger.debug('Not preparing base rollup inputs, state invalid');
720
515
  return;
721
516
  }
@@ -728,9 +523,7 @@ export class ProvingOrchestrator implements EpochProver {
728
523
  buildBaseRollupHints(tx, provingState.globalVariables, db, provingState.spongeBlobState),
729
524
  );
730
525
 
731
- if (!tx.isEmpty) {
732
- this.metrics.recordBaseRollupInputs(ms);
733
- }
526
+ this.metrics.recordBaseRollupInputs(ms);
734
527
 
735
528
  const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map(
736
529
  async (id: MerkleTreeId) => {
@@ -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,40 +541,34 @@ 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
- logger.debug(
762
- `Enqueuing deferred proving base rollup${
763
- processedTx.isEmpty ? ' with padding tx' : ''
764
- } for ${processedTx.hash.toString()}`,
765
- );
554
+ logger.debug(`Enqueuing deferred proving base rollup for ${processedTx.hash.toString()}`);
766
555
 
767
556
  this.deferredProving(
768
557
  provingState,
769
558
  wrapCallbackInSpan(
770
559
  this.tracer,
771
560
  `ProvingOrchestrator.prover.${
772
- rollupType === 'private-base-rollup' ? 'getPrivateBaseRollupProof' : 'getPublicBaseRollupProof'
561
+ inputs instanceof PrivateBaseRollupInputs ? 'getPrivateBaseRollupProof' : 'getPublicBaseRollupProof'
773
562
  }`,
774
563
  {
775
564
  [Attributes.TX_HASH]: processedTx.hash.toString(),
776
565
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
777
- [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType satisfies CircuitName,
566
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
778
567
  },
779
568
  signal => {
780
- if (rollupType === 'private-base-rollup') {
781
- const inputs = txProvingState.getPrivateBaseInputs();
569
+ if (inputs instanceof PrivateBaseRollupInputs) {
782
570
  return this.prover.getPrivateBaseRollupProof(inputs, signal, provingState.epochNumber);
783
571
  } else {
784
- const inputs = txProvingState.getPublicBaseInputs();
785
572
  return this.prover.getPublicBaseRollupProof(inputs, signal, provingState.epochNumber);
786
573
  }
787
574
  },
@@ -789,26 +576,54 @@ export class ProvingOrchestrator implements EpochProver {
789
576
  result => {
790
577
  logger.debug(`Completed proof for ${rollupType} for tx ${processedTx.hash.toString()}`);
791
578
  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
- ]);
579
+ const leafLocation = provingState.setBaseRollupProof(txIndex, result);
580
+ if (provingState.totalNumTxs === 1) {
581
+ this.checkAndEnqueueBlockRootRollup(provingState);
582
+ } else {
583
+ this.checkAndEnqueueNextMergeRollup(provingState, leafLocation);
584
+ }
798
585
  },
799
586
  );
800
587
  }
801
588
 
802
- // Enqueues the tube circuit for a given transaction index
589
+ // Enqueues the tube circuit for a given transaction index, or reuses the one already enqueued
803
590
  // 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()) {
591
+ private getOrEnqueueTube(provingState: BlockProvingState, txIndex: number) {
592
+ if (!provingState.verifyState()) {
806
593
  logger.debug('Not running tube circuit, state invalid');
807
594
  return;
808
595
  }
809
596
 
810
597
  const txProvingState = provingState.getTxProvingState(txIndex);
598
+ const txHash = txProvingState.processedTx.hash.toString();
599
+
600
+ const handleResult = (result: ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>) => {
601
+ logger.debug(`Got tube proof for tx index: ${txIndex}`, { txHash });
602
+ txProvingState.setTubeProof(result);
603
+ this.provingState?.cachedTubeProofs.delete(txHash);
604
+ this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
605
+ };
606
+
607
+ if (this.provingState?.cachedTubeProofs.has(txHash)) {
608
+ logger.debug(`Tube proof already enqueued for tx index: ${txIndex}`, { txHash });
609
+ void this.provingState!.cachedTubeProofs.get(txHash)!.then(handleResult);
610
+ return;
611
+ }
612
+
811
613
  logger.debug(`Enqueuing tube circuit for tx index: ${txIndex}`);
614
+ this.doEnqueueTube(txHash, txProvingState.getTubeInputs(), handleResult);
615
+ }
616
+
617
+ private doEnqueueTube(
618
+ txHash: string,
619
+ inputs: TubeInputs,
620
+ handler: (result: ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>) => void,
621
+ provingState: EpochProvingState | BlockProvingState = this.provingState!,
622
+ ) {
623
+ if (!provingState?.verifyState()) {
624
+ logger.debug('Not running tube circuit, state invalid');
625
+ return;
626
+ }
812
627
 
813
628
  this.deferredProving(
814
629
  provingState,
@@ -816,35 +631,25 @@ export class ProvingOrchestrator implements EpochProver {
816
631
  this.tracer,
817
632
  'ProvingOrchestrator.prover.getTubeProof',
818
633
  {
819
- [Attributes.TX_HASH]: txProvingState.processedTx.hash.toString(),
634
+ [Attributes.TX_HASH]: txHash,
820
635
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
821
636
  [Attributes.PROTOCOL_CIRCUIT_NAME]: 'tube-circuit' satisfies CircuitName,
822
637
  },
823
- signal => {
824
- const inputs = txProvingState.getTubeInputs();
825
- return this.prover.getTubeProof(inputs, signal, provingState.epochNumber);
826
- },
638
+ signal => this.prover.getTubeProof(inputs, signal, this.provingState!.epochNumber),
827
639
  ),
828
- result => {
829
- logger.debug(`Completed tube proof for tx index: ${txIndex}`);
830
- txProvingState.assignTubeProof(result);
831
- this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
832
- },
640
+ handler,
833
641
  );
834
642
  }
835
643
 
836
644
  // Executes the merge rollup circuit and stored the output as intermediate state for the parent merge/block root circuit
837
645
  // 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
- );
646
+ private enqueueMergeRollup(provingState: BlockProvingState, location: TreeNodeLocation) {
647
+ if (!provingState.verifyState()) {
648
+ logger.debug('Not running merge rollup. State no longer valid.');
649
+ return;
650
+ }
651
+
652
+ const inputs = provingState.getMergeRollupInputs(location);
848
653
 
849
654
  this.deferredProving(
850
655
  provingState,
@@ -858,66 +663,27 @@ export class ProvingOrchestrator implements EpochProver {
858
663
  signal => this.prover.getMergeRollupProof(inputs, signal, provingState.epochNumber),
859
664
  ),
860
665
  result => {
861
- this.storeAndExecuteNextMergeLevel(provingState, level, index, [
862
- result.inputs,
863
- result.proof,
864
- result.verificationKey.keyAsFields,
865
- ]);
666
+ provingState.setMergeRollupProof(location, result);
667
+ this.checkAndEnqueueNextMergeRollup(provingState, location);
866
668
  },
867
669
  );
868
670
  }
869
671
 
870
672
  // Executes the block root rollup circuit
871
673
  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
674
  if (!provingState.verifyState()) {
877
675
  logger.debug('Not running block root rollup, state no longer valid');
878
676
  return;
879
677
  }
880
678
 
881
679
  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
680
 
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
- );
681
+ const { rollupType, inputs } = provingState.getBlockRootRollupTypeAndInputs(this.proverId);
893
682
 
894
- const previousRollupData: BlockRootRollupInputs['previousRollupData'] = makeTuple(2, i =>
895
- getPreviousRollupDataFromPublicInputs(
896
- mergeInputData.inputs[i]!,
897
- mergeInputData.proofs[i]!,
898
- mergeInputData.verificationKeys[i]!,
899
- ),
683
+ logger.debug(
684
+ `Enqueuing ${rollupType} for block ${provingState.blockNumber} with ${provingState.newL1ToL2Messages.length} l1 to l2 msgs.`,
900
685
  );
901
686
 
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
687
  this.deferredProving(
922
688
  provingState,
923
689
  wrapCallbackInSpan(
@@ -925,12 +691,21 @@ export class ProvingOrchestrator implements EpochProver {
925
691
  'ProvingOrchestrator.prover.getBlockRootRollupProof',
926
692
  {
927
693
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
928
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'block-root-rollup' satisfies CircuitName,
694
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
695
+ },
696
+ signal => {
697
+ if (inputs instanceof EmptyBlockRootRollupInputs) {
698
+ return this.prover.getEmptyBlockRootRollupProof(inputs, signal, provingState.epochNumber);
699
+ } else if (inputs instanceof SingleTxBlockRootRollupInputs) {
700
+ return this.prover.getSingleTxBlockRootRollupProof(inputs, signal, provingState.epochNumber);
701
+ } else {
702
+ return this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber);
703
+ }
929
704
  },
930
- signal => this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber),
931
705
  ),
932
706
  result => {
933
- const header = this.extractBlockHeaderFromPublicInputs(provingState, result.inputs);
707
+ provingState.setBlockRootRollupProof(result);
708
+ const header = provingState.buildHeaderFromProvingOutputs(logger);
934
709
  if (!header.hash().equals(provingState.block!.header.hash())) {
935
710
  logger.error(
936
711
  `Block header mismatch\nCircuit:${inspect(header)}\nComputed:${inspect(provingState.block!.header)}`,
@@ -938,29 +713,16 @@ export class ProvingOrchestrator implements EpochProver {
938
713
  provingState.reject(`Block header hash mismatch`);
939
714
  }
940
715
 
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}`);
716
+ logger.debug(`Completed ${rollupType} proof for block ${provingState.block!.number}`);
956
717
  // validatePartialState(result.inputs.end, tx.treeSnapshots); // TODO(palla/prover)
957
718
 
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
- ]);
719
+ const epochProvingState = this.provingState!;
720
+ const leafLocation = epochProvingState.setBlockRootRollupProof(provingState.index, result);
721
+ if (epochProvingState.totalNumBlocks === 1) {
722
+ this.enqueueEpochPadding(epochProvingState);
723
+ } else {
724
+ this.checkAndEnqueueNextBlockMergeRollup(epochProvingState, leafLocation);
725
+ }
964
726
  },
965
727
  );
966
728
  }
@@ -968,6 +730,11 @@ export class ProvingOrchestrator implements EpochProver {
968
730
  // Executes the base parity circuit and stores the intermediate state for the root parity circuit
969
731
  // Enqueues the root parity circuit if all inputs are available
970
732
  private enqueueBaseParityCircuit(provingState: BlockProvingState, inputs: BaseParityInputs, index: number) {
733
+ if (!provingState.verifyState()) {
734
+ logger.debug('Not running base parity. State no longer valid.');
735
+ return;
736
+ }
737
+
971
738
  this.deferredProving(
972
739
  provingState,
973
740
  wrapCallbackInSpan(
@@ -980,29 +747,30 @@ export class ProvingOrchestrator implements EpochProver {
980
747
  signal => this.prover.getBaseParityProof(inputs, signal, provingState.epochNumber),
981
748
  ),
982
749
  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
- }
750
+ provingState.setBaseParityProof(index, provingOutput);
751
+ this.checkAndEnqueueRootParityCircuit(provingState);
999
752
  },
1000
753
  );
1001
754
  }
1002
755
 
756
+ private checkAndEnqueueRootParityCircuit(provingState: BlockProvingState) {
757
+ if (!provingState.isReadyForRootParity()) {
758
+ return;
759
+ }
760
+
761
+ this.enqueueRootParityCircuit(provingState);
762
+ }
763
+
1003
764
  // Runs the root parity circuit ans stored the outputs
1004
765
  // Enqueues the root rollup proof if all inputs are available
1005
- private enqueueRootParityCircuit(provingState: BlockProvingState, inputs: RootParityInputs) {
766
+ private enqueueRootParityCircuit(provingState: BlockProvingState) {
767
+ if (!provingState.verifyState()) {
768
+ logger.debug('Not running root parity. State no longer valid.');
769
+ return;
770
+ }
771
+
772
+ const inputs = provingState.getRootParityInputs();
773
+
1006
774
  this.deferredProving(
1007
775
  provingState,
1008
776
  wrapCallbackInSpan(
@@ -1014,14 +782,8 @@ export class ProvingOrchestrator implements EpochProver {
1014
782
  },
1015
783
  signal => this.prover.getRootParityProof(inputs, signal, provingState.epochNumber),
1016
784
  ),
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;
785
+ result => {
786
+ provingState.setRootParityProof(result);
1025
787
  this.checkAndEnqueueBlockRootRollup(provingState);
1026
788
  },
1027
789
  );
@@ -1029,16 +791,13 @@ export class ProvingOrchestrator implements EpochProver {
1029
791
 
1030
792
  // Executes the block merge rollup circuit and stored the output as intermediate state for the parent merge/block root circuit
1031
793
  // 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
- );
794
+ private enqueueBlockMergeRollup(provingState: EpochProvingState, location: TreeNodeLocation) {
795
+ if (!provingState.verifyState()) {
796
+ logger.debug('Not running block merge rollup. State no longer valid.');
797
+ return;
798
+ }
799
+
800
+ const inputs = provingState.getBlockMergeRollupInputs(location);
1042
801
 
1043
802
  this.deferredProving(
1044
803
  provingState,
@@ -1052,34 +811,51 @@ export class ProvingOrchestrator implements EpochProver {
1052
811
  signal => this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber),
1053
812
  ),
1054
813
  result => {
1055
- this.storeAndExecuteNextBlockMergeLevel(provingState, level, index, [
1056
- result.inputs,
1057
- result.proof,
1058
- result.verificationKey.keyAsFields,
1059
- ]);
814
+ provingState.setBlockMergeRollupProof(location, result);
815
+ this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
816
+ },
817
+ );
818
+ }
819
+
820
+ private enqueueEpochPadding(provingState: EpochProvingState) {
821
+ if (!provingState.verifyState()) {
822
+ logger.debug('Not running epoch padding. State no longer valid.');
823
+ return;
824
+ }
825
+
826
+ logger.debug('Padding epoch proof with an empty block root proof.');
827
+
828
+ const inputs = provingState.getPaddingBlockRootInputs(this.proverId);
829
+
830
+ this.deferredProving(
831
+ provingState,
832
+ wrapCallbackInSpan(
833
+ this.tracer,
834
+ 'ProvingOrchestrator.prover.getEmptyBlockRootRollupProof',
835
+ {
836
+ [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
837
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'empty-block-root-rollup' satisfies CircuitName,
838
+ },
839
+ signal => this.prover.getEmptyBlockRootRollupProof(inputs, signal, provingState.epochNumber),
840
+ ),
841
+ result => {
842
+ logger.debug('Completed proof for padding block root.');
843
+ provingState.setPaddingBlockRootProof(result);
844
+ this.checkAndEnqueueRootRollup(provingState);
1060
845
  },
1061
846
  );
1062
847
  }
1063
848
 
1064
849
  // Executes the root rollup circuit
1065
- private enqueueRootRollup(provingState: EpochProvingState | undefined) {
1066
- if (!provingState?.verifyState()) {
850
+ private enqueueRootRollup(provingState: EpochProvingState) {
851
+ if (!provingState.verifyState()) {
1067
852
  logger.debug('Not running root rollup, state no longer valid');
1068
853
  return;
1069
854
  }
1070
855
 
1071
856
  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
- );
857
+
858
+ const inputs = provingState.getRootRollupInputs(this.proverId);
1083
859
 
1084
860
  this.deferredProving(
1085
861
  provingState,
@@ -1094,15 +870,27 @@ export class ProvingOrchestrator implements EpochProver {
1094
870
  ),
1095
871
  result => {
1096
872
  logger.verbose(`Orchestrator completed root rollup for epoch ${provingState.epochNumber}`);
1097
- provingState.rootRollupPublicInputs = result.inputs;
1098
- provingState.finalProof = result.proof.binaryProof;
873
+ provingState.setRootRollupProof(result);
1099
874
  provingState.resolve({ status: 'success' });
1100
875
  },
1101
876
  );
1102
877
  }
1103
878
 
879
+ private checkAndEnqueueNextMergeRollup(provingState: BlockProvingState, currentLocation: TreeNodeLocation) {
880
+ if (!provingState.isReadyForMergeRollup(currentLocation)) {
881
+ return;
882
+ }
883
+
884
+ const parentLocation = provingState.getParentLocation(currentLocation);
885
+ if (parentLocation.level === 0) {
886
+ this.checkAndEnqueueBlockRootRollup(provingState);
887
+ } else {
888
+ this.enqueueMergeRollup(provingState, parentLocation);
889
+ }
890
+ }
891
+
1104
892
  private checkAndEnqueueBlockRootRollup(provingState: BlockProvingState) {
1105
- if (!provingState?.isReadyForBlockRootRollup()) {
893
+ if (!provingState.isReadyForBlockRootRollup()) {
1106
894
  logger.debug('Not ready for root rollup');
1107
895
  return;
1108
896
  }
@@ -1126,94 +914,26 @@ export class ProvingOrchestrator implements EpochProver {
1126
914
  this.enqueueBlockRootRollup(provingState);
1127
915
  }
1128
916
 
1129
- private checkAndEnqueueRootRollup(provingState: EpochProvingState | undefined) {
1130
- if (!provingState?.isReadyForRootRollup()) {
1131
- logger.debug('Not ready for root rollup');
917
+ private checkAndEnqueueNextBlockMergeRollup(provingState: EpochProvingState, currentLocation: TreeNodeLocation) {
918
+ if (!provingState.isReadyForBlockMerge(currentLocation)) {
1132
919
  return;
1133
920
  }
1134
- this.enqueueRootRollup(provingState);
1135
- }
1136
921
 
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);
922
+ const parentLocation = provingState.getParentLocation(currentLocation);
923
+ if (parentLocation.level === 0) {
924
+ this.checkAndEnqueueRootRollup(provingState);
1169
925
  } else {
1170
- // onto the next merge level
1171
- this.enqueueMergeRollup(provingState, mergeLevel, indexWithinMergeLevel, nextMergeInputData);
926
+ this.enqueueBlockMergeRollup(provingState, parentLocation);
1172
927
  }
1173
928
  }
1174
929
 
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}`);
930
+ private checkAndEnqueueRootRollup(provingState: EpochProvingState) {
931
+ if (!provingState.isReadyForRootRollup()) {
932
+ logger.debug('Not ready for root rollup');
1208
933
  return;
1209
934
  }
1210
935
 
1211
- if (mergeLevel === 0n) {
1212
- this.checkAndEnqueueRootRollup(provingState);
1213
- } else {
1214
- // onto the next merge level
1215
- this.enqueueBlockMergeRollup(provingState, mergeLevel, indexWithinMergeLevel, nextMergeInputData);
1216
- }
936
+ this.enqueueRootRollup(provingState);
1217
937
  }
1218
938
 
1219
939
  /**
@@ -1222,8 +942,8 @@ export class ProvingOrchestrator implements EpochProver {
1222
942
  * @param provingState - The proving state being operated on
1223
943
  * @param txIndex - The index of the transaction being proven
1224
944
  */
1225
- private enqueueVM(provingState: BlockProvingState | undefined, txIndex: number) {
1226
- if (!provingState?.verifyState()) {
945
+ private enqueueVM(provingState: BlockProvingState, txIndex: number) {
946
+ if (!provingState.verifyState()) {
1227
947
  logger.debug(`Not running VM circuit as state is no longer valid`);
1228
948
  return;
1229
949
  }
@@ -1263,7 +983,7 @@ export class ProvingOrchestrator implements EpochProver {
1263
983
 
1264
984
  this.deferredProving(provingState, doAvmProving, proofAndVk => {
1265
985
  logger.debug(`Proven VM for tx index: ${txIndex}`);
1266
- txProvingState.assignAvmProof(proofAndVk);
986
+ txProvingState.setAvmProof(proofAndVk);
1267
987
  this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
1268
988
  });
1269
989
  }