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