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