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