@aztec/prover-client 0.0.0-test.1 → 0.0.1-commit.023c3e5

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