@aztec/prover-client 3.0.0-canary.a9708bd → 3.0.0-devnet.3

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 (72) hide show
  1. package/dest/block-factory/light.d.ts +5 -3
  2. package/dest/block-factory/light.d.ts.map +1 -1
  3. package/dest/block-factory/light.js +16 -9
  4. package/dest/mocks/fixtures.d.ts +4 -1
  5. package/dest/mocks/fixtures.d.ts.map +1 -1
  6. package/dest/mocks/fixtures.js +31 -3
  7. package/dest/mocks/test_context.d.ts +32 -9
  8. package/dest/mocks/test_context.d.ts.map +1 -1
  9. package/dest/mocks/test_context.js +78 -22
  10. package/dest/orchestrator/block-building-helpers.d.ts +33 -31
  11. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  12. package/dest/orchestrator/block-building-helpers.js +126 -137
  13. package/dest/orchestrator/block-proving-state.d.ts +60 -53
  14. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  15. package/dest/orchestrator/block-proving-state.js +214 -187
  16. package/dest/orchestrator/checkpoint-proving-state.d.ts +63 -0
  17. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -0
  18. package/dest/orchestrator/checkpoint-proving-state.js +211 -0
  19. package/dest/orchestrator/epoch-proving-state.d.ts +34 -28
  20. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  21. package/dest/orchestrator/epoch-proving-state.js +125 -81
  22. package/dest/orchestrator/orchestrator.d.ts +26 -25
  23. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  24. package/dest/orchestrator/orchestrator.js +350 -218
  25. package/dest/orchestrator/tx-proving-state.d.ts +11 -9
  26. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  27. package/dest/orchestrator/tx-proving-state.js +26 -23
  28. package/dest/prover-client/server-epoch-prover.d.ts +8 -7
  29. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
  30. package/dest/prover-client/server-epoch-prover.js +7 -7
  31. package/dest/proving_broker/broker_prover_facade.d.ts +20 -15
  32. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  33. package/dest/proving_broker/broker_prover_facade.js +36 -21
  34. package/dest/proving_broker/config.d.ts +8 -8
  35. package/dest/proving_broker/config.js +5 -5
  36. package/dest/proving_broker/factory.js +1 -1
  37. package/dest/proving_broker/fixtures.js +1 -1
  38. package/dest/proving_broker/proof_store/index.d.ts +1 -0
  39. package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
  40. package/dest/proving_broker/proof_store/index.js +1 -0
  41. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  42. package/dest/proving_broker/proving_broker.js +29 -18
  43. package/dest/proving_broker/proving_broker_database/persisted.js +5 -5
  44. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  45. package/dest/proving_broker/proving_job_controller.js +38 -18
  46. package/dest/test/mock_prover.d.ts +22 -17
  47. package/dest/test/mock_prover.d.ts.map +1 -1
  48. package/dest/test/mock_prover.js +35 -20
  49. package/package.json +16 -17
  50. package/src/block-factory/light.ts +35 -9
  51. package/src/mocks/fixtures.ts +39 -11
  52. package/src/mocks/test_context.ts +137 -31
  53. package/src/orchestrator/block-building-helpers.ts +213 -211
  54. package/src/orchestrator/block-proving-state.ts +235 -245
  55. package/src/orchestrator/checkpoint-proving-state.ts +299 -0
  56. package/src/orchestrator/epoch-proving-state.ts +169 -126
  57. package/src/orchestrator/orchestrator.ts +519 -286
  58. package/src/orchestrator/tx-proving-state.ts +45 -43
  59. package/src/prover-client/server-epoch-prover.ts +26 -16
  60. package/src/proving_broker/broker_prover_facade.ts +157 -88
  61. package/src/proving_broker/config.ts +7 -7
  62. package/src/proving_broker/factory.ts +1 -1
  63. package/src/proving_broker/fixtures.ts +1 -1
  64. package/src/proving_broker/proof_store/index.ts +1 -0
  65. package/src/proving_broker/proving_broker.ts +36 -18
  66. package/src/proving_broker/proving_broker_database/persisted.ts +5 -5
  67. package/src/proving_broker/proving_job_controller.ts +38 -18
  68. package/src/test/mock_prover.ts +142 -62
  69. package/dest/bin/get-proof-inputs.d.ts +0 -2
  70. package/dest/bin/get-proof-inputs.d.ts.map +0 -1
  71. package/dest/bin/get-proof-inputs.js +0 -51
  72. package/src/bin/get-proof-inputs.ts +0 -59
@@ -1,12 +1,12 @@
1
- import { BlobAccumulatorPublicInputs, FinalBlobBatchingChallenges } from '@aztec/blob-lib';
1
+ import { BatchedBlob, FinalBlobBatchingChallenges, SpongeBlob } from '@aztec/blob-lib';
2
2
  import {
3
3
  L1_TO_L2_MSG_SUBTREE_HEIGHT,
4
- L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH,
4
+ L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
5
+ NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH,
5
6
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
6
7
  NUM_BASE_PARITY_PER_ROOT_PARITY,
7
- type TUBE_PROOF_LENGTH,
8
8
  } from '@aztec/constants';
9
- import { padArrayEnd, times } from '@aztec/foundation/collection';
9
+ import { padArrayEnd } from '@aztec/foundation/collection';
10
10
  import { AbortError } from '@aztec/foundation/error';
11
11
  import { Fr } from '@aztec/foundation/fields';
12
12
  import { createLogger } from '@aztec/foundation/log';
@@ -15,27 +15,33 @@ import { assertLength } from '@aztec/foundation/serialize';
15
15
  import { pushTestData } from '@aztec/foundation/testing';
16
16
  import { elapsed } from '@aztec/foundation/timer';
17
17
  import type { TreeNodeLocation } from '@aztec/foundation/trees';
18
- import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
19
18
  import { readAvmMinimalPublicTxInputsFromFile } from '@aztec/simulator/public/fixtures';
20
- import { EthAddress, L2Block } from '@aztec/stdlib/block';
19
+ import { EthAddress, createBlockEndMarker } from '@aztec/stdlib/block';
21
20
  import type {
22
21
  EpochProver,
23
22
  ForkMerkleTreeOperations,
24
23
  MerkleTreeWriteOperations,
25
- ProofAndVerificationKey,
24
+ PublicInputsAndRecursiveProof,
26
25
  ServerCircuitProver,
27
26
  } from '@aztec/stdlib/interfaces/server';
28
- import { BaseParityInputs } from '@aztec/stdlib/parity';
27
+ import type { Proof } from '@aztec/stdlib/proofs';
29
28
  import {
30
29
  type BaseRollupHints,
31
- EmptyBlockRootRollupInputs,
32
- PrivateBaseRollupInputs,
33
- SingleTxBlockRootRollupInputs,
34
- TubeInputs,
30
+ BlockRootEmptyTxFirstRollupPrivateInputs,
31
+ BlockRootFirstRollupPrivateInputs,
32
+ BlockRootSingleTxFirstRollupPrivateInputs,
33
+ BlockRootSingleTxRollupPrivateInputs,
34
+ CheckpointConstantData,
35
+ CheckpointRootSingleBlockRollupPrivateInputs,
36
+ PrivateTxBaseRollupPrivateInputs,
37
+ PublicTubePrivateInputs,
38
+ PublicTubePublicInputs,
39
+ RootRollupPublicInputs,
35
40
  } from '@aztec/stdlib/rollup';
36
41
  import type { CircuitName } from '@aztec/stdlib/stats';
37
42
  import { type AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
38
- import { type BlockHeader, type GlobalVariables, type ProcessedTx, type Tx, toNumBlobFields } from '@aztec/stdlib/tx';
43
+ import type { BlockHeader, ProcessedTx, Tx } from '@aztec/stdlib/tx';
44
+ import type { UInt64 } from '@aztec/stdlib/types';
39
45
  import {
40
46
  Attributes,
41
47
  type TelemetryClient,
@@ -48,8 +54,10 @@ import {
48
54
  import { inspect } from 'util';
49
55
 
50
56
  import {
51
- buildHeaderAndBodyFromTxs,
57
+ buildBlockHeaderFromTxs,
58
+ buildHeaderFromCircuitOutputs,
52
59
  getLastSiblingPath,
60
+ getPublicTubePrivateInputsFromTx,
53
61
  getRootTreeSiblingPath,
54
62
  getSubtreeSiblingPath,
55
63
  getTreeSnapshot,
@@ -58,6 +66,7 @@ import {
58
66
  validateTx,
59
67
  } from './block-building-helpers.js';
60
68
  import type { BlockProvingState } from './block-proving-state.js';
69
+ import type { CheckpointProvingState } from './checkpoint-proving-state.js';
61
70
  import { EpochProvingState, type ProvingResult, type TreeSnapshots } from './epoch-proving-state.js';
62
71
  import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
63
72
  import { TxProvingState } from './tx-proving-state.js';
@@ -110,80 +119,141 @@ export class ProvingOrchestrator implements EpochProver {
110
119
 
111
120
  public startNewEpoch(
112
121
  epochNumber: number,
113
- firstBlockNumber: number,
114
- totalNumBlocks: number,
122
+ totalNumCheckpoints: number,
115
123
  finalBlobBatchingChallenges: FinalBlobBatchingChallenges,
116
124
  ) {
125
+ if (this.provingState?.verifyState()) {
126
+ throw new Error(
127
+ `Cannot start epoch ${epochNumber} when epoch ${this.provingState.epochNumber} is still being processed.`,
128
+ );
129
+ }
130
+
117
131
  const { promise: _promise, resolve, reject } = promiseWithResolvers<ProvingResult>();
118
132
  const promise = _promise.catch((reason): ProvingResult => ({ status: 'failure', reason }));
119
- if (totalNumBlocks <= 0 || !Number.isInteger(totalNumBlocks)) {
120
- throw new Error(`Invalid number of blocks for epoch (got ${totalNumBlocks})`);
121
- }
122
- logger.info(`Starting epoch ${epochNumber} with ${totalNumBlocks} blocks`);
133
+ logger.info(`Starting epoch ${epochNumber} with ${totalNumCheckpoints} checkpoints.`);
123
134
  this.provingState = new EpochProvingState(
124
135
  epochNumber,
125
- firstBlockNumber,
126
- totalNumBlocks,
136
+ totalNumCheckpoints,
127
137
  finalBlobBatchingChallenges,
138
+ provingState => this.checkAndEnqueueCheckpointRootRollup(provingState),
128
139
  resolve,
129
140
  reject,
130
141
  );
131
142
  this.provingPromise = promise;
132
143
  }
133
144
 
145
+ public async startNewCheckpoint(
146
+ checkpointIndex: number,
147
+ constants: CheckpointConstantData,
148
+ l1ToL2Messages: Fr[],
149
+ totalNumBlocks: number,
150
+ totalNumBlobFields: number,
151
+ headerOfLastBlockInPreviousCheckpoint: BlockHeader,
152
+ ) {
153
+ if (!this.provingState) {
154
+ throw new Error('Empty epoch proving state. Call startNewEpoch before starting a checkpoint.');
155
+ }
156
+
157
+ if (!this.provingState.isAcceptingCheckpoints()) {
158
+ throw new Error(`Epoch not accepting further checkpoints.`);
159
+ }
160
+
161
+ // Fork world state at the end of the immediately previous block.
162
+ const lastBlockNumber = headerOfLastBlockInPreviousCheckpoint.globalVariables.blockNumber;
163
+ const db = await this.dbProvider.fork(lastBlockNumber);
164
+
165
+ const firstBlockNumber = lastBlockNumber + 1;
166
+ this.dbs.set(firstBlockNumber, db);
167
+
168
+ // Get archive sibling path before any block in this checkpoint lands.
169
+ const lastArchiveSiblingPath = await getLastSiblingPath(MerkleTreeId.ARCHIVE, db);
170
+
171
+ // Insert all the l1 to l2 messages into the db. And get the states before and after the insertion.
172
+ const {
173
+ lastL1ToL2MessageTreeSnapshot,
174
+ lastL1ToL2MessageSubtreeRootSiblingPath,
175
+ newL1ToL2MessageTreeSnapshot,
176
+ newL1ToL2MessageSubtreeRootSiblingPath,
177
+ } = await this.updateL1ToL2MessageTree(l1ToL2Messages, db);
178
+
179
+ this.provingState.startNewCheckpoint(
180
+ checkpointIndex,
181
+ constants,
182
+ totalNumBlocks,
183
+ totalNumBlobFields,
184
+ headerOfLastBlockInPreviousCheckpoint,
185
+ lastArchiveSiblingPath,
186
+ l1ToL2Messages,
187
+ lastL1ToL2MessageTreeSnapshot,
188
+ lastL1ToL2MessageSubtreeRootSiblingPath,
189
+ newL1ToL2MessageTreeSnapshot,
190
+ newL1ToL2MessageSubtreeRootSiblingPath,
191
+ );
192
+ }
193
+
134
194
  /**
135
195
  * Starts off a new block
136
- * @param globalVariables - The global variables for the block
137
- * @param l1ToL2Messages - The l1 to l2 messages for the block
138
- * @returns A proving ticket, containing a promise notifying of proving completion
196
+ * @param blockNumber - The block number
197
+ * @param timestamp - The timestamp of the block. This is only required for constructing the private inputs for the
198
+ * block that doesn't have any txs.
199
+ * @param totalNumTxs - The total number of txs in the block
139
200
  */
140
- @trackSpan('ProvingOrchestrator.startNewBlock', globalVariables => ({
141
- [Attributes.BLOCK_NUMBER]: globalVariables.blockNumber,
201
+ @trackSpan('ProvingOrchestrator.startNewBlock', blockNumber => ({
202
+ [Attributes.BLOCK_NUMBER]: blockNumber,
142
203
  }))
143
- public async startNewBlock(globalVariables: GlobalVariables, l1ToL2Messages: Fr[], previousBlockHeader: BlockHeader) {
204
+ public async startNewBlock(blockNumber: number, timestamp: UInt64, totalNumTxs: number) {
144
205
  if (!this.provingState) {
145
- throw new Error(`Invalid proving state, call startNewEpoch before starting a block`);
206
+ throw new Error('Empty epoch proving state. Call startNewEpoch before starting a block.');
146
207
  }
147
208
 
148
- if (!this.provingState?.isAcceptingBlocks()) {
149
- throw new Error(`Epoch not accepting further blocks`);
209
+ const checkpointProvingState = this.provingState.getCheckpointProvingStateByBlockNumber(blockNumber);
210
+ if (!checkpointProvingState) {
211
+ throw new Error(`Checkpoint not started. Call startNewCheckpoint first.`);
150
212
  }
151
213
 
152
- logger.info(`Starting block ${globalVariables.blockNumber} for slot ${globalVariables.slotNumber.toNumber()}`);
214
+ if (!checkpointProvingState.isAcceptingBlocks()) {
215
+ throw new Error(`Checkpoint not accepting further blocks.`);
216
+ }
153
217
 
154
- // Fork world state at the end of the immediately previous block
155
- const db = await this.dbProvider.fork(globalVariables.blockNumber - 1);
156
- this.dbs.set(globalVariables.blockNumber, db);
218
+ const constants = checkpointProvingState.constants;
219
+ logger.info(`Starting block ${blockNumber} for slot ${constants.slotNumber.toNumber()}.`);
157
220
 
158
- // we start the block by enqueueing all of the base parity circuits
159
- const {
160
- l1ToL2MessageTreeSnapshot,
161
- l1ToL2MessageSubtreeSiblingPath,
162
- l1ToL2MessageTreeSnapshotAfterInsertion,
163
- baseParityInputs,
164
- } = await this.prepareBaseParityInputs(l1ToL2Messages, db);
165
-
166
- // Get archive snapshot before this block lands
167
- const lastArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
168
- const lastArchiveSiblingPath = await getLastSiblingPath(MerkleTreeId.ARCHIVE, db);
169
- const newArchiveSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.ARCHIVE, db);
221
+ // Fork the db only when it's not already set. The db for the first block is set in `startNewCheckpoint`.
222
+ if (!this.dbs.has(blockNumber)) {
223
+ // Fork world state at the end of the immediately previous block
224
+ const db = await this.dbProvider.fork(blockNumber - 1);
225
+ this.dbs.set(blockNumber, db);
226
+ }
227
+ const db = this.dbs.get(blockNumber)!;
170
228
 
171
- const blockProvingState = this.provingState!.startNewBlock(
172
- globalVariables,
173
- l1ToL2Messages,
174
- l1ToL2MessageTreeSnapshot,
175
- l1ToL2MessageSubtreeSiblingPath,
176
- l1ToL2MessageTreeSnapshotAfterInsertion,
177
- lastArchive,
229
+ // Get archive snapshot and sibling path before any txs in this block lands.
230
+ const lastArchiveTreeSnapshot = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
231
+ const lastArchiveSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.ARCHIVE, db);
232
+
233
+ const blockProvingState = await checkpointProvingState.startNewBlock(
234
+ blockNumber,
235
+ timestamp,
236
+ totalNumTxs,
237
+ lastArchiveTreeSnapshot,
178
238
  lastArchiveSiblingPath,
179
- newArchiveSiblingPath,
180
- previousBlockHeader,
181
- this.proverId,
182
239
  );
183
240
 
184
- // Enqueue base parity circuits for the block
185
- for (let i = 0; i < baseParityInputs.length; i++) {
186
- this.enqueueBaseParityCircuit(blockProvingState, baseParityInputs[i], i);
241
+ // Enqueue base parity circuits for the first block in the checkpoint.
242
+ if (blockProvingState.index === 0) {
243
+ for (let i = 0; i < NUM_BASE_PARITY_PER_ROOT_PARITY; i++) {
244
+ this.enqueueBaseParityCircuit(checkpointProvingState, blockProvingState, i);
245
+ }
246
+ }
247
+
248
+ // Because `addTxs` won't be called for a block without txs, and that's where the sponge blob state is computed.
249
+ // We need to set its end sponge blob here, which will become the start sponge blob for the next block.
250
+ if (totalNumTxs === 0) {
251
+ const endSpongeBlob = blockProvingState.getStartSpongeBlob().clone();
252
+ await endSpongeBlob.absorb([createBlockEndMarker(0)]);
253
+ blockProvingState.setEndSpongeBlob(endSpongeBlob);
254
+
255
+ // And also try to accumulate the blobs as far as we can:
256
+ await this.provingState.setBlobAccumulators();
187
257
  }
188
258
  }
189
259
 
@@ -195,28 +265,40 @@ export class ProvingOrchestrator implements EpochProver {
195
265
  [Attributes.BLOCK_TXS_COUNT]: txs.length,
196
266
  }))
197
267
  public async addTxs(txs: ProcessedTx[]): Promise<void> {
268
+ if (!this.provingState) {
269
+ throw new Error(`Empty epoch proving state. Call startNewEpoch before adding txs.`);
270
+ }
271
+
198
272
  if (!txs.length) {
199
273
  // To avoid an ugly throw below. If we require an empty block, we can just call setBlockCompleted
200
274
  // on a block with no txs. We cannot do that here because we cannot find the blockNumber without any txs.
201
275
  logger.warn(`Provided no txs to orchestrator addTxs.`);
202
276
  return;
203
277
  }
278
+
204
279
  const blockNumber = txs[0].globalVariables.blockNumber;
205
- const provingState = this.provingState?.getBlockProvingStateByBlockNumber(blockNumber!);
280
+ const provingState = this.provingState.getBlockProvingStateByBlockNumber(blockNumber!);
206
281
  if (!provingState) {
207
- throw new Error(`Block proving state for ${blockNumber} not found`);
282
+ throw new Error(`Proving state for block ${blockNumber} not found. Call startNewBlock first.`);
283
+ }
284
+
285
+ if (provingState.totalNumTxs !== txs.length) {
286
+ throw new Error(
287
+ `Block ${blockNumber} should be filled with ${provingState.totalNumTxs} txs. Received ${txs.length} txs.`,
288
+ );
208
289
  }
209
290
 
210
- if (provingState.totalNumTxs) {
291
+ if (!provingState.isAcceptingTxs()) {
211
292
  throw new Error(`Block ${blockNumber} has been initialized with transactions.`);
212
293
  }
213
294
 
214
- const numBlobFields = toNumBlobFields(txs);
215
- provingState.startNewBlock(txs.length, numBlobFields);
295
+ logger.info(`Adding ${txs.length} transactions to block ${blockNumber}`);
296
+
297
+ const db = this.dbs.get(blockNumber)!;
298
+ const lastArchive = provingState.lastArchiveTreeSnapshot;
299
+ const newL1ToL2MessageTreeSnapshot = provingState.newL1ToL2MessageTreeSnapshot;
300
+ const spongeBlobState = provingState.getStartSpongeBlob().clone();
216
301
 
217
- logger.info(
218
- `Adding ${txs.length} transactions with ${numBlobFields} blob fields to block ${provingState.blockNumber}`,
219
- );
220
302
  for (const tx of txs) {
221
303
  try {
222
304
  if (!provingState.verifyState()) {
@@ -227,13 +309,30 @@ export class ProvingOrchestrator implements EpochProver {
227
309
 
228
310
  logger.info(`Received transaction: ${tx.hash}`);
229
311
 
230
- const [hints, treeSnapshots] = await this.prepareTransaction(tx, provingState);
231
- const txProvingState = new TxProvingState(tx, hints, treeSnapshots);
312
+ const startSpongeBlob = spongeBlobState.clone();
313
+ const [hints, treeSnapshots] = await this.prepareBaseRollupInputs(
314
+ tx,
315
+ lastArchive,
316
+ newL1ToL2MessageTreeSnapshot,
317
+ startSpongeBlob,
318
+ db,
319
+ );
320
+
321
+ if (!provingState.verifyState()) {
322
+ throw new Error(`Unable to add transaction, preparing base inputs failed`);
323
+ }
324
+
325
+ await spongeBlobState.absorb(tx.txEffect.toBlobFields());
326
+
327
+ const txProvingState = new TxProvingState(tx, hints, treeSnapshots, this.proverId.toField());
232
328
  const txIndex = provingState.addNewTx(txProvingState);
233
- this.getOrEnqueueTube(provingState, txIndex);
234
329
  if (txProvingState.requireAvmProof) {
330
+ this.getOrEnqueueTube(provingState, txIndex);
235
331
  logger.debug(`Enqueueing public VM for tx ${txIndex}`);
236
332
  this.enqueueVM(provingState, txIndex);
333
+ } else {
334
+ logger.debug(`Enqueueing base rollup for private-only tx ${txIndex}`);
335
+ this.enqueueBaseRollup(provingState, txIndex);
237
336
  }
238
337
  } catch (err: any) {
239
338
  throw new Error(`Error adding transaction ${tx.hash.toString()} to block ${blockNumber}: ${err.message}`, {
@@ -241,6 +340,13 @@ export class ProvingOrchestrator implements EpochProver {
241
340
  });
242
341
  }
243
342
  }
343
+
344
+ await spongeBlobState.absorb([createBlockEndMarker(txs.length)]);
345
+
346
+ provingState.setEndSpongeBlob(spongeBlobState);
347
+
348
+ // Txs have been added to the block. Now try to accumulate the blobs as far as we can:
349
+ await this.provingState.setBlobAccumulators();
244
350
  }
245
351
 
246
352
  /**
@@ -250,15 +356,21 @@ export class ProvingOrchestrator implements EpochProver {
250
356
  @trackSpan('ProvingOrchestrator.startTubeCircuits')
251
357
  public startTubeCircuits(txs: Tx[]) {
252
358
  if (!this.provingState?.verifyState()) {
253
- throw new Error(`Invalid proving state, call startNewEpoch before starting tube circuits`);
359
+ throw new Error(`Empty epoch proving state. call startNewEpoch before starting tube circuits.`);
254
360
  }
255
- for (const tx of txs) {
361
+ const publicTxs = txs.filter(tx => tx.data.forPublic);
362
+ for (const tx of publicTxs) {
256
363
  const txHash = tx.getTxHash().toString();
257
- const tubeInputs = new TubeInputs(!!tx.data.forPublic, tx.clientIvcProof);
258
- const tubeProof = promiseWithResolvers<ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>>();
364
+ const privateInputs = getPublicTubePrivateInputsFromTx(tx, this.proverId.toField());
365
+ const tubeProof =
366
+ promiseWithResolvers<
367
+ PublicInputsAndRecursiveProof<PublicTubePublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>
368
+ >();
259
369
  logger.debug(`Starting tube circuit for tx ${txHash}`);
260
- this.doEnqueueTube(txHash, tubeInputs, proof => tubeProof.resolve(proof));
261
- this.provingState?.cachedTubeProofs.set(txHash, tubeProof.promise);
370
+ this.doEnqueueTube(txHash, privateInputs, proof => {
371
+ tubeProof.resolve(proof);
372
+ });
373
+ this.provingState.cachedTubeProofs.set(txHash, tubeProof.promise);
262
374
  }
263
375
  return Promise.resolve();
264
376
  }
@@ -270,58 +382,50 @@ export class ProvingOrchestrator implements EpochProver {
270
382
  @trackSpan('ProvingOrchestrator.setBlockCompleted', (blockNumber: number) => ({
271
383
  [Attributes.BLOCK_NUMBER]: blockNumber,
272
384
  }))
273
- public async setBlockCompleted(blockNumber: number, expectedHeader?: BlockHeader): Promise<L2Block> {
385
+ public async setBlockCompleted(blockNumber: number, expectedHeader?: BlockHeader): Promise<BlockHeader> {
274
386
  const provingState = this.provingState?.getBlockProvingStateByBlockNumber(blockNumber);
275
387
  if (!provingState) {
276
388
  throw new Error(`Block proving state for ${blockNumber} not found`);
277
389
  }
278
390
 
279
- if (!provingState.spongeBlobState) {
280
- // If we are completing an empty block, initialize the provingState.
281
- // We will have 0 txs and no blob fields.
282
- provingState.startNewBlock(0, 0);
391
+ // Abort with specific error for the block if there's one.
392
+ const error = provingState.getError();
393
+ if (error) {
394
+ throw new Error(`Block proving failed: ${error}`);
283
395
  }
284
396
 
397
+ // Abort if the proving state is not valid due to errors occurred elsewhere.
285
398
  if (!provingState.verifyState()) {
286
- throw new Error(`Block proving failed: ${provingState.error}`);
399
+ throw new Error(`Invalid proving state when completing block ${blockNumber}.`);
400
+ }
401
+
402
+ if (provingState.isAcceptingTxs()) {
403
+ throw new Error(
404
+ `Block ${blockNumber} is still accepting txs. Call setBlockCompleted after all txs have been added.`,
405
+ );
287
406
  }
288
407
 
289
408
  // And build the block header
290
409
  logger.verbose(`Block ${blockNumber} completed. Assembling header.`);
291
- await this.buildBlock(provingState, expectedHeader);
410
+ const header = await this.buildL2BlockHeader(provingState, expectedHeader);
292
411
 
293
- logger.debug(`Accumulating blobs for ${blockNumber}`);
294
- await this.provingState?.setBlobAccumulators(blockNumber);
412
+ await this.verifyBuiltBlockAgainstSyncedState(provingState);
295
413
 
296
- // If the proofs were faster than the block building, then we need to try the block root rollup again here
297
- await this.checkAndEnqueueBlockRootRollup(provingState);
298
- return provingState.block!;
414
+ return header;
299
415
  }
300
416
 
301
- /** Returns the block as built for a given index. */
302
- public getBlock(index: number): L2Block {
303
- const block = this.provingState?.blocks[index]?.block;
304
- if (!block) {
305
- throw new Error(`Block at index ${index} not available`);
306
- }
307
- return block;
308
- }
417
+ private async buildL2BlockHeader(provingState: BlockProvingState, expectedHeader?: BlockHeader) {
418
+ // Collect all txs in this block to build the header. The function calling this has made sure that all txs have been added.
419
+ const txs = provingState.getProcessedTxs();
309
420
 
310
- private async buildBlock(provingState: BlockProvingState, expectedHeader?: BlockHeader) {
311
- // Collect all new nullifiers, commitments, and contracts from all txs in this block to build body
312
- const txs = provingState.allTxs.map(a => a.processedTx);
421
+ const startSpongeBlob = provingState.getStartSpongeBlob();
313
422
 
314
423
  // Get db for this block
315
424
  const db = this.dbs.get(provingState.blockNumber)!;
316
425
 
317
426
  // Given we've applied every change from this block, now assemble the block header
318
427
  // and update the archive tree, so we're ready to start processing the next block
319
- const { header, body } = await buildHeaderAndBodyFromTxs(
320
- txs,
321
- provingState.globalVariables,
322
- provingState.newL1ToL2Messages,
323
- db,
324
- );
428
+ const header = await buildBlockHeaderFromTxs(txs, provingState.getGlobalVariables(), startSpongeBlob, db);
325
429
 
326
430
  if (expectedHeader && !header.equals(expectedHeader)) {
327
431
  logger.error(`Block header mismatch: header=${header} expectedHeader=${expectedHeader}`);
@@ -333,26 +437,65 @@ export class ProvingOrchestrator implements EpochProver {
333
437
  );
334
438
  await db.updateArchive(header);
335
439
 
336
- // Assemble the L2 block
337
- const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
338
- const l2Block = new L2Block(newArchive, header, body);
339
-
340
- await this.verifyBuiltBlockAgainstSyncedState(l2Block, newArchive);
440
+ provingState.setBuiltBlockHeader(header);
341
441
 
342
- logger.verbose(`Orchestrator finalized block ${l2Block.number}`);
343
- provingState.setBlock(l2Block);
442
+ return header;
344
443
  }
345
444
 
346
445
  // Flagged as protected to disable in certain unit tests
347
- protected async verifyBuiltBlockAgainstSyncedState(l2Block: L2Block, newArchive: AppendOnlyTreeSnapshot) {
348
- const syncedArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.dbProvider.getSnapshot(l2Block.number));
446
+ protected async verifyBuiltBlockAgainstSyncedState(provingState: BlockProvingState) {
447
+ const builtBlockHeader = provingState.getBuiltBlockHeader();
448
+ if (!builtBlockHeader) {
449
+ logger.debug('Block header not built yet, skipping header check.');
450
+ return;
451
+ }
452
+
453
+ const output = provingState.getBlockRootRollupOutput();
454
+ if (!output) {
455
+ logger.debug('Block root rollup proof not built yet, skipping header check.');
456
+ return;
457
+ }
458
+ const header = await buildHeaderFromCircuitOutputs(output);
459
+
460
+ if (!(await header.hash()).equals(await builtBlockHeader.hash())) {
461
+ logger.error(`Block header mismatch.\nCircuit: ${inspect(header)}\nComputed: ${inspect(builtBlockHeader)}`);
462
+ provingState.reject(`Block header hash mismatch.`);
463
+ return;
464
+ }
465
+
466
+ // Get db for this block
467
+ const blockNumber = provingState.blockNumber;
468
+ const db = this.dbs.get(blockNumber)!;
469
+
470
+ const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
471
+ const syncedArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.dbProvider.getSnapshot(blockNumber));
349
472
  if (!syncedArchive.equals(newArchive)) {
350
- throw new Error(
351
- `Archive tree mismatch for block ${l2Block.number}: world state synced to ${inspect(
473
+ logger.error(
474
+ `Archive tree mismatch for block ${blockNumber}: world state synced to ${inspect(
352
475
  syncedArchive,
353
476
  )} but built ${inspect(newArchive)}`,
354
477
  );
478
+ provingState.reject(`Archive tree mismatch.`);
479
+ return;
480
+ }
481
+
482
+ const circuitArchive = output.newArchive;
483
+ if (!newArchive.equals(circuitArchive)) {
484
+ logger.error(`New archive mismatch.\nCircuit: ${output.newArchive}\nComputed: ${newArchive}`);
485
+ provingState.reject(`New archive mismatch.`);
486
+ return;
355
487
  }
488
+
489
+ // TODO(palla/prover): This closes the fork only on the happy path. If this epoch orchestrator
490
+ // is aborted and never reaches this point, it will leak the fork. We need to add a global cleanup,
491
+ // but have to make sure it only runs once all operations are completed, otherwise some function here
492
+ // will attempt to access the fork after it was closed.
493
+ logger.debug(`Cleaning up world state fork for ${blockNumber}`);
494
+ void this.dbs
495
+ .get(blockNumber)
496
+ ?.close()
497
+ .then(() => this.dbs.delete(blockNumber))
498
+ .catch(err => logger.error(`Error closing db for block ${blockNumber}`, err));
356
499
  }
357
500
 
358
501
  /**
@@ -369,7 +512,11 @@ export class ProvingOrchestrator implements EpochProver {
369
512
  /**
370
513
  * Returns the proof for the current epoch.
371
514
  */
372
- public async finalizeEpoch() {
515
+ public async finalizeEpoch(): Promise<{
516
+ publicInputs: RootRollupPublicInputs;
517
+ proof: Proof;
518
+ batchedBlobInputs: BatchedBlob;
519
+ }> {
373
520
  if (!this.provingState || !this.provingPromise) {
374
521
  throw new Error(`Invalid proving state, an epoch must be proven before it can be finalized`);
375
522
  }
@@ -379,14 +526,7 @@ export class ProvingOrchestrator implements EpochProver {
379
526
  throw new Error(`Epoch proving failed: ${result.reason}`);
380
527
  }
381
528
 
382
- // TODO(MW): Move this? Requires async and don't want to force root methods to be async
383
- // TODO(MW): EpochProvingState uses this.blocks.filter(b => !!b).length as total blocks, use this below:
384
- const finalBlock = this.provingState.blocks[this.provingState.totalNumBlocks - 1];
385
- if (!finalBlock || !finalBlock.endBlobAccumulator) {
386
- throw new Error(`Epoch's final block not ready for finalize`);
387
- }
388
- const finalBatchedBlob = await finalBlock.endBlobAccumulator.finalize();
389
- this.provingState.setFinalBatchedBlob(finalBatchedBlob);
529
+ await this.provingState.finalizeBatchedBlob();
390
530
 
391
531
  const epochProofResult = this.provingState.getEpochProofResult();
392
532
 
@@ -398,20 +538,6 @@ export class ProvingOrchestrator implements EpochProver {
398
538
  return epochProofResult;
399
539
  }
400
540
 
401
- /**
402
- * Starts the proving process for the given transaction and adds it to our state
403
- * @param tx - The transaction whose proving we wish to commence
404
- * @param provingState - The proving state being worked on
405
- */
406
- private async prepareTransaction(tx: ProcessedTx, provingState: BlockProvingState) {
407
- const txInputs = await this.prepareBaseRollupInputs(provingState, tx);
408
- if (!txInputs) {
409
- // This should not be possible
410
- throw new Error(`Unable to add transaction, preparing base inputs failed`);
411
- }
412
- return txInputs;
413
- }
414
-
415
541
  /**
416
542
  * Enqueue a job to be scheduled
417
543
  * @param provingState - The proving state object being operated on
@@ -419,11 +545,11 @@ export class ProvingOrchestrator implements EpochProver {
419
545
  * @param job - The actual job, returns a promise notifying of the job's completion
420
546
  */
421
547
  private deferredProving<T>(
422
- provingState: EpochProvingState | BlockProvingState | undefined,
548
+ provingState: EpochProvingState | CheckpointProvingState | BlockProvingState,
423
549
  request: (signal: AbortSignal) => Promise<T>,
424
550
  callback: (result: T) => void | Promise<void>,
425
551
  ) {
426
- if (!provingState?.verifyState()) {
552
+ if (!provingState.verifyState()) {
427
553
  logger.debug(`Not enqueuing job, state no longer valid`);
428
554
  return;
429
555
  }
@@ -441,7 +567,7 @@ export class ProvingOrchestrator implements EpochProver {
441
567
  }
442
568
 
443
569
  const result = await request(controller.signal);
444
- if (!provingState?.verifyState()) {
570
+ if (!provingState.verifyState()) {
445
571
  logger.debug(`State no longer valid, discarding result`);
446
572
  return;
447
573
  }
@@ -474,60 +600,58 @@ export class ProvingOrchestrator implements EpochProver {
474
600
  setImmediate(() => void safeJob());
475
601
  }
476
602
 
477
- private async prepareBaseParityInputs(l1ToL2Messages: Fr[], db: MerkleTreeWriteOperations) {
478
- const l1ToL2MessagesPadded = padArrayEnd(
603
+ private async updateL1ToL2MessageTree(l1ToL2Messages: Fr[], db: MerkleTreeWriteOperations) {
604
+ const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
479
605
  l1ToL2Messages,
480
606
  Fr.ZERO,
481
607
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
482
608
  'Too many L1 to L2 messages',
483
609
  );
484
- const baseParityInputs = times(NUM_BASE_PARITY_PER_ROOT_PARITY, i =>
485
- BaseParityInputs.fromSlice(l1ToL2MessagesPadded, i, getVKTreeRoot()),
486
- );
487
610
 
488
- const l1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
489
-
490
- const l1ToL2MessageSubtreeSiblingPath = assertLength(
611
+ const lastL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
612
+ const lastL1ToL2MessageSubtreeRootSiblingPath = assertLength(
491
613
  await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db),
492
- L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH,
614
+ L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
493
615
  );
494
616
 
495
617
  // Update the local trees to include the new l1 to l2 messages
496
618
  await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
497
- const l1ToL2MessageTreeSnapshotAfterInsertion = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
619
+
620
+ const newL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
621
+ const newL1ToL2MessageSubtreeRootSiblingPath = assertLength(
622
+ await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db),
623
+ L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
624
+ );
498
625
 
499
626
  return {
500
- l1ToL2MessageTreeSnapshot,
501
- l1ToL2MessageSubtreeSiblingPath,
502
- l1ToL2MessageTreeSnapshotAfterInsertion,
503
- baseParityInputs,
627
+ lastL1ToL2MessageTreeSnapshot,
628
+ lastL1ToL2MessageSubtreeRootSiblingPath,
629
+ newL1ToL2MessageTreeSnapshot,
630
+ newL1ToL2MessageSubtreeRootSiblingPath,
504
631
  };
505
632
  }
506
633
 
507
634
  // Updates the merkle trees for a transaction. The first enqueued job for a transaction
508
- @trackSpan('ProvingOrchestrator.prepareBaseRollupInputs', (_, tx) => ({
635
+ @trackSpan('ProvingOrchestrator.prepareBaseRollupInputs', tx => ({
509
636
  [Attributes.TX_HASH]: tx.hash.toString(),
510
637
  }))
511
638
  private async prepareBaseRollupInputs(
512
- provingState: BlockProvingState,
513
639
  tx: ProcessedTx,
514
- ): Promise<[BaseRollupHints, TreeSnapshots] | undefined> {
515
- if (!provingState.verifyState() || !provingState.spongeBlobState) {
516
- logger.debug('Not preparing base rollup inputs, state invalid');
517
- return;
518
- }
519
-
520
- const db = this.dbs.get(provingState.blockNumber)!;
521
-
640
+ lastArchive: AppendOnlyTreeSnapshot,
641
+ newL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot,
642
+ startSpongeBlob: SpongeBlob,
643
+ db: MerkleTreeWriteOperations,
644
+ ): Promise<[BaseRollupHints, TreeSnapshots]> {
522
645
  // We build the base rollup inputs using a mock proof and verification key.
523
646
  // These will be overwritten later once we have proven the tube circuit and any public kernels
524
647
  const [ms, hints] = await elapsed(
525
648
  insertSideEffectsAndBuildBaseRollupHints(
526
649
  tx,
527
- provingState.globalVariables,
528
- provingState.l1ToL2MessageTreeSnapshotAfterInsertion,
650
+ lastArchive,
651
+ newL1ToL2MessageTreeSnapshot,
652
+ startSpongeBlob,
653
+ this.proverId.toField(),
529
654
  db,
530
- provingState.spongeBlobState,
531
655
  ),
532
656
  );
533
657
 
@@ -540,10 +664,6 @@ export class ProvingOrchestrator implements EpochProver {
540
664
  );
541
665
  const treeSnapshots: TreeSnapshots = new Map((await Promise.all(promises)).map(obj => [obj.key, obj.value]));
542
666
 
543
- if (!provingState.verifyState()) {
544
- logger.debug(`Discarding proving job, state no longer valid`);
545
- return;
546
- }
547
667
  return [hints, treeSnapshots];
548
668
  }
549
669
 
@@ -555,6 +675,11 @@ export class ProvingOrchestrator implements EpochProver {
555
675
  return;
556
676
  }
557
677
 
678
+ if (!provingState.tryStartProvingBase(txIndex)) {
679
+ logger.debug(`Base rollup for tx ${txIndex} already started.`);
680
+ return;
681
+ }
682
+
558
683
  const txProvingState = provingState.getTxProvingState(txIndex);
559
684
  const { processedTx } = txProvingState;
560
685
  const { rollupType, inputs } = txProvingState.getBaseRollupTypeAndInputs();
@@ -566,35 +691,37 @@ export class ProvingOrchestrator implements EpochProver {
566
691
  wrapCallbackInSpan(
567
692
  this.tracer,
568
693
  `ProvingOrchestrator.prover.${
569
- inputs instanceof PrivateBaseRollupInputs ? 'getPrivateBaseRollupProof' : 'getPublicBaseRollupProof'
694
+ inputs instanceof PrivateTxBaseRollupPrivateInputs
695
+ ? 'getPrivateTxBaseRollupProof'
696
+ : 'getPublicTxBaseRollupProof'
570
697
  }`,
571
698
  {
572
699
  [Attributes.TX_HASH]: processedTx.hash.toString(),
573
700
  [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
574
701
  },
575
702
  signal => {
576
- if (inputs instanceof PrivateBaseRollupInputs) {
577
- return this.prover.getPrivateBaseRollupProof(inputs, signal, provingState.epochNumber);
703
+ if (inputs instanceof PrivateTxBaseRollupPrivateInputs) {
704
+ return this.prover.getPrivateTxBaseRollupProof(inputs, signal, provingState.epochNumber);
578
705
  } else {
579
- return this.prover.getPublicBaseRollupProof(inputs, signal, provingState.epochNumber);
706
+ return this.prover.getPublicTxBaseRollupProof(inputs, signal, provingState.epochNumber);
580
707
  }
581
708
  },
582
709
  ),
583
- async result => {
710
+ result => {
584
711
  logger.debug(`Completed proof for ${rollupType} for tx ${processedTx.hash.toString()}`);
585
- validatePartialState(result.inputs.end, txProvingState.treeSnapshots);
712
+ validatePartialState(result.inputs.endTreeSnapshots, txProvingState.treeSnapshots);
586
713
  const leafLocation = provingState.setBaseRollupProof(txIndex, result);
587
714
  if (provingState.totalNumTxs === 1) {
588
- await this.checkAndEnqueueBlockRootRollup(provingState);
715
+ this.checkAndEnqueueBlockRootRollup(provingState);
589
716
  } else {
590
- await this.checkAndEnqueueNextMergeRollup(provingState, leafLocation);
717
+ this.checkAndEnqueueNextMergeRollup(provingState, leafLocation);
591
718
  }
592
719
  },
593
720
  );
594
721
  }
595
722
 
596
- // Enqueues the tube circuit for a given transaction index, or reuses the one already enqueued
597
- // Once completed, will enqueue the next circuit, either a public kernel or the base rollup
723
+ // Enqueues the public tube circuit for a given transaction index, or reuses the one already enqueued.
724
+ // Once completed, will enqueue the the public tx base rollup.
598
725
  private getOrEnqueueTube(provingState: BlockProvingState, txIndex: number) {
599
726
  if (!provingState.verifyState()) {
600
727
  logger.debug('Not running tube circuit, state invalid');
@@ -603,12 +730,14 @@ export class ProvingOrchestrator implements EpochProver {
603
730
 
604
731
  const txProvingState = provingState.getTxProvingState(txIndex);
605
732
  const txHash = txProvingState.processedTx.hash.toString();
606
-
607
- const handleResult = (result: ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>) => {
733
+ NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH;
734
+ const handleResult = (
735
+ result: PublicInputsAndRecursiveProof<PublicTubePublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>,
736
+ ) => {
608
737
  logger.debug(`Got tube proof for tx index: ${txIndex}`, { txHash });
609
- txProvingState.setTubeProof(result);
738
+ txProvingState.setPublicTubeProof(result);
610
739
  this.provingState?.cachedTubeProofs.delete(txHash);
611
- this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
740
+ this.checkAndEnqueueBaseRollup(provingState, txIndex);
612
741
  };
613
742
 
614
743
  if (this.provingState?.cachedTubeProofs.has(txHash)) {
@@ -618,16 +747,18 @@ export class ProvingOrchestrator implements EpochProver {
618
747
  }
619
748
 
620
749
  logger.debug(`Enqueuing tube circuit for tx index: ${txIndex}`);
621
- this.doEnqueueTube(txHash, txProvingState.getTubeInputs(), handleResult);
750
+ this.doEnqueueTube(txHash, txProvingState.getPublicTubePrivateInputs(), handleResult);
622
751
  }
623
752
 
624
753
  private doEnqueueTube(
625
754
  txHash: string,
626
- inputs: TubeInputs,
627
- handler: (result: ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>) => void,
755
+ inputs: PublicTubePrivateInputs,
756
+ handler: (
757
+ result: PublicInputsAndRecursiveProof<PublicTubePublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>,
758
+ ) => void,
628
759
  provingState: EpochProvingState | BlockProvingState = this.provingState!,
629
760
  ) {
630
- if (!provingState?.verifyState()) {
761
+ if (!provingState.verifyState()) {
631
762
  logger.debug('Not running tube circuit, state invalid');
632
763
  return;
633
764
  }
@@ -636,12 +767,12 @@ export class ProvingOrchestrator implements EpochProver {
636
767
  provingState,
637
768
  wrapCallbackInSpan(
638
769
  this.tracer,
639
- 'ProvingOrchestrator.prover.getTubeProof',
770
+ 'ProvingOrchestrator.prover.getPublicTubeProof',
640
771
  {
641
772
  [Attributes.TX_HASH]: txHash,
642
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'tube-circuit' satisfies CircuitName,
773
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'tube-public' satisfies CircuitName,
643
774
  },
644
- signal => this.prover.getTubeProof(inputs, signal, this.provingState!.epochNumber),
775
+ signal => this.prover.getPublicTubeProof(inputs, signal, provingState.epochNumber),
645
776
  ),
646
777
  handler,
647
778
  );
@@ -655,39 +786,45 @@ export class ProvingOrchestrator implements EpochProver {
655
786
  return;
656
787
  }
657
788
 
789
+ if (!provingState.tryStartProvingMerge(location)) {
790
+ logger.debug('Merge rollup already started.');
791
+ return;
792
+ }
793
+
658
794
  const inputs = provingState.getMergeRollupInputs(location);
659
795
 
660
796
  this.deferredProving(
661
797
  provingState,
662
798
  wrapCallbackInSpan(
663
799
  this.tracer,
664
- 'ProvingOrchestrator.prover.getMergeRollupProof',
800
+ 'ProvingOrchestrator.prover.getTxMergeRollupProof',
665
801
  {
666
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'merge-rollup' satisfies CircuitName,
802
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-tx-merge' satisfies CircuitName,
667
803
  },
668
- signal => this.prover.getMergeRollupProof(inputs, signal, provingState.epochNumber),
804
+ signal => this.prover.getTxMergeRollupProof(inputs, signal, provingState.epochNumber),
669
805
  ),
670
- async result => {
806
+ result => {
671
807
  provingState.setMergeRollupProof(location, result);
672
- await this.checkAndEnqueueNextMergeRollup(provingState, location);
808
+ this.checkAndEnqueueNextMergeRollup(provingState, location);
673
809
  },
674
810
  );
675
811
  }
676
812
 
677
813
  // Executes the block root rollup circuit
678
- private async enqueueBlockRootRollup(provingState: BlockProvingState) {
814
+ private enqueueBlockRootRollup(provingState: BlockProvingState) {
679
815
  if (!provingState.verifyState()) {
680
816
  logger.debug('Not running block root rollup, state no longer valid');
681
817
  return;
682
818
  }
683
819
 
684
- provingState.blockRootRollupStarted = true;
820
+ if (!provingState.tryStartProvingBlockRoot()) {
821
+ logger.debug('Block root rollup already started.');
822
+ return;
823
+ }
685
824
 
686
- const { rollupType, inputs } = await provingState.getBlockRootRollupTypeAndInputs();
825
+ const { rollupType, inputs } = provingState.getBlockRootRollupTypeAndInputs();
687
826
 
688
- logger.debug(
689
- `Enqueuing ${rollupType} for block ${provingState.blockNumber} with ${provingState.newL1ToL2Messages.length} l1 to l2 msgs.`,
690
- );
827
+ logger.debug(`Enqueuing ${rollupType} for block ${provingState.blockNumber}.`);
691
828
 
692
829
  this.deferredProving(
693
830
  provingState,
@@ -698,56 +835,32 @@ export class ProvingOrchestrator implements EpochProver {
698
835
  [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
699
836
  },
700
837
  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);
838
+ if (inputs instanceof BlockRootFirstRollupPrivateInputs) {
839
+ return this.prover.getBlockRootFirstRollupProof(inputs, signal, provingState.epochNumber);
840
+ } else if (inputs instanceof BlockRootSingleTxFirstRollupPrivateInputs) {
841
+ return this.prover.getBlockRootSingleTxFirstRollupProof(inputs, signal, provingState.epochNumber);
842
+ } else if (inputs instanceof BlockRootEmptyTxFirstRollupPrivateInputs) {
843
+ return this.prover.getBlockRootEmptyTxFirstRollupProof(inputs, signal, provingState.epochNumber);
844
+ } else if (inputs instanceof BlockRootSingleTxRollupPrivateInputs) {
845
+ return this.prover.getBlockRootSingleTxRollupProof(inputs, signal, provingState.epochNumber);
705
846
  } else {
706
847
  return this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber);
707
848
  }
708
849
  },
709
850
  ),
710
851
  async result => {
711
- provingState.setBlockRootRollupProof(result);
712
- const header = await provingState.buildHeaderFromProvingOutputs();
713
- if (!(await header.hash()).equals(await provingState.block!.header.hash())) {
714
- logger.error(
715
- `Block header mismatch.\nCircuit: ${inspect(header)}\nComputed: ${inspect(provingState.block!.header)}`,
716
- );
717
- provingState.reject(`Block header hash mismatch.`);
718
- }
719
-
720
- const dbArchiveRoot = provingState.block!.archive.root;
721
- const circuitArchiveRoot = result.inputs.newArchive.root;
722
- if (!dbArchiveRoot.equals(circuitArchiveRoot)) {
723
- logger.error(
724
- `New archive root mismatch.\nCircuit: ${result.inputs.newArchive.root}\nComputed: ${dbArchiveRoot}`,
725
- );
726
- provingState.reject(`New archive root mismatch.`);
727
- }
852
+ // If the proofs were slower than the block header building, then we need to try validating the block header hashes here.
853
+ await this.verifyBuiltBlockAgainstSyncedState(provingState);
728
854
 
729
- const endBlobAccumulatorPublicInputs = BlobAccumulatorPublicInputs.fromBatchedBlobAccumulator(
730
- provingState.endBlobAccumulator!,
731
- );
732
- const circuitEndBlobAccumulatorState = result.inputs.blobPublicInputs.endBlobAccumulator;
733
- if (!circuitEndBlobAccumulatorState.equals(endBlobAccumulatorPublicInputs)) {
734
- logger.error(
735
- `Blob accumulator state mismatch.\nCircuit: ${inspect(circuitEndBlobAccumulatorState)}\nComputed: ${inspect(
736
- endBlobAccumulatorPublicInputs,
737
- )}`,
738
- );
739
- provingState.reject(`Blob accumulator state mismatch.`);
740
- }
855
+ logger.debug(`Completed ${rollupType} proof for block ${provingState.blockNumber}`);
741
856
 
742
- logger.debug(`Completed ${rollupType} proof for block ${provingState.block!.number}`);
743
- // validatePartialState(result.inputs.end, tx.treeSnapshots); // TODO(palla/prover)
857
+ const leafLocation = provingState.setBlockRootRollupProof(result);
858
+ const checkpointProvingState = provingState.parentCheckpoint;
744
859
 
745
- const epochProvingState = this.provingState!;
746
- const leafLocation = epochProvingState.setBlockRootRollupProof(provingState.index, result);
747
- if (epochProvingState.totalNumBlocks === 1) {
748
- this.enqueueEpochPadding(epochProvingState);
860
+ if (checkpointProvingState.totalNumBlocks === 1) {
861
+ this.checkAndEnqueueCheckpointRootRollup(checkpointProvingState);
749
862
  } else {
750
- this.checkAndEnqueueNextBlockMergeRollup(epochProvingState, leafLocation);
863
+ this.checkAndEnqueueNextBlockMergeRollup(checkpointProvingState, leafLocation);
751
864
  }
752
865
  },
753
866
  );
@@ -755,24 +868,35 @@ export class ProvingOrchestrator implements EpochProver {
755
868
 
756
869
  // Executes the base parity circuit and stores the intermediate state for the root parity circuit
757
870
  // Enqueues the root parity circuit if all inputs are available
758
- private enqueueBaseParityCircuit(provingState: BlockProvingState, inputs: BaseParityInputs, index: number) {
871
+ private enqueueBaseParityCircuit(
872
+ checkpointProvingState: CheckpointProvingState,
873
+ provingState: BlockProvingState,
874
+ baseParityIndex: number,
875
+ ) {
759
876
  if (!provingState.verifyState()) {
760
877
  logger.debug('Not running base parity. State no longer valid.');
761
878
  return;
762
879
  }
763
880
 
881
+ if (!provingState.tryStartProvingBaseParity(baseParityIndex)) {
882
+ logger.warn(`Base parity ${baseParityIndex} already started.`);
883
+ return;
884
+ }
885
+
886
+ const inputs = checkpointProvingState.getBaseParityInputs(baseParityIndex);
887
+
764
888
  this.deferredProving(
765
889
  provingState,
766
890
  wrapCallbackInSpan(
767
891
  this.tracer,
768
892
  'ProvingOrchestrator.prover.getBaseParityProof',
769
893
  {
770
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'base-parity' satisfies CircuitName,
894
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'parity-base' satisfies CircuitName,
771
895
  },
772
896
  signal => this.prover.getBaseParityProof(inputs, signal, provingState.epochNumber),
773
897
  ),
774
898
  provingOutput => {
775
- provingState.setBaseParityProof(index, provingOutput);
899
+ provingState.setBaseParityProof(baseParityIndex, provingOutput);
776
900
  this.checkAndEnqueueRootParityCircuit(provingState);
777
901
  },
778
902
  );
@@ -794,7 +918,12 @@ export class ProvingOrchestrator implements EpochProver {
794
918
  return;
795
919
  }
796
920
 
797
- const inputs = provingState.getRootParityInputs();
921
+ if (!provingState.tryStartProvingRootParity()) {
922
+ logger.debug('Root parity already started.');
923
+ return;
924
+ }
925
+
926
+ const inputs = provingState.getParityRootInputs();
798
927
 
799
928
  this.deferredProving(
800
929
  provingState,
@@ -802,25 +931,30 @@ export class ProvingOrchestrator implements EpochProver {
802
931
  this.tracer,
803
932
  'ProvingOrchestrator.prover.getRootParityProof',
804
933
  {
805
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-parity' satisfies CircuitName,
934
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'parity-root' satisfies CircuitName,
806
935
  },
807
936
  signal => this.prover.getRootParityProof(inputs, signal, provingState.epochNumber),
808
937
  ),
809
- async result => {
938
+ result => {
810
939
  provingState.setRootParityProof(result);
811
- await this.checkAndEnqueueBlockRootRollup(provingState);
940
+ this.checkAndEnqueueBlockRootRollup(provingState);
812
941
  },
813
942
  );
814
943
  }
815
944
 
816
945
  // Executes the block merge rollup circuit and stored the output as intermediate state for the parent merge/block root circuit
817
946
  // Enqueues the next level of merge if all inputs are available
818
- private enqueueBlockMergeRollup(provingState: EpochProvingState, location: TreeNodeLocation) {
947
+ private enqueueBlockMergeRollup(provingState: CheckpointProvingState, location: TreeNodeLocation) {
819
948
  if (!provingState.verifyState()) {
820
949
  logger.debug('Not running block merge rollup. State no longer valid.');
821
950
  return;
822
951
  }
823
952
 
953
+ if (!provingState.tryStartProvingBlockMerge(location)) {
954
+ logger.debug('Block merge rollup already started.');
955
+ return;
956
+ }
957
+
824
958
  const inputs = provingState.getBlockMergeRollupInputs(location);
825
959
  this.deferredProving(
826
960
  provingState,
@@ -828,7 +962,7 @@ export class ProvingOrchestrator implements EpochProver {
828
962
  this.tracer,
829
963
  'ProvingOrchestrator.prover.getBlockMergeRollupProof',
830
964
  {
831
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'block-merge-rollup' satisfies CircuitName,
965
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-block-merge' satisfies CircuitName,
832
966
  },
833
967
  signal => this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber),
834
968
  ),
@@ -839,29 +973,125 @@ export class ProvingOrchestrator implements EpochProver {
839
973
  );
840
974
  }
841
975
 
976
+ private enqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
977
+ if (!provingState.verifyState()) {
978
+ logger.debug('Not running checkpoint root rollup. State no longer valid.');
979
+ return;
980
+ }
981
+
982
+ if (!provingState.tryStartProvingCheckpointRoot()) {
983
+ logger.debug('Checkpoint root rollup already started.');
984
+ return;
985
+ }
986
+
987
+ const rollupType = provingState.getCheckpointRootRollupType();
988
+
989
+ logger.debug(`Enqueuing ${rollupType} for checkpoint ${provingState.index}.`);
990
+
991
+ const inputs = provingState.getCheckpointRootRollupInputs();
992
+
993
+ this.deferredProving(
994
+ provingState,
995
+ wrapCallbackInSpan(
996
+ this.tracer,
997
+ 'ProvingOrchestrator.prover.getCheckpointRootRollupProof',
998
+ {
999
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
1000
+ },
1001
+ signal => {
1002
+ if (inputs instanceof CheckpointRootSingleBlockRollupPrivateInputs) {
1003
+ return this.prover.getCheckpointRootSingleBlockRollupProof(inputs, signal, provingState.epochNumber);
1004
+ } else {
1005
+ return this.prover.getCheckpointRootRollupProof(inputs, signal, provingState.epochNumber);
1006
+ }
1007
+ },
1008
+ ),
1009
+ result => {
1010
+ const computedEndBlobAccumulatorState = provingState.getEndBlobAccumulator()!.toBlobAccumulator();
1011
+ const circuitEndBlobAccumulatorState = result.inputs.endBlobAccumulator;
1012
+ if (!circuitEndBlobAccumulatorState.equals(computedEndBlobAccumulatorState)) {
1013
+ logger.error(
1014
+ `Blob accumulator state mismatch.\nCircuit: ${inspect(circuitEndBlobAccumulatorState)}\nComputed: ${inspect(
1015
+ computedEndBlobAccumulatorState,
1016
+ )}`,
1017
+ );
1018
+ provingState.reject(`Blob accumulator state mismatch.`);
1019
+ return;
1020
+ }
1021
+
1022
+ logger.debug(`Completed ${rollupType} proof for checkpoint ${provingState.index}.`);
1023
+
1024
+ const leafLocation = provingState.setCheckpointRootRollupProof(result);
1025
+ const epochProvingState = provingState.parentEpoch;
1026
+
1027
+ if (epochProvingState.totalNumCheckpoints === 1) {
1028
+ this.enqueueEpochPadding(epochProvingState);
1029
+ } else {
1030
+ this.checkAndEnqueueNextCheckpointMergeRollup(epochProvingState, leafLocation);
1031
+ }
1032
+ },
1033
+ );
1034
+ }
1035
+
1036
+ private enqueueCheckpointMergeRollup(provingState: EpochProvingState, location: TreeNodeLocation) {
1037
+ if (!provingState.verifyState()) {
1038
+ logger.debug('Not running checkpoint merge rollup. State no longer valid.');
1039
+ return;
1040
+ }
1041
+
1042
+ if (!provingState.tryStartProvingCheckpointMerge(location)) {
1043
+ logger.debug('Checkpoint merge rollup already started.');
1044
+ return;
1045
+ }
1046
+
1047
+ const inputs = provingState.getCheckpointMergeRollupInputs(location);
1048
+
1049
+ this.deferredProving(
1050
+ provingState,
1051
+ wrapCallbackInSpan(
1052
+ this.tracer,
1053
+ 'ProvingOrchestrator.prover.getCheckpointMergeRollupProof',
1054
+ {
1055
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-merge' satisfies CircuitName,
1056
+ },
1057
+ signal => this.prover.getCheckpointMergeRollupProof(inputs, signal, provingState.epochNumber),
1058
+ ),
1059
+ result => {
1060
+ logger.debug('Completed proof for checkpoint merge rollup.');
1061
+ provingState.setCheckpointMergeRollupProof(location, result);
1062
+ this.checkAndEnqueueNextCheckpointMergeRollup(provingState, location);
1063
+ },
1064
+ );
1065
+ }
1066
+
842
1067
  private enqueueEpochPadding(provingState: EpochProvingState) {
843
1068
  if (!provingState.verifyState()) {
844
1069
  logger.debug('Not running epoch padding. State no longer valid.');
845
1070
  return;
846
1071
  }
847
1072
 
1073
+ if (!provingState.tryStartProvingPaddingCheckpoint()) {
1074
+ logger.debug('Padding checkpoint already started.');
1075
+ return;
1076
+ }
1077
+
848
1078
  logger.debug('Padding epoch proof with a padding block root proof.');
849
1079
 
850
- const inputs = provingState.getPaddingBlockRootInputs();
1080
+ const inputs = provingState.getPaddingCheckpointInputs();
851
1081
 
852
1082
  this.deferredProving(
853
1083
  provingState,
854
1084
  wrapCallbackInSpan(
855
1085
  this.tracer,
856
- 'ProvingOrchestrator.prover.getPaddingBlockRootRollupProof',
1086
+ 'ProvingOrchestrator.prover.getCheckpointPaddingRollupProof',
857
1087
  {
858
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'padding-block-root-rollup' satisfies CircuitName,
1088
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-padding' satisfies CircuitName,
859
1089
  },
860
- signal => this.prover.getPaddingBlockRootRollupProof(inputs, signal, provingState.epochNumber),
1090
+ signal => this.prover.getCheckpointPaddingRollupProof(inputs, signal, provingState.epochNumber),
861
1091
  ),
862
1092
  result => {
863
- logger.debug('Completed proof for padding block root.');
864
- provingState.setPaddingBlockRootProof(result);
1093
+ logger.debug('Completed proof for padding checkpoint.');
1094
+ provingState.setCheckpointPaddingProof(result);
865
1095
  this.checkAndEnqueueRootRollup(provingState);
866
1096
  },
867
1097
  );
@@ -884,7 +1114,7 @@ export class ProvingOrchestrator implements EpochProver {
884
1114
  this.tracer,
885
1115
  'ProvingOrchestrator.prover.getRootRollupProof',
886
1116
  {
887
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-rollup' satisfies CircuitName,
1117
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-root' satisfies CircuitName,
888
1118
  },
889
1119
  signal => this.prover.getRootRollupProof(inputs, signal, provingState.epochNumber),
890
1120
  ),
@@ -896,48 +1126,51 @@ export class ProvingOrchestrator implements EpochProver {
896
1126
  );
897
1127
  }
898
1128
 
899
- private async checkAndEnqueueNextMergeRollup(provingState: BlockProvingState, currentLocation: TreeNodeLocation) {
1129
+ private checkAndEnqueueNextMergeRollup(provingState: BlockProvingState, currentLocation: TreeNodeLocation) {
900
1130
  if (!provingState.isReadyForMergeRollup(currentLocation)) {
901
1131
  return;
902
1132
  }
903
1133
 
904
1134
  const parentLocation = provingState.getParentLocation(currentLocation);
905
1135
  if (parentLocation.level === 0) {
906
- await this.checkAndEnqueueBlockRootRollup(provingState);
1136
+ this.checkAndEnqueueBlockRootRollup(provingState);
907
1137
  } else {
908
1138
  this.enqueueMergeRollup(provingState, parentLocation);
909
1139
  }
910
1140
  }
911
1141
 
912
- private async checkAndEnqueueBlockRootRollup(provingState: BlockProvingState) {
913
- const blockNumber = provingState.blockNumber;
914
- // Accumulate as far as we can, in case blocks came in out of order and we are behind:
915
- await this.provingState?.setBlobAccumulators(blockNumber);
1142
+ private checkAndEnqueueBlockRootRollup(provingState: BlockProvingState) {
916
1143
  if (!provingState.isReadyForBlockRootRollup()) {
917
1144
  logger.debug('Not ready for block root rollup');
918
1145
  return;
919
1146
  }
920
- if (provingState.blockRootRollupStarted) {
921
- logger.debug('Block root rollup already started');
1147
+
1148
+ this.enqueueBlockRootRollup(provingState);
1149
+ }
1150
+
1151
+ private checkAndEnqueueNextBlockMergeRollup(provingState: CheckpointProvingState, currentLocation: TreeNodeLocation) {
1152
+ if (!provingState.isReadyForBlockMerge(currentLocation)) {
922
1153
  return;
923
1154
  }
924
1155
 
925
- // TODO(palla/prover): This closes the fork only on the happy path. If this epoch orchestrator
926
- // is aborted and never reaches this point, it will leak the fork. We need to add a global cleanup,
927
- // but have to make sure it only runs once all operations are completed, otherwise some function here
928
- // will attempt to access the fork after it was closed.
929
- logger.debug(`Cleaning up world state fork for ${blockNumber}`);
930
- void this.dbs
931
- .get(blockNumber)
932
- ?.close()
933
- .then(() => this.dbs.delete(blockNumber))
934
- .catch(err => logger.error(`Error closing db for block ${blockNumber}`, err));
1156
+ const parentLocation = provingState.getParentLocation(currentLocation);
1157
+ if (parentLocation.level === 0) {
1158
+ this.checkAndEnqueueCheckpointRootRollup(provingState);
1159
+ } else {
1160
+ this.enqueueBlockMergeRollup(provingState, parentLocation);
1161
+ }
1162
+ }
935
1163
 
936
- await this.enqueueBlockRootRollup(provingState);
1164
+ private checkAndEnqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
1165
+ if (!provingState.isReadyForCheckpointRoot()) {
1166
+ return;
1167
+ }
1168
+
1169
+ this.enqueueCheckpointRootRollup(provingState);
937
1170
  }
938
1171
 
939
- private checkAndEnqueueNextBlockMergeRollup(provingState: EpochProvingState, currentLocation: TreeNodeLocation) {
940
- if (!provingState.isReadyForBlockMerge(currentLocation)) {
1172
+ private checkAndEnqueueNextCheckpointMergeRollup(provingState: EpochProvingState, currentLocation: TreeNodeLocation) {
1173
+ if (!provingState.isReadyForCheckpointMerge(currentLocation)) {
941
1174
  return;
942
1175
  }
943
1176
 
@@ -945,7 +1178,7 @@ export class ProvingOrchestrator implements EpochProver {
945
1178
  if (parentLocation.level === 0) {
946
1179
  this.checkAndEnqueueRootRollup(provingState);
947
1180
  } else {
948
- this.enqueueBlockMergeRollup(provingState, parentLocation);
1181
+ this.enqueueCheckpointMergeRollup(provingState, parentLocation);
949
1182
  }
950
1183
  }
951
1184
 
@@ -1012,11 +1245,11 @@ export class ProvingOrchestrator implements EpochProver {
1012
1245
  this.deferredProving(provingState, doAvmProving, proofAndVk => {
1013
1246
  logger.debug(`Proven VM for tx index: ${txIndex}`);
1014
1247
  txProvingState.setAvmProof(proofAndVk);
1015
- this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
1248
+ this.checkAndEnqueueBaseRollup(provingState, txIndex);
1016
1249
  });
1017
1250
  }
1018
1251
 
1019
- private checkAndEnqueueNextTxCircuit(provingState: BlockProvingState, txIndex: number) {
1252
+ private checkAndEnqueueBaseRollup(provingState: BlockProvingState, txIndex: number) {
1020
1253
  const txProvingState = provingState.getTxProvingState(txIndex);
1021
1254
  if (!txProvingState.ready()) {
1022
1255
  return;