@aztec/prover-client 0.0.1-fake-c83136db25 → 0.0.1-fake-ceab37513c

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 (67) 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 +51 -0
  4. package/dest/block-factory/light.d.ts +3 -5
  5. package/dest/block-factory/light.d.ts.map +1 -1
  6. package/dest/block-factory/light.js +9 -16
  7. package/dest/config.js +1 -1
  8. package/dest/mocks/fixtures.d.ts +1 -4
  9. package/dest/mocks/fixtures.d.ts.map +1 -1
  10. package/dest/mocks/fixtures.js +3 -31
  11. package/dest/mocks/test_context.d.ts +9 -32
  12. package/dest/mocks/test_context.d.ts.map +1 -1
  13. package/dest/mocks/test_context.js +22 -78
  14. package/dest/orchestrator/block-building-helpers.d.ts +31 -33
  15. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  16. package/dest/orchestrator/block-building-helpers.js +137 -126
  17. package/dest/orchestrator/block-proving-state.d.ts +53 -60
  18. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  19. package/dest/orchestrator/block-proving-state.js +187 -214
  20. package/dest/orchestrator/epoch-proving-state.d.ts +28 -34
  21. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  22. package/dest/orchestrator/epoch-proving-state.js +84 -128
  23. package/dest/orchestrator/orchestrator.d.ts +30 -31
  24. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  25. package/dest/orchestrator/orchestrator.js +236 -368
  26. package/dest/orchestrator/tx-proving-state.d.ts +9 -11
  27. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  28. package/dest/orchestrator/tx-proving-state.js +23 -26
  29. package/dest/prover-client/server-epoch-prover.d.ts +8 -9
  30. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
  31. package/dest/prover-client/server-epoch-prover.js +9 -9
  32. package/dest/proving_broker/broker_prover_facade.d.ts +15 -20
  33. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  34. package/dest/proving_broker/broker_prover_facade.js +21 -36
  35. package/dest/proving_broker/fixtures.js +1 -1
  36. package/dest/proving_broker/proof_store/index.d.ts +0 -1
  37. package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
  38. package/dest/proving_broker/proof_store/index.js +0 -1
  39. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  40. package/dest/proving_broker/proving_broker.js +18 -29
  41. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  42. package/dest/proving_broker/proving_job_controller.js +18 -38
  43. package/dest/test/mock_prover.d.ts +17 -22
  44. package/dest/test/mock_prover.d.ts.map +1 -1
  45. package/dest/test/mock_prover.js +20 -35
  46. package/package.json +17 -16
  47. package/src/bin/get-proof-inputs.ts +59 -0
  48. package/src/block-factory/light.ts +9 -35
  49. package/src/config.ts +1 -1
  50. package/src/mocks/fixtures.ts +11 -39
  51. package/src/mocks/test_context.ts +31 -137
  52. package/src/orchestrator/block-building-helpers.ts +211 -211
  53. package/src/orchestrator/block-proving-state.ts +245 -235
  54. package/src/orchestrator/epoch-proving-state.ts +127 -172
  55. package/src/orchestrator/orchestrator.ts +303 -545
  56. package/src/orchestrator/tx-proving-state.ts +43 -49
  57. package/src/prover-client/server-epoch-prover.ts +18 -28
  58. package/src/proving_broker/broker_prover_facade.ts +86 -157
  59. package/src/proving_broker/fixtures.ts +1 -1
  60. package/src/proving_broker/proof_store/index.ts +0 -1
  61. package/src/proving_broker/proving_broker.ts +18 -36
  62. package/src/proving_broker/proving_job_controller.ts +18 -38
  63. package/src/test/mock_prover.ts +60 -142
  64. package/dest/orchestrator/checkpoint-proving-state.d.ts +0 -63
  65. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +0 -1
  66. package/dest/orchestrator/checkpoint-proving-state.js +0 -211
  67. package/src/orchestrator/checkpoint-proving-state.ts +0 -299
@@ -4,8 +4,9 @@ function _ts_decorate(decorators, target, key, desc) {
4
4
  else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  }
7
- import { L1_TO_L2_MSG_SUBTREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH, NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUM_BASE_PARITY_PER_ROOT_PARITY } from '@aztec/constants';
8
- import { padArrayEnd } from '@aztec/foundation/collection';
7
+ import { BlobAccumulatorPublicInputs } from '@aztec/blob-lib';
8
+ import { L1_TO_L2_MSG_SUBTREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUM_BASE_PARITY_PER_ROOT_PARITY } from '@aztec/constants';
9
+ import { padArrayEnd, times } from '@aztec/foundation/collection';
9
10
  import { AbortError } from '@aztec/foundation/error';
10
11
  import { Fr } from '@aztec/foundation/fields';
11
12
  import { createLogger } from '@aztec/foundation/log';
@@ -13,13 +14,16 @@ import { promiseWithResolvers } from '@aztec/foundation/promise';
13
14
  import { assertLength } from '@aztec/foundation/serialize';
14
15
  import { pushTestData } from '@aztec/foundation/testing';
15
16
  import { elapsed } from '@aztec/foundation/timer';
17
+ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
16
18
  import { readAvmMinimalPublicTxInputsFromFile } from '@aztec/simulator/public/fixtures';
17
- import { createBlockEndMarker } from '@aztec/stdlib/block';
18
- import { BlockRootEmptyTxFirstRollupPrivateInputs, BlockRootFirstRollupPrivateInputs, BlockRootSingleTxFirstRollupPrivateInputs, BlockRootSingleTxRollupPrivateInputs, CheckpointRootSingleBlockRollupPrivateInputs, PrivateTxBaseRollupPrivateInputs } from '@aztec/stdlib/rollup';
19
+ import { L2Block } from '@aztec/stdlib/block';
20
+ import { BaseParityInputs } from '@aztec/stdlib/parity';
21
+ import { EmptyBlockRootRollupInputs, PrivateBaseRollupInputs, SingleTxBlockRootRollupInputs, TubeInputs } from '@aztec/stdlib/rollup';
19
22
  import { MerkleTreeId } from '@aztec/stdlib/trees';
23
+ import { toNumBlobFields } from '@aztec/stdlib/tx';
20
24
  import { Attributes, getTelemetryClient, trackSpan, wrapCallbackInSpan } from '@aztec/telemetry-client';
21
25
  import { inspect } from 'util';
22
- import { buildBlockHeaderFromTxs, buildHeaderFromCircuitOutputs, getLastSiblingPath, getPublicChonkVerifierPrivateInputsFromTx, getRootTreeSiblingPath, getSubtreeSiblingPath, getTreeSnapshot, insertSideEffectsAndBuildBaseRollupHints, validatePartialState, validateTx } from './block-building-helpers.js';
26
+ import { buildHeaderAndBodyFromTxs, getLastSiblingPath, getRootTreeSiblingPath, getSubtreeSiblingPath, getTreeSnapshot, insertSideEffectsAndBuildBaseRollupHints, validatePartialState, validateTx } from './block-building-helpers.js';
23
27
  import { EpochProvingState } from './epoch-proving-state.js';
24
28
  import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
25
29
  import { TxProvingState } from './tx-proving-state.js';
@@ -64,92 +68,51 @@ const logger = createLogger('prover-client:orchestrator');
64
68
  this.cancel();
65
69
  return Promise.resolve();
66
70
  }
67
- startNewEpoch(epochNumber, totalNumCheckpoints, finalBlobBatchingChallenges) {
68
- if (this.provingState?.verifyState()) {
69
- throw new Error(`Cannot start epoch ${epochNumber} when epoch ${this.provingState.epochNumber} is still being processed.`);
70
- }
71
+ startNewEpoch(epochNumber, firstBlockNumber, totalNumBlocks, finalBlobBatchingChallenges) {
71
72
  const { promise: _promise, resolve, reject } = promiseWithResolvers();
72
73
  const promise = _promise.catch((reason)=>({
73
74
  status: 'failure',
74
75
  reason
75
76
  }));
76
- logger.info(`Starting epoch ${epochNumber} with ${totalNumCheckpoints} checkpoints.`);
77
- this.provingState = new EpochProvingState(epochNumber, totalNumCheckpoints, finalBlobBatchingChallenges, (provingState)=>this.checkAndEnqueueCheckpointRootRollup(provingState), resolve, reject);
78
- this.provingPromise = promise;
79
- }
80
- async startNewCheckpoint(checkpointIndex, constants, l1ToL2Messages, totalNumBlocks, totalNumBlobFields, headerOfLastBlockInPreviousCheckpoint) {
81
- if (!this.provingState) {
82
- throw new Error('Empty epoch proving state. Call startNewEpoch before starting a checkpoint.');
77
+ if (totalNumBlocks <= 0 || !Number.isInteger(totalNumBlocks)) {
78
+ throw new Error(`Invalid number of blocks for epoch (got ${totalNumBlocks})`);
83
79
  }
84
- if (!this.provingState.isAcceptingCheckpoints()) {
85
- throw new Error(`Epoch not accepting further checkpoints.`);
86
- }
87
- // Fork world state at the end of the immediately previous block.
88
- const lastBlockNumber = headerOfLastBlockInPreviousCheckpoint.globalVariables.blockNumber;
89
- const db = await this.dbProvider.fork(lastBlockNumber);
90
- const firstBlockNumber = lastBlockNumber + 1;
91
- this.dbs.set(firstBlockNumber, db);
92
- // Get archive sibling path before any block in this checkpoint lands.
93
- const lastArchiveSiblingPath = await getLastSiblingPath(MerkleTreeId.ARCHIVE, db);
94
- // Insert all the l1 to l2 messages into the db. And get the states before and after the insertion.
95
- const { lastL1ToL2MessageTreeSnapshot, lastL1ToL2MessageSubtreeRootSiblingPath, newL1ToL2MessageTreeSnapshot, newL1ToL2MessageSubtreeRootSiblingPath } = await this.updateL1ToL2MessageTree(l1ToL2Messages, db);
96
- this.provingState.startNewCheckpoint(checkpointIndex, constants, totalNumBlocks, totalNumBlobFields, headerOfLastBlockInPreviousCheckpoint, lastArchiveSiblingPath, l1ToL2Messages, lastL1ToL2MessageTreeSnapshot, lastL1ToL2MessageSubtreeRootSiblingPath, newL1ToL2MessageTreeSnapshot, newL1ToL2MessageSubtreeRootSiblingPath);
80
+ logger.info(`Starting epoch ${epochNumber} with ${totalNumBlocks} blocks`);
81
+ this.provingState = new EpochProvingState(epochNumber, firstBlockNumber, totalNumBlocks, finalBlobBatchingChallenges, resolve, reject);
82
+ this.provingPromise = promise;
97
83
  }
98
84
  /**
99
85
  * Starts off a new block
100
- * @param blockNumber - The block number
101
- * @param timestamp - The timestamp of the block. This is only required for constructing the private inputs for the
102
- * block that doesn't have any txs.
103
- * @param totalNumTxs - The total number of txs in the block
104
- */ async startNewBlock(blockNumber, timestamp, totalNumTxs) {
86
+ * @param globalVariables - The global variables for the block
87
+ * @param l1ToL2Messages - The l1 to l2 messages for the block
88
+ * @returns A proving ticket, containing a promise notifying of proving completion
89
+ */ async startNewBlock(globalVariables, l1ToL2Messages, previousBlockHeader) {
105
90
  if (!this.provingState) {
106
- throw new Error('Empty epoch proving state. Call startNewEpoch before starting a block.');
107
- }
108
- const checkpointProvingState = this.provingState.getCheckpointProvingStateByBlockNumber(blockNumber);
109
- if (!checkpointProvingState) {
110
- throw new Error(`Checkpoint not started. Call startNewCheckpoint first.`);
111
- }
112
- if (!checkpointProvingState.isAcceptingBlocks()) {
113
- throw new Error(`Checkpoint not accepting further blocks.`);
114
- }
115
- const constants = checkpointProvingState.constants;
116
- logger.info(`Starting block ${blockNumber} for slot ${constants.slotNumber.toNumber()}.`);
117
- // Fork the db only when it's not already set. The db for the first block is set in `startNewCheckpoint`.
118
- if (!this.dbs.has(blockNumber)) {
119
- // Fork world state at the end of the immediately previous block
120
- const db = await this.dbProvider.fork(blockNumber - 1);
121
- this.dbs.set(blockNumber, db);
122
- }
123
- const db = this.dbs.get(blockNumber);
124
- // Get archive snapshot and sibling path before any txs in this block lands.
125
- const lastArchiveTreeSnapshot = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
126
- const lastArchiveSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.ARCHIVE, db);
127
- const blockProvingState = await checkpointProvingState.startNewBlock(blockNumber, timestamp, totalNumTxs, lastArchiveTreeSnapshot, lastArchiveSiblingPath);
128
- // Enqueue base parity circuits for the first block in the checkpoint.
129
- if (blockProvingState.index === 0) {
130
- for(let i = 0; i < NUM_BASE_PARITY_PER_ROOT_PARITY; i++){
131
- this.enqueueBaseParityCircuit(checkpointProvingState, blockProvingState, i);
132
- }
133
- }
134
- // Because `addTxs` won't be called for a block without txs, and that's where the sponge blob state is computed.
135
- // We need to set its end sponge blob here, which will become the start sponge blob for the next block.
136
- if (totalNumTxs === 0) {
137
- const endSpongeBlob = blockProvingState.getStartSpongeBlob().clone();
138
- await endSpongeBlob.absorb([
139
- createBlockEndMarker(0)
140
- ]);
141
- blockProvingState.setEndSpongeBlob(endSpongeBlob);
142
- // And also try to accumulate the blobs as far as we can:
143
- await this.provingState.setBlobAccumulators();
91
+ throw new Error(`Invalid proving state, call startNewEpoch before starting a block`);
92
+ }
93
+ if (!this.provingState?.isAcceptingBlocks()) {
94
+ throw new Error(`Epoch not accepting further blocks`);
95
+ }
96
+ logger.info(`Starting block ${globalVariables.blockNumber} for slot ${globalVariables.slotNumber.toNumber()}`);
97
+ // Fork world state at the end of the immediately previous block
98
+ const db = await this.dbProvider.fork(globalVariables.blockNumber - 1);
99
+ this.dbs.set(globalVariables.blockNumber, db);
100
+ // we start the block by enqueueing all of the base parity circuits
101
+ const { l1ToL2MessageTreeSnapshot, l1ToL2MessageSubtreeSiblingPath, l1ToL2MessageTreeSnapshotAfterInsertion, baseParityInputs } = await this.prepareBaseParityInputs(l1ToL2Messages, db);
102
+ // Get archive snapshot before this block lands
103
+ const lastArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
104
+ const lastArchiveSiblingPath = await getLastSiblingPath(MerkleTreeId.ARCHIVE, db);
105
+ const newArchiveSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.ARCHIVE, db);
106
+ const blockProvingState = this.provingState.startNewBlock(globalVariables, l1ToL2Messages, l1ToL2MessageTreeSnapshot, l1ToL2MessageSubtreeSiblingPath, l1ToL2MessageTreeSnapshotAfterInsertion, lastArchive, lastArchiveSiblingPath, newArchiveSiblingPath, previousBlockHeader, this.proverId);
107
+ // Enqueue base parity circuits for the block
108
+ for(let i = 0; i < baseParityInputs.length; i++){
109
+ this.enqueueBaseParityCircuit(blockProvingState, baseParityInputs[i], i);
144
110
  }
145
111
  }
146
112
  /**
147
113
  * The interface to add simulated transactions to the scheduler. This can only be called once per block.
148
114
  * @param txs - The transactions to be proven
149
115
  */ async addTxs(txs) {
150
- if (!this.provingState) {
151
- throw new Error(`Empty epoch proving state. Call startNewEpoch before adding txs.`);
152
- }
153
116
  if (!txs.length) {
154
117
  // To avoid an ugly throw below. If we require an empty block, we can just call setBlockCompleted
155
118
  // on a block with no txs. We cannot do that here because we cannot find the blockNumber without any txs.
@@ -157,21 +120,16 @@ const logger = createLogger('prover-client:orchestrator');
157
120
  return;
158
121
  }
159
122
  const blockNumber = txs[0].globalVariables.blockNumber;
160
- const provingState = this.provingState.getBlockProvingStateByBlockNumber(blockNumber);
123
+ const provingState = this.provingState?.getBlockProvingStateByBlockNumber(blockNumber);
161
124
  if (!provingState) {
162
- throw new Error(`Proving state for block ${blockNumber} not found. Call startNewBlock first.`);
163
- }
164
- if (provingState.totalNumTxs !== txs.length) {
165
- throw new Error(`Block ${blockNumber} should be filled with ${provingState.totalNumTxs} txs. Received ${txs.length} txs.`);
125
+ throw new Error(`Block proving state for ${blockNumber} not found`);
166
126
  }
167
- if (!provingState.isAcceptingTxs()) {
127
+ if (provingState.totalNumTxs) {
168
128
  throw new Error(`Block ${blockNumber} has been initialized with transactions.`);
169
129
  }
170
- logger.info(`Adding ${txs.length} transactions to block ${blockNumber}`);
171
- const db = this.dbs.get(blockNumber);
172
- const lastArchive = provingState.lastArchiveTreeSnapshot;
173
- const newL1ToL2MessageTreeSnapshot = provingState.newL1ToL2MessageTreeSnapshot;
174
- const spongeBlobState = provingState.getStartSpongeBlob().clone();
130
+ const numBlobFields = toNumBlobFields(txs);
131
+ provingState.startNewBlock(txs.length, numBlobFields);
132
+ logger.info(`Adding ${txs.length} transactions with ${numBlobFields} blob fields to block ${provingState.blockNumber}`);
175
133
  for (const tx of txs){
176
134
  try {
177
135
  if (!provingState.verifyState()) {
@@ -179,21 +137,13 @@ const logger = createLogger('prover-client:orchestrator');
179
137
  }
180
138
  validateTx(tx);
181
139
  logger.info(`Received transaction: ${tx.hash}`);
182
- const startSpongeBlob = spongeBlobState.clone();
183
- const [hints, treeSnapshots] = await this.prepareBaseRollupInputs(tx, lastArchive, newL1ToL2MessageTreeSnapshot, startSpongeBlob, db);
184
- if (!provingState.verifyState()) {
185
- throw new Error(`Unable to add transaction, preparing base inputs failed`);
186
- }
187
- await spongeBlobState.absorb(tx.txEffect.toBlobFields());
188
- const txProvingState = new TxProvingState(tx, hints, treeSnapshots, this.proverId.toField());
140
+ const [hints, treeSnapshots] = await this.prepareTransaction(tx, provingState);
141
+ const txProvingState = new TxProvingState(tx, hints, treeSnapshots);
189
142
  const txIndex = provingState.addNewTx(txProvingState);
143
+ this.getOrEnqueueTube(provingState, txIndex);
190
144
  if (txProvingState.requireAvmProof) {
191
- this.getOrEnqueueChonkVerifier(provingState, txIndex);
192
145
  logger.debug(`Enqueueing public VM for tx ${txIndex}`);
193
146
  this.enqueueVM(provingState, txIndex);
194
- } else {
195
- logger.debug(`Enqueueing base rollup for private-only tx ${txIndex}`);
196
- this.enqueueBaseRollup(provingState, txIndex);
197
147
  }
198
148
  } catch (err) {
199
149
  throw new Error(`Error adding transaction ${tx.hash.toString()} to block ${blockNumber}: ${err.message}`, {
@@ -201,30 +151,21 @@ const logger = createLogger('prover-client:orchestrator');
201
151
  });
202
152
  }
203
153
  }
204
- await spongeBlobState.absorb([
205
- createBlockEndMarker(txs.length)
206
- ]);
207
- provingState.setEndSpongeBlob(spongeBlobState);
208
- // Txs have been added to the block. Now try to accumulate the blobs as far as we can:
209
- await this.provingState.setBlobAccumulators();
210
154
  }
211
155
  /**
212
- * Kickstarts chonk verifier circuits for the specified txs. These will be used during epoch proving.
213
- * Note that if the chonk verifier circuits are not started this way, they will be started nontheless after processing.
214
- */ startChonkVerifierCircuits(txs) {
156
+ * Kickstarts tube circuits for the specified txs. These will be used during epoch proving.
157
+ * Note that if the tube circuits are not started this way, they will be started nontheless after processing.
158
+ */ startTubeCircuits(txs) {
215
159
  if (!this.provingState?.verifyState()) {
216
- throw new Error(`Empty epoch proving state. call startNewEpoch before starting chonk verifier circuits.`);
160
+ throw new Error(`Invalid proving state, call startNewEpoch before starting tube circuits`);
217
161
  }
218
- const publicTxs = txs.filter((tx)=>tx.data.forPublic);
219
- for (const tx of publicTxs){
162
+ for (const tx of txs){
220
163
  const txHash = tx.getTxHash().toString();
221
- const privateInputs = getPublicChonkVerifierPrivateInputsFromTx(tx, this.proverId.toField());
164
+ const tubeInputs = new TubeInputs(!!tx.data.forPublic, tx.clientIvcProof);
222
165
  const tubeProof = promiseWithResolvers();
223
- logger.debug(`Starting chonk verifier circuit for tx ${txHash}`);
224
- this.doEnqueueChonkVerifier(txHash, privateInputs, (proof)=>{
225
- tubeProof.resolve(proof);
226
- });
227
- this.provingState.cachedChonkVerifierProofs.set(txHash, tubeProof.promise);
166
+ logger.debug(`Starting tube circuit for tx ${txHash}`);
167
+ this.doEnqueueTube(txHash, tubeInputs, (proof)=>tubeProof.resolve(proof));
168
+ this.provingState?.cachedTubeProofs.set(txHash, tubeProof.promise);
228
169
  }
229
170
  return Promise.resolve();
230
171
  }
@@ -236,82 +177,57 @@ const logger = createLogger('prover-client:orchestrator');
236
177
  if (!provingState) {
237
178
  throw new Error(`Block proving state for ${blockNumber} not found`);
238
179
  }
239
- // Abort with specific error for the block if there's one.
240
- const error = provingState.getError();
241
- if (error) {
242
- throw new Error(`Block proving failed: ${error}`);
180
+ if (!provingState.spongeBlobState) {
181
+ // If we are completing an empty block, initialize the provingState.
182
+ // We will have 0 txs and no blob fields.
183
+ provingState.startNewBlock(0, 0);
243
184
  }
244
- // Abort if the proving state is not valid due to errors occurred elsewhere.
245
185
  if (!provingState.verifyState()) {
246
- throw new Error(`Invalid proving state when completing block ${blockNumber}.`);
247
- }
248
- if (provingState.isAcceptingTxs()) {
249
- throw new Error(`Block ${blockNumber} is still accepting txs. Call setBlockCompleted after all txs have been added.`);
186
+ throw new Error(`Block proving failed: ${provingState.error}`);
250
187
  }
251
188
  // And build the block header
252
189
  logger.verbose(`Block ${blockNumber} completed. Assembling header.`);
253
- const header = await this.buildL2BlockHeader(provingState, expectedHeader);
254
- await this.verifyBuiltBlockAgainstSyncedState(provingState);
255
- return header;
256
- }
257
- async buildL2BlockHeader(provingState, expectedHeader) {
258
- // Collect all txs in this block to build the header. The function calling this has made sure that all txs have been added.
259
- const txs = provingState.getProcessedTxs();
260
- const startSpongeBlob = provingState.getStartSpongeBlob();
190
+ await this.buildBlock(provingState, expectedHeader);
191
+ logger.debug(`Accumulating blobs for ${blockNumber}`);
192
+ await this.provingState?.setBlobAccumulators(blockNumber);
193
+ // If the proofs were faster than the block building, then we need to try the block root rollup again here
194
+ await this.checkAndEnqueueBlockRootRollup(provingState);
195
+ return provingState.block;
196
+ }
197
+ /** Returns the block as built for a given index. */ getBlock(index) {
198
+ const block = this.provingState?.blocks[index]?.block;
199
+ if (!block) {
200
+ throw new Error(`Block at index ${index} not available`);
201
+ }
202
+ return block;
203
+ }
204
+ async buildBlock(provingState, expectedHeader) {
205
+ // Collect all new nullifiers, commitments, and contracts from all txs in this block to build body
206
+ const txs = provingState.allTxs.map((a)=>a.processedTx);
261
207
  // Get db for this block
262
208
  const db = this.dbs.get(provingState.blockNumber);
263
209
  // Given we've applied every change from this block, now assemble the block header
264
210
  // and update the archive tree, so we're ready to start processing the next block
265
- const header = await buildBlockHeaderFromTxs(txs, provingState.getGlobalVariables(), startSpongeBlob, db);
211
+ const { header, body } = await buildHeaderAndBodyFromTxs(txs, provingState.globalVariables, provingState.newL1ToL2Messages, db);
266
212
  if (expectedHeader && !header.equals(expectedHeader)) {
267
213
  logger.error(`Block header mismatch: header=${header} expectedHeader=${expectedHeader}`);
268
214
  throw new Error('Block header mismatch');
269
215
  }
270
216
  logger.verbose(`Updating archive tree with block ${provingState.blockNumber} header ${(await header.hash()).toString()}`);
271
217
  await db.updateArchive(header);
272
- provingState.setBuiltBlockHeader(header);
273
- return header;
218
+ // Assemble the L2 block
219
+ const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
220
+ const l2Block = new L2Block(newArchive, header, body);
221
+ await this.verifyBuiltBlockAgainstSyncedState(l2Block, newArchive);
222
+ logger.verbose(`Orchestrator finalized block ${l2Block.number}`);
223
+ provingState.setBlock(l2Block);
274
224
  }
275
225
  // Flagged as protected to disable in certain unit tests
276
- async verifyBuiltBlockAgainstSyncedState(provingState) {
277
- const builtBlockHeader = provingState.getBuiltBlockHeader();
278
- if (!builtBlockHeader) {
279
- logger.debug('Block header not built yet, skipping header check.');
280
- return;
281
- }
282
- const output = provingState.getBlockRootRollupOutput();
283
- if (!output) {
284
- logger.debug('Block root rollup proof not built yet, skipping header check.');
285
- return;
286
- }
287
- const header = await buildHeaderFromCircuitOutputs(output);
288
- if (!(await header.hash()).equals(await builtBlockHeader.hash())) {
289
- logger.error(`Block header mismatch.\nCircuit: ${inspect(header)}\nComputed: ${inspect(builtBlockHeader)}`);
290
- provingState.reject(`Block header hash mismatch.`);
291
- return;
292
- }
293
- // Get db for this block
294
- const blockNumber = provingState.blockNumber;
295
- const db = this.dbs.get(blockNumber);
296
- const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
297
- const syncedArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.dbProvider.getSnapshot(blockNumber));
226
+ async verifyBuiltBlockAgainstSyncedState(l2Block, newArchive) {
227
+ const syncedArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.dbProvider.getSnapshot(l2Block.number));
298
228
  if (!syncedArchive.equals(newArchive)) {
299
- logger.error(`Archive tree mismatch for block ${blockNumber}: world state synced to ${inspect(syncedArchive)} but built ${inspect(newArchive)}`);
300
- provingState.reject(`Archive tree mismatch.`);
301
- return;
302
- }
303
- const circuitArchive = output.newArchive;
304
- if (!newArchive.equals(circuitArchive)) {
305
- logger.error(`New archive mismatch.\nCircuit: ${output.newArchive}\nComputed: ${newArchive}`);
306
- provingState.reject(`New archive mismatch.`);
307
- return;
229
+ throw new Error(`Archive tree mismatch for block ${l2Block.number}: world state synced to ${inspect(syncedArchive)} but built ${inspect(newArchive)}`);
308
230
  }
309
- // TODO(palla/prover): This closes the fork only on the happy path. If this epoch orchestrator
310
- // is aborted and never reaches this point, it will leak the fork. We need to add a global cleanup,
311
- // but have to make sure it only runs once all operations are completed, otherwise some function here
312
- // will attempt to access the fork after it was closed.
313
- logger.debug(`Cleaning up world state fork for ${blockNumber}`);
314
- void this.dbs.get(blockNumber)?.close().then(()=>this.dbs.delete(blockNumber)).catch((err)=>logger.error(`Error closing db for block ${blockNumber}`, err));
315
231
  }
316
232
  /**
317
233
  * Cancel any further proving
@@ -331,7 +247,14 @@ const logger = createLogger('prover-client:orchestrator');
331
247
  if (result.status === 'failure') {
332
248
  throw new Error(`Epoch proving failed: ${result.reason}`);
333
249
  }
334
- await this.provingState.finalizeBatchedBlob();
250
+ // TODO(MW): Move this? Requires async and don't want to force root methods to be async
251
+ // TODO(MW): EpochProvingState uses this.blocks.filter(b => !!b).length as total blocks, use this below:
252
+ const finalBlock = this.provingState.blocks[this.provingState.totalNumBlocks - 1];
253
+ if (!finalBlock || !finalBlock.endBlobAccumulator) {
254
+ throw new Error(`Epoch's final block not ready for finalize`);
255
+ }
256
+ const finalBatchedBlob = await finalBlock.endBlobAccumulator.finalize();
257
+ this.provingState.setFinalBatchedBlob(finalBatchedBlob);
335
258
  const epochProofResult = this.provingState.getEpochProofResult();
336
259
  pushTestData('epochProofResult', {
337
260
  proof: epochProofResult.proof.toString(),
@@ -340,12 +263,24 @@ const logger = createLogger('prover-client:orchestrator');
340
263
  return epochProofResult;
341
264
  }
342
265
  /**
266
+ * Starts the proving process for the given transaction and adds it to our state
267
+ * @param tx - The transaction whose proving we wish to commence
268
+ * @param provingState - The proving state being worked on
269
+ */ async prepareTransaction(tx, provingState) {
270
+ const txInputs = await this.prepareBaseRollupInputs(provingState, tx);
271
+ if (!txInputs) {
272
+ // This should not be possible
273
+ throw new Error(`Unable to add transaction, preparing base inputs failed`);
274
+ }
275
+ return txInputs;
276
+ }
277
+ /**
343
278
  * Enqueue a job to be scheduled
344
279
  * @param provingState - The proving state object being operated on
345
280
  * @param jobType - The type of job to be queued
346
281
  * @param job - The actual job, returns a promise notifying of the job's completion
347
282
  */ deferredProving(provingState, request, callback) {
348
- if (!provingState.verifyState()) {
283
+ if (!provingState?.verifyState()) {
349
284
  logger.debug(`Not enqueuing job, state no longer valid`);
350
285
  return;
351
286
  }
@@ -360,7 +295,7 @@ const logger = createLogger('prover-client:orchestrator');
360
295
  return;
361
296
  }
362
297
  const result = await request(controller.signal);
363
- if (!provingState.verifyState()) {
298
+ if (!provingState?.verifyState()) {
364
299
  logger.debug(`State no longer valid, discarding result`);
365
300
  return;
366
301
  }
@@ -388,26 +323,31 @@ const logger = createLogger('prover-client:orchestrator');
388
323
  // let the callstack unwind before adding the job to the queue
389
324
  setImmediate(()=>void safeJob());
390
325
  }
391
- async updateL1ToL2MessageTree(l1ToL2Messages, db) {
326
+ async prepareBaseParityInputs(l1ToL2Messages, db) {
392
327
  const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 'Too many L1 to L2 messages');
393
- const lastL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
394
- const lastL1ToL2MessageSubtreeRootSiblingPath = assertLength(await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db), L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH);
328
+ const baseParityInputs = times(NUM_BASE_PARITY_PER_ROOT_PARITY, (i)=>BaseParityInputs.fromSlice(l1ToL2MessagesPadded, i, getVKTreeRoot()));
329
+ const l1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
330
+ const l1ToL2MessageSubtreeSiblingPath = assertLength(await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db), L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH);
395
331
  // Update the local trees to include the new l1 to l2 messages
396
332
  await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
397
- const newL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
398
- const newL1ToL2MessageSubtreeRootSiblingPath = assertLength(await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db), L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH);
333
+ const l1ToL2MessageTreeSnapshotAfterInsertion = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
399
334
  return {
400
- lastL1ToL2MessageTreeSnapshot,
401
- lastL1ToL2MessageSubtreeRootSiblingPath,
402
- newL1ToL2MessageTreeSnapshot,
403
- newL1ToL2MessageSubtreeRootSiblingPath
335
+ l1ToL2MessageTreeSnapshot,
336
+ l1ToL2MessageSubtreeSiblingPath,
337
+ l1ToL2MessageTreeSnapshotAfterInsertion,
338
+ baseParityInputs
404
339
  };
405
340
  }
406
341
  // Updates the merkle trees for a transaction. The first enqueued job for a transaction
407
- async prepareBaseRollupInputs(tx, lastArchive, newL1ToL2MessageTreeSnapshot, startSpongeBlob, db) {
342
+ async prepareBaseRollupInputs(provingState, tx) {
343
+ if (!provingState.verifyState() || !provingState.spongeBlobState) {
344
+ logger.debug('Not preparing base rollup inputs, state invalid');
345
+ return;
346
+ }
347
+ const db = this.dbs.get(provingState.blockNumber);
408
348
  // We build the base rollup inputs using a mock proof and verification key.
409
- // These will be overwritten later once we have proven the chonk verifier circuit and any public kernels
410
- const [ms, hints] = await elapsed(insertSideEffectsAndBuildBaseRollupHints(tx, lastArchive, newL1ToL2MessageTreeSnapshot, startSpongeBlob, this.proverId.toField(), db));
349
+ // These will be overwritten later once we have proven the tube circuit and any public kernels
350
+ const [ms, hints] = await elapsed(insertSideEffectsAndBuildBaseRollupHints(tx, provingState.globalVariables, provingState.l1ToL2MessageTreeSnapshotAfterInsertion, db, provingState.spongeBlobState));
411
351
  this.metrics.recordBaseRollupInputs(ms);
412
352
  const promises = [
413
353
  MerkleTreeId.NOTE_HASH_TREE,
@@ -423,6 +363,10 @@ const logger = createLogger('prover-client:orchestrator');
423
363
  obj.key,
424
364
  obj.value
425
365
  ]));
366
+ if (!provingState.verifyState()) {
367
+ logger.debug(`Discarding proving job, state no longer valid`);
368
+ return;
369
+ }
426
370
  return [
427
371
  hints,
428
372
  treeSnapshots
@@ -435,71 +379,66 @@ const logger = createLogger('prover-client:orchestrator');
435
379
  logger.debug('Not running base rollup, state invalid');
436
380
  return;
437
381
  }
438
- if (!provingState.tryStartProvingBase(txIndex)) {
439
- logger.debug(`Base rollup for tx ${txIndex} already started.`);
440
- return;
441
- }
442
382
  const txProvingState = provingState.getTxProvingState(txIndex);
443
383
  const { processedTx } = txProvingState;
444
384
  const { rollupType, inputs } = txProvingState.getBaseRollupTypeAndInputs();
445
385
  logger.debug(`Enqueuing deferred proving base rollup for ${processedTx.hash.toString()}`);
446
- this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, `ProvingOrchestrator.prover.${inputs instanceof PrivateTxBaseRollupPrivateInputs ? 'getPrivateTxBaseRollupProof' : 'getPublicTxBaseRollupProof'}`, {
386
+ this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, `ProvingOrchestrator.prover.${inputs instanceof PrivateBaseRollupInputs ? 'getPrivateBaseRollupProof' : 'getPublicBaseRollupProof'}`, {
447
387
  [Attributes.TX_HASH]: processedTx.hash.toString(),
448
388
  [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType
449
389
  }, (signal)=>{
450
- if (inputs instanceof PrivateTxBaseRollupPrivateInputs) {
451
- return this.prover.getPrivateTxBaseRollupProof(inputs, signal, provingState.epochNumber);
390
+ if (inputs instanceof PrivateBaseRollupInputs) {
391
+ return this.prover.getPrivateBaseRollupProof(inputs, signal, provingState.epochNumber);
452
392
  } else {
453
- return this.prover.getPublicTxBaseRollupProof(inputs, signal, provingState.epochNumber);
393
+ return this.prover.getPublicBaseRollupProof(inputs, signal, provingState.epochNumber);
454
394
  }
455
- }), (result)=>{
395
+ }), async (result)=>{
456
396
  logger.debug(`Completed proof for ${rollupType} for tx ${processedTx.hash.toString()}`);
457
- validatePartialState(result.inputs.endTreeSnapshots, txProvingState.treeSnapshots);
397
+ validatePartialState(result.inputs.end, txProvingState.treeSnapshots);
458
398
  const leafLocation = provingState.setBaseRollupProof(txIndex, result);
459
399
  if (provingState.totalNumTxs === 1) {
460
- this.checkAndEnqueueBlockRootRollup(provingState);
400
+ await this.checkAndEnqueueBlockRootRollup(provingState);
461
401
  } else {
462
- this.checkAndEnqueueNextMergeRollup(provingState, leafLocation);
402
+ await this.checkAndEnqueueNextMergeRollup(provingState, leafLocation);
463
403
  }
464
404
  });
465
405
  }
466
- // Enqueues the public chonk verifier circuit for a given transaction index, or reuses the one already enqueued.
467
- // Once completed, will enqueue the the public tx base rollup.
468
- getOrEnqueueChonkVerifier(provingState, txIndex) {
406
+ // Enqueues the tube circuit for a given transaction index, or reuses the one already enqueued
407
+ // Once completed, will enqueue the next circuit, either a public kernel or the base rollup
408
+ getOrEnqueueTube(provingState, txIndex) {
469
409
  if (!provingState.verifyState()) {
470
- logger.debug('Not running chonk verifier circuit, state invalid');
410
+ logger.debug('Not running tube circuit, state invalid');
471
411
  return;
472
412
  }
473
413
  const txProvingState = provingState.getTxProvingState(txIndex);
474
414
  const txHash = txProvingState.processedTx.hash.toString();
475
- NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH;
476
415
  const handleResult = (result)=>{
477
- logger.debug(`Got chonk verifier proof for tx index: ${txIndex}`, {
416
+ logger.debug(`Got tube proof for tx index: ${txIndex}`, {
478
417
  txHash
479
418
  });
480
- txProvingState.setPublicChonkVerifierProof(result);
481
- this.provingState?.cachedChonkVerifierProofs.delete(txHash);
482
- this.checkAndEnqueueBaseRollup(provingState, txIndex);
419
+ txProvingState.setTubeProof(result);
420
+ this.provingState?.cachedTubeProofs.delete(txHash);
421
+ this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
483
422
  };
484
- if (this.provingState?.cachedChonkVerifierProofs.has(txHash)) {
485
- logger.debug(`Chonk verifier proof already enqueued for tx index: ${txIndex}`, {
423
+ if (this.provingState?.cachedTubeProofs.has(txHash)) {
424
+ logger.debug(`Tube proof already enqueued for tx index: ${txIndex}`, {
486
425
  txHash
487
426
  });
488
- void this.provingState.cachedChonkVerifierProofs.get(txHash).then(handleResult);
427
+ void this.provingState.cachedTubeProofs.get(txHash).then(handleResult);
489
428
  return;
490
429
  }
491
- logger.debug(`Enqueuing chonk verifier circuit for tx index: ${txIndex}`);
492
- this.doEnqueueChonkVerifier(txHash, txProvingState.getPublicChonkVerifierPrivateInputs(), handleResult);
430
+ logger.debug(`Enqueuing tube circuit for tx index: ${txIndex}`);
431
+ this.doEnqueueTube(txHash, txProvingState.getTubeInputs(), handleResult);
493
432
  }
494
- doEnqueueChonkVerifier(txHash, inputs, handler, provingState = this.provingState) {
495
- if (!provingState.verifyState()) {
496
- logger.debug('Not running chonk verifier circuit, state invalid');
433
+ doEnqueueTube(txHash, inputs, handler, provingState = this.provingState) {
434
+ if (!provingState?.verifyState()) {
435
+ logger.debug('Not running tube circuit, state invalid');
497
436
  return;
498
437
  }
499
- this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getPublicChonkVerifierProof', {
438
+ this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getTubeProof', {
500
439
  [Attributes.TX_HASH]: txHash,
501
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'chonk-verifier-public'
502
- }, (signal)=>this.prover.getPublicChonkVerifierProof(inputs, signal, provingState.epochNumber)), handler);
440
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'tube-circuit'
441
+ }, (signal)=>this.prover.getTubeProof(inputs, signal, this.provingState.epochNumber)), handler);
503
442
  }
504
443
  // Executes the merge rollup circuit and stored the output as intermediate state for the parent merge/block root circuit
505
444
  // Enqueues the next level of merge if all inputs are available
@@ -508,73 +447,74 @@ const logger = createLogger('prover-client:orchestrator');
508
447
  logger.debug('Not running merge rollup. State no longer valid.');
509
448
  return;
510
449
  }
511
- if (!provingState.tryStartProvingMerge(location)) {
512
- logger.debug('Merge rollup already started.');
513
- return;
514
- }
515
450
  const inputs = provingState.getMergeRollupInputs(location);
516
- this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getTxMergeRollupProof', {
517
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-tx-merge'
518
- }, (signal)=>this.prover.getTxMergeRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
451
+ this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getMergeRollupProof', {
452
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'merge-rollup'
453
+ }, (signal)=>this.prover.getMergeRollupProof(inputs, signal, provingState.epochNumber)), async (result)=>{
519
454
  provingState.setMergeRollupProof(location, result);
520
- this.checkAndEnqueueNextMergeRollup(provingState, location);
455
+ await this.checkAndEnqueueNextMergeRollup(provingState, location);
521
456
  });
522
457
  }
523
458
  // Executes the block root rollup circuit
524
- enqueueBlockRootRollup(provingState) {
459
+ async enqueueBlockRootRollup(provingState) {
525
460
  if (!provingState.verifyState()) {
526
461
  logger.debug('Not running block root rollup, state no longer valid');
527
462
  return;
528
463
  }
529
- if (!provingState.tryStartProvingBlockRoot()) {
530
- logger.debug('Block root rollup already started.');
531
- return;
532
- }
533
- const { rollupType, inputs } = provingState.getBlockRootRollupTypeAndInputs();
534
- logger.debug(`Enqueuing ${rollupType} for block ${provingState.blockNumber}.`);
464
+ provingState.blockRootRollupStarted = true;
465
+ const { rollupType, inputs } = await provingState.getBlockRootRollupTypeAndInputs();
466
+ logger.debug(`Enqueuing ${rollupType} for block ${provingState.blockNumber} with ${provingState.newL1ToL2Messages.length} l1 to l2 msgs.`);
535
467
  this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getBlockRootRollupProof', {
536
468
  [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType
537
469
  }, (signal)=>{
538
- if (inputs instanceof BlockRootFirstRollupPrivateInputs) {
539
- return this.prover.getBlockRootFirstRollupProof(inputs, signal, provingState.epochNumber);
540
- } else if (inputs instanceof BlockRootSingleTxFirstRollupPrivateInputs) {
541
- return this.prover.getBlockRootSingleTxFirstRollupProof(inputs, signal, provingState.epochNumber);
542
- } else if (inputs instanceof BlockRootEmptyTxFirstRollupPrivateInputs) {
543
- return this.prover.getBlockRootEmptyTxFirstRollupProof(inputs, signal, provingState.epochNumber);
544
- } else if (inputs instanceof BlockRootSingleTxRollupPrivateInputs) {
545
- return this.prover.getBlockRootSingleTxRollupProof(inputs, signal, provingState.epochNumber);
470
+ if (inputs instanceof EmptyBlockRootRollupInputs) {
471
+ return this.prover.getEmptyBlockRootRollupProof(inputs, signal, provingState.epochNumber);
472
+ } else if (inputs instanceof SingleTxBlockRootRollupInputs) {
473
+ return this.prover.getSingleTxBlockRootRollupProof(inputs, signal, provingState.epochNumber);
546
474
  } else {
547
475
  return this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber);
548
476
  }
549
477
  }), async (result)=>{
550
- // If the proofs were slower than the block header building, then we need to try validating the block header hashes here.
551
- await this.verifyBuiltBlockAgainstSyncedState(provingState);
552
- logger.debug(`Completed ${rollupType} proof for block ${provingState.blockNumber}`);
553
- const leafLocation = provingState.setBlockRootRollupProof(result);
554
- const checkpointProvingState = provingState.parentCheckpoint;
555
- if (checkpointProvingState.totalNumBlocks === 1) {
556
- this.checkAndEnqueueCheckpointRootRollup(checkpointProvingState);
478
+ provingState.setBlockRootRollupProof(result);
479
+ const header = await provingState.buildHeaderFromProvingOutputs();
480
+ if (!(await header.hash()).equals(await provingState.block.header.hash())) {
481
+ logger.error(`Block header mismatch.\nCircuit: ${inspect(header)}\nComputed: ${inspect(provingState.block.header)}`);
482
+ provingState.reject(`Block header hash mismatch.`);
483
+ }
484
+ const dbArchiveRoot = provingState.block.archive.root;
485
+ const circuitArchiveRoot = result.inputs.newArchive.root;
486
+ if (!dbArchiveRoot.equals(circuitArchiveRoot)) {
487
+ logger.error(`New archive root mismatch.\nCircuit: ${result.inputs.newArchive.root}\nComputed: ${dbArchiveRoot}`);
488
+ provingState.reject(`New archive root mismatch.`);
489
+ }
490
+ const endBlobAccumulatorPublicInputs = BlobAccumulatorPublicInputs.fromBatchedBlobAccumulator(provingState.endBlobAccumulator);
491
+ const circuitEndBlobAccumulatorState = result.inputs.blobPublicInputs.endBlobAccumulator;
492
+ if (!circuitEndBlobAccumulatorState.equals(endBlobAccumulatorPublicInputs)) {
493
+ logger.error(`Blob accumulator state mismatch.\nCircuit: ${inspect(circuitEndBlobAccumulatorState)}\nComputed: ${inspect(endBlobAccumulatorPublicInputs)}`);
494
+ provingState.reject(`Blob accumulator state mismatch.`);
495
+ }
496
+ logger.debug(`Completed ${rollupType} proof for block ${provingState.block.number}`);
497
+ // validatePartialState(result.inputs.end, tx.treeSnapshots); // TODO(palla/prover)
498
+ const epochProvingState = this.provingState;
499
+ const leafLocation = epochProvingState.setBlockRootRollupProof(provingState.index, result);
500
+ if (epochProvingState.totalNumBlocks === 1) {
501
+ this.enqueueEpochPadding(epochProvingState);
557
502
  } else {
558
- this.checkAndEnqueueNextBlockMergeRollup(checkpointProvingState, leafLocation);
503
+ this.checkAndEnqueueNextBlockMergeRollup(epochProvingState, leafLocation);
559
504
  }
560
505
  });
561
506
  }
562
507
  // Executes the base parity circuit and stores the intermediate state for the root parity circuit
563
508
  // Enqueues the root parity circuit if all inputs are available
564
- enqueueBaseParityCircuit(checkpointProvingState, provingState, baseParityIndex) {
509
+ enqueueBaseParityCircuit(provingState, inputs, index) {
565
510
  if (!provingState.verifyState()) {
566
511
  logger.debug('Not running base parity. State no longer valid.');
567
512
  return;
568
513
  }
569
- if (!provingState.tryStartProvingBaseParity(baseParityIndex)) {
570
- logger.warn(`Base parity ${baseParityIndex} already started.`);
571
- return;
572
- }
573
- const inputs = checkpointProvingState.getBaseParityInputs(baseParityIndex);
574
514
  this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getBaseParityProof', {
575
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'parity-base'
515
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'base-parity'
576
516
  }, (signal)=>this.prover.getBaseParityProof(inputs, signal, provingState.epochNumber)), (provingOutput)=>{
577
- provingState.setBaseParityProof(baseParityIndex, provingOutput);
517
+ provingState.setBaseParityProof(index, provingOutput);
578
518
  this.checkAndEnqueueRootParityCircuit(provingState);
579
519
  });
580
520
  }
@@ -591,16 +531,12 @@ const logger = createLogger('prover-client:orchestrator');
591
531
  logger.debug('Not running root parity. State no longer valid.');
592
532
  return;
593
533
  }
594
- if (!provingState.tryStartProvingRootParity()) {
595
- logger.debug('Root parity already started.');
596
- return;
597
- }
598
- const inputs = provingState.getParityRootInputs();
534
+ const inputs = provingState.getRootParityInputs();
599
535
  this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getRootParityProof', {
600
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'parity-root'
601
- }, (signal)=>this.prover.getRootParityProof(inputs, signal, provingState.epochNumber)), (result)=>{
536
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-parity'
537
+ }, (signal)=>this.prover.getRootParityProof(inputs, signal, provingState.epochNumber)), async (result)=>{
602
538
  provingState.setRootParityProof(result);
603
- this.checkAndEnqueueBlockRootRollup(provingState);
539
+ await this.checkAndEnqueueBlockRootRollup(provingState);
604
540
  });
605
541
  }
606
542
  // Executes the block merge rollup circuit and stored the output as intermediate state for the parent merge/block root circuit
@@ -610,90 +546,26 @@ const logger = createLogger('prover-client:orchestrator');
610
546
  logger.debug('Not running block merge rollup. State no longer valid.');
611
547
  return;
612
548
  }
613
- if (!provingState.tryStartProvingBlockMerge(location)) {
614
- logger.debug('Block merge rollup already started.');
615
- return;
616
- }
617
549
  const inputs = provingState.getBlockMergeRollupInputs(location);
618
550
  this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getBlockMergeRollupProof', {
619
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-block-merge'
551
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'block-merge-rollup'
620
552
  }, (signal)=>this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
621
553
  provingState.setBlockMergeRollupProof(location, result);
622
554
  this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
623
555
  });
624
556
  }
625
- enqueueCheckpointRootRollup(provingState) {
626
- if (!provingState.verifyState()) {
627
- logger.debug('Not running checkpoint root rollup. State no longer valid.');
628
- return;
629
- }
630
- if (!provingState.tryStartProvingCheckpointRoot()) {
631
- logger.debug('Checkpoint root rollup already started.');
632
- return;
633
- }
634
- const rollupType = provingState.getCheckpointRootRollupType();
635
- logger.debug(`Enqueuing ${rollupType} for checkpoint ${provingState.index}.`);
636
- const inputs = provingState.getCheckpointRootRollupInputs();
637
- this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getCheckpointRootRollupProof', {
638
- [Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType
639
- }, (signal)=>{
640
- if (inputs instanceof CheckpointRootSingleBlockRollupPrivateInputs) {
641
- return this.prover.getCheckpointRootSingleBlockRollupProof(inputs, signal, provingState.epochNumber);
642
- } else {
643
- return this.prover.getCheckpointRootRollupProof(inputs, signal, provingState.epochNumber);
644
- }
645
- }), (result)=>{
646
- const computedEndBlobAccumulatorState = provingState.getEndBlobAccumulator().toBlobAccumulator();
647
- const circuitEndBlobAccumulatorState = result.inputs.endBlobAccumulator;
648
- if (!circuitEndBlobAccumulatorState.equals(computedEndBlobAccumulatorState)) {
649
- logger.error(`Blob accumulator state mismatch.\nCircuit: ${inspect(circuitEndBlobAccumulatorState)}\nComputed: ${inspect(computedEndBlobAccumulatorState)}`);
650
- provingState.reject(`Blob accumulator state mismatch.`);
651
- return;
652
- }
653
- logger.debug(`Completed ${rollupType} proof for checkpoint ${provingState.index}.`);
654
- const leafLocation = provingState.setCheckpointRootRollupProof(result);
655
- const epochProvingState = provingState.parentEpoch;
656
- if (epochProvingState.totalNumCheckpoints === 1) {
657
- this.enqueueEpochPadding(epochProvingState);
658
- } else {
659
- this.checkAndEnqueueNextCheckpointMergeRollup(epochProvingState, leafLocation);
660
- }
661
- });
662
- }
663
- enqueueCheckpointMergeRollup(provingState, location) {
664
- if (!provingState.verifyState()) {
665
- logger.debug('Not running checkpoint merge rollup. State no longer valid.');
666
- return;
667
- }
668
- if (!provingState.tryStartProvingCheckpointMerge(location)) {
669
- logger.debug('Checkpoint merge rollup already started.');
670
- return;
671
- }
672
- const inputs = provingState.getCheckpointMergeRollupInputs(location);
673
- this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getCheckpointMergeRollupProof', {
674
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-merge'
675
- }, (signal)=>this.prover.getCheckpointMergeRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
676
- logger.debug('Completed proof for checkpoint merge rollup.');
677
- provingState.setCheckpointMergeRollupProof(location, result);
678
- this.checkAndEnqueueNextCheckpointMergeRollup(provingState, location);
679
- });
680
- }
681
557
  enqueueEpochPadding(provingState) {
682
558
  if (!provingState.verifyState()) {
683
559
  logger.debug('Not running epoch padding. State no longer valid.');
684
560
  return;
685
561
  }
686
- if (!provingState.tryStartProvingPaddingCheckpoint()) {
687
- logger.debug('Padding checkpoint already started.');
688
- return;
689
- }
690
562
  logger.debug('Padding epoch proof with a padding block root proof.');
691
- const inputs = provingState.getPaddingCheckpointInputs();
692
- this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getCheckpointPaddingRollupProof', {
693
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-padding'
694
- }, (signal)=>this.prover.getCheckpointPaddingRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
695
- logger.debug('Completed proof for padding checkpoint.');
696
- provingState.setCheckpointPaddingProof(result);
563
+ const inputs = provingState.getPaddingBlockRootInputs();
564
+ this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getPaddingBlockRootRollupProof', {
565
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'padding-block-root-rollup'
566
+ }, (signal)=>this.prover.getPaddingBlockRootRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
567
+ logger.debug('Completed proof for padding block root.');
568
+ provingState.setPaddingBlockRootProof(result);
697
569
  this.checkAndEnqueueRootRollup(provingState);
698
570
  });
699
571
  }
@@ -706,7 +578,7 @@ const logger = createLogger('prover-client:orchestrator');
706
578
  logger.debug(`Preparing root rollup`);
707
579
  const inputs = provingState.getRootRollupInputs();
708
580
  this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getRootRollupProof', {
709
- [Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-root'
581
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-rollup'
710
582
  }, (signal)=>this.prover.getRootRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
711
583
  logger.verbose(`Orchestrator completed root rollup for epoch ${provingState.epochNumber}`);
712
584
  provingState.setRootRollupProof(result);
@@ -715,50 +587,46 @@ const logger = createLogger('prover-client:orchestrator');
715
587
  });
716
588
  });
717
589
  }
718
- checkAndEnqueueNextMergeRollup(provingState, currentLocation) {
590
+ async checkAndEnqueueNextMergeRollup(provingState, currentLocation) {
719
591
  if (!provingState.isReadyForMergeRollup(currentLocation)) {
720
592
  return;
721
593
  }
722
594
  const parentLocation = provingState.getParentLocation(currentLocation);
723
595
  if (parentLocation.level === 0) {
724
- this.checkAndEnqueueBlockRootRollup(provingState);
596
+ await this.checkAndEnqueueBlockRootRollup(provingState);
725
597
  } else {
726
598
  this.enqueueMergeRollup(provingState, parentLocation);
727
599
  }
728
600
  }
729
- checkAndEnqueueBlockRootRollup(provingState) {
601
+ async checkAndEnqueueBlockRootRollup(provingState) {
602
+ const blockNumber = provingState.blockNumber;
603
+ // Accumulate as far as we can, in case blocks came in out of order and we are behind:
604
+ await this.provingState?.setBlobAccumulators(blockNumber);
730
605
  if (!provingState.isReadyForBlockRootRollup()) {
731
606
  logger.debug('Not ready for block root rollup');
732
607
  return;
733
608
  }
734
- this.enqueueBlockRootRollup(provingState);
735
- }
736
- checkAndEnqueueNextBlockMergeRollup(provingState, currentLocation) {
737
- if (!provingState.isReadyForBlockMerge(currentLocation)) {
609
+ if (provingState.blockRootRollupStarted) {
610
+ logger.debug('Block root rollup already started');
738
611
  return;
739
612
  }
740
- const parentLocation = provingState.getParentLocation(currentLocation);
741
- if (parentLocation.level === 0) {
742
- this.checkAndEnqueueCheckpointRootRollup(provingState);
743
- } else {
744
- this.enqueueBlockMergeRollup(provingState, parentLocation);
745
- }
746
- }
747
- checkAndEnqueueCheckpointRootRollup(provingState) {
748
- if (!provingState.isReadyForCheckpointRoot()) {
749
- return;
750
- }
751
- this.enqueueCheckpointRootRollup(provingState);
613
+ // TODO(palla/prover): This closes the fork only on the happy path. If this epoch orchestrator
614
+ // is aborted and never reaches this point, it will leak the fork. We need to add a global cleanup,
615
+ // but have to make sure it only runs once all operations are completed, otherwise some function here
616
+ // will attempt to access the fork after it was closed.
617
+ logger.debug(`Cleaning up world state fork for ${blockNumber}`);
618
+ void this.dbs.get(blockNumber)?.close().then(()=>this.dbs.delete(blockNumber)).catch((err)=>logger.error(`Error closing db for block ${blockNumber}`, err));
619
+ await this.enqueueBlockRootRollup(provingState);
752
620
  }
753
- checkAndEnqueueNextCheckpointMergeRollup(provingState, currentLocation) {
754
- if (!provingState.isReadyForCheckpointMerge(currentLocation)) {
621
+ checkAndEnqueueNextBlockMergeRollup(provingState, currentLocation) {
622
+ if (!provingState.isReadyForBlockMerge(currentLocation)) {
755
623
  return;
756
624
  }
757
625
  const parentLocation = provingState.getParentLocation(currentLocation);
758
626
  if (parentLocation.level === 0) {
759
627
  this.checkAndEnqueueRootRollup(provingState);
760
628
  } else {
761
- this.enqueueCheckpointMergeRollup(provingState, parentLocation);
629
+ this.enqueueBlockMergeRollup(provingState, parentLocation);
762
630
  }
763
631
  }
764
632
  checkAndEnqueueRootRollup(provingState) {
@@ -810,22 +678,22 @@ const logger = createLogger('prover-client:orchestrator');
810
678
  this.deferredProving(provingState, doAvmProving, (proofAndVk)=>{
811
679
  logger.debug(`Proven VM for tx index: ${txIndex}`);
812
680
  txProvingState.setAvmProof(proofAndVk);
813
- this.checkAndEnqueueBaseRollup(provingState, txIndex);
681
+ this.checkAndEnqueueNextTxCircuit(provingState, txIndex);
814
682
  });
815
683
  }
816
- checkAndEnqueueBaseRollup(provingState, txIndex) {
684
+ checkAndEnqueueNextTxCircuit(provingState, txIndex) {
817
685
  const txProvingState = provingState.getTxProvingState(txIndex);
818
686
  if (!txProvingState.ready()) {
819
687
  return;
820
688
  }
821
- // We must have completed all proving (chonk verifier proof and (if required) vm proof are generated), we now move to the base rollup.
689
+ // We must have completed all proving (tube proof and (if required) vm proof are generated), we now move to the base rollup.
822
690
  logger.debug(`Public functions completed for tx ${txIndex} enqueueing base rollup`);
823
691
  this.enqueueBaseRollup(provingState, txIndex);
824
692
  }
825
693
  }
826
694
  _ts_decorate([
827
- trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
828
- [Attributes.BLOCK_NUMBER]: blockNumber
695
+ trackSpan('ProvingOrchestrator.startNewBlock', (globalVariables)=>({
696
+ [Attributes.BLOCK_NUMBER]: globalVariables.blockNumber
829
697
  }))
830
698
  ], ProvingOrchestrator.prototype, "startNewBlock", null);
831
699
  _ts_decorate([
@@ -834,15 +702,15 @@ _ts_decorate([
834
702
  }))
835
703
  ], ProvingOrchestrator.prototype, "addTxs", null);
836
704
  _ts_decorate([
837
- trackSpan('ProvingOrchestrator.startChonkVerifierCircuits')
838
- ], ProvingOrchestrator.prototype, "startChonkVerifierCircuits", null);
705
+ trackSpan('ProvingOrchestrator.startTubeCircuits')
706
+ ], ProvingOrchestrator.prototype, "startTubeCircuits", null);
839
707
  _ts_decorate([
840
708
  trackSpan('ProvingOrchestrator.setBlockCompleted', (blockNumber)=>({
841
709
  [Attributes.BLOCK_NUMBER]: blockNumber
842
710
  }))
843
711
  ], ProvingOrchestrator.prototype, "setBlockCompleted", null);
844
712
  _ts_decorate([
845
- trackSpan('ProvingOrchestrator.prepareBaseRollupInputs', (tx)=>({
713
+ trackSpan('ProvingOrchestrator.prepareBaseRollupInputs', (_, tx)=>({
846
714
  [Attributes.TX_HASH]: tx.hash.toString()
847
715
  }))
848
716
  ], ProvingOrchestrator.prototype, "prepareBaseRollupInputs", null);