@aztec/prover-client 0.0.0-test.1 → 0.0.1-commit.0b941701

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