@aztec/prover-node 0.0.1-commit.b655e406 → 0.0.1-commit.c7c42ec
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/actions/download-epoch-proving-job.d.ts +4 -4
- package/dest/actions/index.d.ts +1 -1
- package/dest/actions/rerun-epoch-proving-job.d.ts +2 -2
- package/dest/actions/upload-epoch-proof-failure.d.ts +1 -1
- package/dest/bin/run-failed-epoch.d.ts +1 -1
- package/dest/config.d.ts +5 -4
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +4 -3
- package/dest/factory.d.ts +4 -4
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +11 -7
- package/dest/index.d.ts +1 -1
- package/dest/job/epoch-proving-job-data.d.ts +8 -6
- package/dest/job/epoch-proving-job-data.d.ts.map +1 -1
- package/dest/job/epoch-proving-job-data.js +25 -18
- package/dest/job/epoch-proving-job.d.ts +5 -12
- package/dest/job/epoch-proving-job.d.ts.map +1 -1
- package/dest/job/epoch-proving-job.js +93 -83
- package/dest/metrics.d.ts +4 -3
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +8 -2
- package/dest/monitors/epoch-monitor.d.ts +3 -2
- package/dest/monitors/epoch-monitor.d.ts.map +1 -1
- package/dest/monitors/epoch-monitor.js +2 -1
- package/dest/monitors/index.d.ts +1 -1
- package/dest/prover-node-publisher.d.ts +9 -7
- package/dest/prover-node-publisher.d.ts.map +1 -1
- package/dest/prover-node-publisher.js +43 -37
- package/dest/prover-node.d.ts +8 -7
- package/dest/prover-node.d.ts.map +1 -1
- package/dest/prover-node.js +35 -32
- package/dest/prover-publisher-factory.d.ts +4 -2
- package/dest/prover-publisher-factory.d.ts.map +1 -1
- package/dest/test/index.d.ts +1 -1
- package/dest/test/index.d.ts.map +1 -1
- package/package.json +26 -25
- package/src/bin/run-failed-epoch.ts +1 -1
- package/src/config.ts +6 -4
- package/src/factory.ts +13 -8
- package/src/job/epoch-proving-job-data.ts +31 -25
- package/src/job/epoch-proving-job.ts +107 -100
- package/src/metrics.ts +15 -3
- package/src/monitors/epoch-monitor.ts +4 -3
- package/src/prover-node-publisher.ts +62 -52
- package/src/prover-node.ts +47 -43
- package/src/prover-publisher-factory.ts +3 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
2
|
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
3
|
+
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
3
4
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
4
|
-
import { Fr } from '@aztec/foundation/
|
|
5
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
6
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
7
|
import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
7
8
|
import { Timer } from '@aztec/foundation/timer';
|
|
@@ -9,7 +10,9 @@ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
|
9
10
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
10
11
|
import { buildFinalBlobChallenges } from '@aztec/prover-client/helpers';
|
|
11
12
|
import type { PublicProcessor, PublicProcessorFactory } from '@aztec/simulator/server';
|
|
12
|
-
import
|
|
13
|
+
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
14
|
+
import type { L2BlockNew, L2BlockSource } from '@aztec/stdlib/block';
|
|
15
|
+
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
13
16
|
import {
|
|
14
17
|
type EpochProver,
|
|
15
18
|
type EpochProvingJobState,
|
|
@@ -73,7 +76,7 @@ export class EpochProvingJob implements Traceable {
|
|
|
73
76
|
return this.state;
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
public getEpochNumber():
|
|
79
|
+
public getEpochNumber(): EpochNumber {
|
|
77
80
|
return this.data.epochNumber;
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -89,8 +92,8 @@ export class EpochProvingJob implements Traceable {
|
|
|
89
92
|
return this.data.epochNumber;
|
|
90
93
|
}
|
|
91
94
|
|
|
92
|
-
private get
|
|
93
|
-
return this.data.
|
|
95
|
+
private get checkpoints() {
|
|
96
|
+
return this.data.checkpoints;
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
private get txs() {
|
|
@@ -105,7 +108,7 @@ export class EpochProvingJob implements Traceable {
|
|
|
105
108
|
* Proves the given epoch and submits the proof to L1.
|
|
106
109
|
*/
|
|
107
110
|
@trackSpan('EpochProvingJob.run', function () {
|
|
108
|
-
return { [Attributes.EPOCH_NUMBER]:
|
|
111
|
+
return { [Attributes.EPOCH_NUMBER]: this.data.epochNumber };
|
|
109
112
|
})
|
|
110
113
|
public async run() {
|
|
111
114
|
this.scheduleDeadlineStop();
|
|
@@ -114,14 +117,22 @@ export class EpochProvingJob implements Traceable {
|
|
|
114
117
|
}
|
|
115
118
|
|
|
116
119
|
const attestations = this.attestations.map(attestation => attestation.toViem());
|
|
117
|
-
const epochNumber =
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
120
|
+
const epochNumber = this.epochNumber;
|
|
121
|
+
const epochSizeCheckpoints = this.checkpoints.length;
|
|
122
|
+
const epochSizeBlocks = this.checkpoints.reduce((accum, checkpoint) => accum + checkpoint.blocks.length, 0);
|
|
123
|
+
const epochSizeTxs = this.checkpoints.reduce(
|
|
124
|
+
(accum, checkpoint) =>
|
|
125
|
+
accum + checkpoint.blocks.reduce((accumC, block) => accumC + block.body.txEffects.length, 0),
|
|
126
|
+
0,
|
|
127
|
+
);
|
|
128
|
+
const fromCheckpoint = this.checkpoints[0].number;
|
|
129
|
+
const toCheckpoint = this.checkpoints.at(-1)!.number;
|
|
130
|
+
const fromBlock = this.checkpoints[0].blocks[0].number;
|
|
131
|
+
const toBlock = this.checkpoints.at(-1)!.blocks.at(-1)!.number;
|
|
132
|
+
this.log.info(`Starting epoch ${epochNumber} proving job with checkpoints ${fromCheckpoint} to ${toCheckpoint}`, {
|
|
122
133
|
fromBlock,
|
|
123
134
|
toBlock,
|
|
124
|
-
|
|
135
|
+
epochSizeTxs,
|
|
125
136
|
epochNumber,
|
|
126
137
|
uuid: this.uuid,
|
|
127
138
|
});
|
|
@@ -132,83 +143,93 @@ export class EpochProvingJob implements Traceable {
|
|
|
132
143
|
this.runPromise = promise;
|
|
133
144
|
|
|
134
145
|
try {
|
|
135
|
-
const blobFieldsPerCheckpoint = this.
|
|
146
|
+
const blobFieldsPerCheckpoint = this.checkpoints.map(checkpoint => checkpoint.toBlobFields());
|
|
136
147
|
const finalBlobBatchingChallenges = await buildFinalBlobChallenges(blobFieldsPerCheckpoint);
|
|
137
148
|
|
|
138
|
-
|
|
139
|
-
// Total number of checkpoints equals number of blocks because we currently build a checkpoint with only one block.
|
|
140
|
-
const totalNumCheckpoints = epochSizeBlocks;
|
|
141
|
-
|
|
142
|
-
this.prover.startNewEpoch(epochNumber, totalNumCheckpoints, finalBlobBatchingChallenges);
|
|
149
|
+
this.prover.startNewEpoch(epochNumber, epochSizeCheckpoints, finalBlobBatchingChallenges);
|
|
143
150
|
await this.prover.startChonkVerifierCircuits(Array.from(this.txs.values()));
|
|
144
151
|
|
|
145
|
-
|
|
146
|
-
|
|
152
|
+
// Everything in the epoch should have the same chainId and version.
|
|
153
|
+
const { chainId, version } = this.checkpoints[0].blocks[0].header.globalVariables;
|
|
147
154
|
|
|
148
|
-
|
|
149
|
-
const txs = this.getTxs(block);
|
|
150
|
-
const l1ToL2Messages = this.getL1ToL2Messages(block);
|
|
151
|
-
const previousHeader = this.getBlockHeader(block.number - 1)!;
|
|
152
|
-
|
|
153
|
-
this.log.verbose(`Starting processing block ${block.number}`, {
|
|
154
|
-
number: block.number,
|
|
155
|
-
blockHash: (await block.hash()).toString(),
|
|
156
|
-
lastArchive: block.header.lastArchive.root,
|
|
157
|
-
noteHashTreeRoot: block.header.state.partial.noteHashTree.root,
|
|
158
|
-
nullifierTreeRoot: block.header.state.partial.nullifierTree.root,
|
|
159
|
-
publicDataTreeRoot: block.header.state.partial.publicDataTree.root,
|
|
160
|
-
previousHeader: previousHeader.hash(),
|
|
161
|
-
uuid: this.uuid,
|
|
162
|
-
...globalVariables,
|
|
163
|
-
});
|
|
155
|
+
const previousBlockHeaders = this.gatherPreviousBlockHeaders();
|
|
164
156
|
|
|
157
|
+
await asyncPool(this.config.parallelBlockLimit ?? 32, this.checkpoints, async checkpoint => {
|
|
158
|
+
this.checkState();
|
|
159
|
+
|
|
160
|
+
const checkpointIndex = checkpoint.number - fromCheckpoint;
|
|
165
161
|
const checkpointConstants = CheckpointConstantData.from({
|
|
166
|
-
chainId
|
|
167
|
-
version
|
|
162
|
+
chainId,
|
|
163
|
+
version,
|
|
168
164
|
vkTreeRoot: getVKTreeRoot(),
|
|
169
165
|
protocolContractsHash: protocolContractsHash,
|
|
170
166
|
proverId: this.prover.getProverId().toField(),
|
|
171
|
-
slotNumber:
|
|
172
|
-
coinbase:
|
|
173
|
-
feeRecipient:
|
|
174
|
-
gasFees:
|
|
167
|
+
slotNumber: checkpoint.header.slotNumber,
|
|
168
|
+
coinbase: checkpoint.header.coinbase,
|
|
169
|
+
feeRecipient: checkpoint.header.feeRecipient,
|
|
170
|
+
gasFees: checkpoint.header.gasFees,
|
|
171
|
+
});
|
|
172
|
+
const previousHeader = previousBlockHeaders[checkpointIndex];
|
|
173
|
+
const l1ToL2Messages = this.getL1ToL2Messages(checkpoint);
|
|
174
|
+
|
|
175
|
+
this.log.verbose(`Starting processing checkpoint ${checkpoint.number}`, {
|
|
176
|
+
number: checkpoint.number,
|
|
177
|
+
checkpointHash: checkpoint.hash().toString(),
|
|
178
|
+
lastArchive: checkpoint.header.lastArchiveRoot,
|
|
179
|
+
previousHeader: previousHeader.hash(),
|
|
180
|
+
uuid: this.uuid,
|
|
175
181
|
});
|
|
176
182
|
|
|
177
|
-
// TODO(#17027): Enable multiple blocks per checkpoint.
|
|
178
|
-
// Each checkpoint has only one block.
|
|
179
|
-
const totalNumBlocks = 1;
|
|
180
|
-
const checkpointIndex = block.number - fromBlock;
|
|
181
183
|
await this.prover.startNewCheckpoint(
|
|
182
184
|
checkpointIndex,
|
|
183
185
|
checkpointConstants,
|
|
184
186
|
l1ToL2Messages,
|
|
185
|
-
|
|
186
|
-
blobFieldsPerCheckpoint[checkpointIndex].length,
|
|
187
|
+
checkpoint.blocks.length,
|
|
187
188
|
previousHeader,
|
|
188
189
|
);
|
|
189
190
|
|
|
190
|
-
|
|
191
|
-
|
|
191
|
+
for (const block of checkpoint.blocks) {
|
|
192
|
+
const globalVariables = block.header.globalVariables;
|
|
193
|
+
const txs = this.getTxs(block);
|
|
194
|
+
|
|
195
|
+
this.log.verbose(`Starting processing block ${block.number}`, {
|
|
196
|
+
number: block.number,
|
|
197
|
+
blockHash: (await block.hash()).toString(),
|
|
198
|
+
lastArchive: block.header.lastArchive.root,
|
|
199
|
+
noteHashTreeRoot: block.header.state.partial.noteHashTree.root,
|
|
200
|
+
nullifierTreeRoot: block.header.state.partial.nullifierTree.root,
|
|
201
|
+
publicDataTreeRoot: block.header.state.partial.publicDataTree.root,
|
|
202
|
+
...globalVariables,
|
|
203
|
+
numTxs: txs.length,
|
|
204
|
+
});
|
|
192
205
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
// Start block proving
|
|
207
|
+
await this.prover.startNewBlock(block.number, globalVariables.timestamp, txs.length);
|
|
208
|
+
|
|
209
|
+
// Process public fns
|
|
210
|
+
const db = await this.createFork(BlockNumber(block.number - 1), l1ToL2Messages);
|
|
211
|
+
const config = PublicSimulatorConfig.from({
|
|
212
|
+
proverId: this.prover.getProverId().toField(),
|
|
213
|
+
skipFeeEnforcement: false,
|
|
214
|
+
collectDebugLogs: false,
|
|
215
|
+
collectHints: true,
|
|
216
|
+
collectPublicInputs: true,
|
|
217
|
+
collectStatistics: false,
|
|
218
|
+
});
|
|
219
|
+
const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, config);
|
|
220
|
+
const processed = await this.processTxs(publicProcessor, txs);
|
|
221
|
+
await this.prover.addTxs(processed);
|
|
222
|
+
await db.close();
|
|
223
|
+
this.log.verbose(`Processed all ${txs.length} txs for block ${block.number}`, {
|
|
224
|
+
blockNumber: block.number,
|
|
225
|
+
blockHash: (await block.hash()).toString(),
|
|
226
|
+
uuid: this.uuid,
|
|
227
|
+
});
|
|
208
228
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
229
|
+
// Mark block as completed to pad it
|
|
230
|
+
const expectedBlockHeader = block.header;
|
|
231
|
+
await this.prover.setBlockCompleted(block.number, expectedBlockHeader);
|
|
232
|
+
}
|
|
212
233
|
});
|
|
213
234
|
|
|
214
235
|
const executionTime = timer.ms();
|
|
@@ -221,16 +242,16 @@ export class EpochProvingJob implements Traceable {
|
|
|
221
242
|
|
|
222
243
|
if (this.config.skipSubmitProof) {
|
|
223
244
|
this.log.info(
|
|
224
|
-
`Proof publishing is disabled. Dropping valid proof for epoch ${epochNumber} (
|
|
245
|
+
`Proof publishing is disabled. Dropping valid proof for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`,
|
|
225
246
|
);
|
|
226
247
|
this.state = 'completed';
|
|
227
|
-
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeBlocks, epochSizeTxs);
|
|
248
|
+
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeCheckpoints, epochSizeBlocks, epochSizeTxs);
|
|
228
249
|
return;
|
|
229
250
|
}
|
|
230
251
|
|
|
231
252
|
const success = await this.publisher.submitEpochProof({
|
|
232
|
-
|
|
233
|
-
|
|
253
|
+
fromCheckpoint,
|
|
254
|
+
toCheckpoint,
|
|
234
255
|
epochNumber,
|
|
235
256
|
publicInputs,
|
|
236
257
|
proof,
|
|
@@ -241,12 +262,12 @@ export class EpochProvingJob implements Traceable {
|
|
|
241
262
|
throw new Error('Failed to submit epoch proof to L1');
|
|
242
263
|
}
|
|
243
264
|
|
|
244
|
-
this.log.info(`Submitted proof for epoch ${epochNumber} (
|
|
265
|
+
this.log.info(`Submitted proof for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`, {
|
|
245
266
|
epochNumber,
|
|
246
267
|
uuid: this.uuid,
|
|
247
268
|
});
|
|
248
269
|
this.state = 'completed';
|
|
249
|
-
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeBlocks, epochSizeTxs);
|
|
270
|
+
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeCheckpoints, epochSizeBlocks, epochSizeTxs);
|
|
250
271
|
} catch (err: any) {
|
|
251
272
|
if (err && err.name === 'HaltExecutionError') {
|
|
252
273
|
this.log.warn(`Halted execution of epoch ${epochNumber} prover job`, {
|
|
@@ -272,7 +293,7 @@ export class EpochProvingJob implements Traceable {
|
|
|
272
293
|
* Create a new db fork for tx processing, inserting all L1 to L2.
|
|
273
294
|
* REFACTOR: The prover already spawns a db fork of its own for each block, so we may be able to do away with just one fork.
|
|
274
295
|
*/
|
|
275
|
-
private async createFork(blockNumber:
|
|
296
|
+
private async createFork(blockNumber: BlockNumber, l1ToL2Messages: Fr[]) {
|
|
276
297
|
const db = await this.dbProvider.fork(blockNumber);
|
|
277
298
|
const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
|
|
278
299
|
l1ToL2Messages,
|
|
@@ -282,7 +303,7 @@ export class EpochProvingJob implements Traceable {
|
|
|
282
303
|
);
|
|
283
304
|
this.log.verbose(`Creating fork at ${blockNumber} with ${l1ToL2Messages.length} L1 to L2 messages`, {
|
|
284
305
|
blockNumber,
|
|
285
|
-
l1ToL2Messages:
|
|
306
|
+
l1ToL2Messages: l1ToL2Messages.map(m => m.toString()),
|
|
286
307
|
});
|
|
287
308
|
await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
|
|
288
309
|
return db;
|
|
@@ -343,11 +364,9 @@ export class EpochProvingJob implements Traceable {
|
|
|
343
364
|
async () => {
|
|
344
365
|
const blocks = await l2BlockSource.getBlockHeadersForEpoch(this.epochNumber);
|
|
345
366
|
const blockHashes = await Promise.all(blocks.map(block => block.hash()));
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
!blockHashes.every((block, i) => block.equals(thisBlockHashes[i]))
|
|
350
|
-
) {
|
|
367
|
+
const thisBlocks = this.checkpoints.flatMap(checkpoint => checkpoint.blocks);
|
|
368
|
+
const thisBlockHashes = await Promise.all(thisBlocks.map(block => block.hash()));
|
|
369
|
+
if (blocks.length !== thisBlocks.length || !blockHashes.every((block, i) => block.equals(thisBlockHashes[i]))) {
|
|
351
370
|
this.log.warn('Epoch blocks changed underfoot', {
|
|
352
371
|
uuid: this.uuid,
|
|
353
372
|
epochNumber: this.epochNumber,
|
|
@@ -363,30 +382,18 @@ export class EpochProvingJob implements Traceable {
|
|
|
363
382
|
this.log.verbose(`Scheduled epoch check for epoch ${this.epochNumber} every ${intervalMs}ms`);
|
|
364
383
|
}
|
|
365
384
|
|
|
366
|
-
/* Returns the header
|
|
367
|
-
private
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
return block.getBlockHeader();
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (blockNumber === Number(this.data.previousBlockHeader.getBlockNumber())) {
|
|
374
|
-
return this.data.previousBlockHeader;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
throw new Error(
|
|
378
|
-
`Block header not found for block number ${blockNumber} (got ${this.blocks
|
|
379
|
-
.map(b => b.number)
|
|
380
|
-
.join(', ')} and previous header ${this.data.previousBlockHeader.getBlockNumber()})`,
|
|
381
|
-
);
|
|
385
|
+
/* Returns the last block header in the previous checkpoint for all checkpoints in the epoch */
|
|
386
|
+
private gatherPreviousBlockHeaders() {
|
|
387
|
+
const lastBlocks = this.checkpoints.map(checkpoint => checkpoint.blocks.at(-1)!);
|
|
388
|
+
return [this.data.previousBlockHeader, ...lastBlocks.map(block => block.header).slice(0, -1)];
|
|
382
389
|
}
|
|
383
390
|
|
|
384
|
-
private getTxs(block:
|
|
391
|
+
private getTxs(block: L2BlockNew): Tx[] {
|
|
385
392
|
return block.body.txEffects.map(txEffect => this.txs.get(txEffect.txHash.toString())!);
|
|
386
393
|
}
|
|
387
394
|
|
|
388
|
-
private getL1ToL2Messages(
|
|
389
|
-
return this.data.l1ToL2Messages[
|
|
395
|
+
private getL1ToL2Messages(checkpoint: Checkpoint) {
|
|
396
|
+
return this.data.l1ToL2Messages[checkpoint.number];
|
|
390
397
|
}
|
|
391
398
|
|
|
392
399
|
private async processTxs(publicProcessor: PublicProcessor, txs: Tx[]): Promise<ProcessedTx[]> {
|
package/src/metrics.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RollupContract } from '@aztec/ethereum';
|
|
1
|
+
import type { RollupContract } from '@aztec/ethereum/contracts';
|
|
2
2
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import type { L1PublishProofStats, L1PublishStats } from '@aztec/stdlib/stats';
|
|
@@ -21,6 +21,7 @@ import { formatEther, formatUnits } from 'viem';
|
|
|
21
21
|
export class ProverNodeJobMetrics {
|
|
22
22
|
proverEpochExecutionDuration: Histogram;
|
|
23
23
|
provingJobDuration: Histogram;
|
|
24
|
+
provingJobCheckpoints: Gauge;
|
|
24
25
|
provingJobBlocks: Gauge;
|
|
25
26
|
provingJobTransactions: Gauge;
|
|
26
27
|
|
|
@@ -39,6 +40,10 @@ export class ProverNodeJobMetrics {
|
|
|
39
40
|
unit: 's',
|
|
40
41
|
valueType: ValueType.DOUBLE,
|
|
41
42
|
});
|
|
43
|
+
this.provingJobCheckpoints = this.meter.createGauge(Metrics.PROVER_NODE_JOB_CHECKPOINTS, {
|
|
44
|
+
description: 'Number of checkpoints in a proven epoch',
|
|
45
|
+
valueType: ValueType.INT,
|
|
46
|
+
});
|
|
42
47
|
this.provingJobBlocks = this.meter.createGauge(Metrics.PROVER_NODE_JOB_BLOCKS, {
|
|
43
48
|
description: 'Number of blocks in a proven epoch',
|
|
44
49
|
valueType: ValueType.INT,
|
|
@@ -49,9 +54,16 @@ export class ProverNodeJobMetrics {
|
|
|
49
54
|
});
|
|
50
55
|
}
|
|
51
56
|
|
|
52
|
-
public recordProvingJob(
|
|
57
|
+
public recordProvingJob(
|
|
58
|
+
executionTimeMs: number,
|
|
59
|
+
totalTimeMs: number,
|
|
60
|
+
numCheckpoints: number,
|
|
61
|
+
numBlocks: number,
|
|
62
|
+
numTxs: number,
|
|
63
|
+
) {
|
|
53
64
|
this.proverEpochExecutionDuration.record(Math.ceil(executionTimeMs));
|
|
54
65
|
this.provingJobDuration.record(totalTimeMs / 1000);
|
|
66
|
+
this.provingJobCheckpoints.record(Math.floor(numCheckpoints));
|
|
55
67
|
this.provingJobBlocks.record(Math.floor(numBlocks));
|
|
56
68
|
this.provingJobTransactions.record(Math.floor(numTxs));
|
|
57
69
|
}
|
|
@@ -97,7 +109,7 @@ export class ProverNodeRewardsMetrics {
|
|
|
97
109
|
// look at the prev epoch so that we get an accurate value, after proof submission window has closed
|
|
98
110
|
// For example, if proof submission window is 1 epoch, and we are in epoch 2, we should be looking at epoch 0.
|
|
99
111
|
// Similarly, if the proof submission window is 0, and we are in epoch 1, we should be looking at epoch 0.
|
|
100
|
-
const closedEpoch = epoch - BigInt(this.proofSubmissionEpochs) - 1n;
|
|
112
|
+
const closedEpoch = BigInt(epoch) - BigInt(this.proofSubmissionEpochs) - 1n;
|
|
101
113
|
const rewards = await this.rollup.getSpecificProverRewardsForEpoch(closedEpoch, this.coinbase);
|
|
102
114
|
|
|
103
115
|
const fmt = parseFloat(formatUnits(rewards, 18));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
3
4
|
import { sleep } from '@aztec/foundation/sleep';
|
|
@@ -12,7 +13,7 @@ import {
|
|
|
12
13
|
} from '@aztec/telemetry-client';
|
|
13
14
|
|
|
14
15
|
export interface EpochMonitorHandler {
|
|
15
|
-
handleEpochReadyToProve(epochNumber:
|
|
16
|
+
handleEpochReadyToProve(epochNumber: EpochNumber): Promise<boolean>;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -32,7 +33,7 @@ export class EpochMonitor implements Traceable {
|
|
|
32
33
|
public readonly tracer: Tracer;
|
|
33
34
|
|
|
34
35
|
private handler: EpochMonitorHandler | undefined;
|
|
35
|
-
private latestEpochNumber:
|
|
36
|
+
private latestEpochNumber: EpochNumber | undefined;
|
|
36
37
|
|
|
37
38
|
constructor(
|
|
38
39
|
private readonly l2BlockSource: L2BlockSource,
|
|
@@ -104,7 +105,7 @@ export class EpochMonitor implements Traceable {
|
|
|
104
105
|
|
|
105
106
|
private async getEpochNumberToProve() {
|
|
106
107
|
const lastBlockProven = await this.l2BlockSource.getProvenBlockNumber();
|
|
107
|
-
const firstBlockToProve = lastBlockProven + 1;
|
|
108
|
+
const firstBlockToProve = BlockNumber(lastBlockProven + 1);
|
|
108
109
|
const firstBlockHeaderToProve = await this.l2BlockSource.getBlockHeader(firstBlockToProve);
|
|
109
110
|
if (!firstBlockHeaderToProve) {
|
|
110
111
|
return { epochToProve: undefined, blockNumber: firstBlockToProve };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { BatchedBlob, getEthBlobEvaluationInputs } from '@aztec/blob-lib';
|
|
2
2
|
import { AZTEC_MAX_EPOCH_DURATION } from '@aztec/constants';
|
|
3
|
-
import type {
|
|
3
|
+
import type { RollupContract, ViemCommitteeAttestation } from '@aztec/ethereum/contracts';
|
|
4
|
+
import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
|
|
4
5
|
import { makeTuple } from '@aztec/foundation/array';
|
|
6
|
+
import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
5
7
|
import { areArraysEqual } from '@aztec/foundation/collection';
|
|
8
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
9
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
8
10
|
import { createLogger } from '@aztec/foundation/log';
|
|
9
11
|
import type { Tuple } from '@aztec/foundation/serialize';
|
|
10
12
|
import { Timer } from '@aztec/foundation/timer';
|
|
@@ -85,16 +87,16 @@ export class ProverNodePublisher {
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
public async submitEpochProof(args: {
|
|
88
|
-
epochNumber:
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
epochNumber: EpochNumber;
|
|
91
|
+
fromCheckpoint: CheckpointNumber;
|
|
92
|
+
toCheckpoint: CheckpointNumber;
|
|
91
93
|
publicInputs: RootRollupPublicInputs;
|
|
92
94
|
proof: Proof;
|
|
93
95
|
batchedBlobInputs: BatchedBlob;
|
|
94
96
|
attestations: ViemCommitteeAttestation[];
|
|
95
97
|
}): Promise<boolean> {
|
|
96
|
-
const { epochNumber,
|
|
97
|
-
const ctx = { epochNumber,
|
|
98
|
+
const { epochNumber, fromCheckpoint, toCheckpoint } = args;
|
|
99
|
+
const ctx = { epochNumber, fromCheckpoint, toCheckpoint };
|
|
98
100
|
|
|
99
101
|
if (!this.interrupted) {
|
|
100
102
|
const timer = new Timer();
|
|
@@ -103,6 +105,7 @@ export class ProverNodePublisher {
|
|
|
103
105
|
|
|
104
106
|
const txReceipt = await this.sendSubmitEpochProofTx(args);
|
|
105
107
|
if (!txReceipt) {
|
|
108
|
+
this.log.error(`Failed to mine submitEpochProof tx`, undefined, ctx);
|
|
106
109
|
return false;
|
|
107
110
|
}
|
|
108
111
|
|
|
@@ -135,47 +138,51 @@ export class ProverNodePublisher {
|
|
|
135
138
|
}
|
|
136
139
|
|
|
137
140
|
this.metrics.recordFailedTx();
|
|
138
|
-
this.log.error(`Rollup
|
|
141
|
+
this.log.error(`Rollup submitEpochProof tx reverted ${txReceipt.transactionHash}`, undefined, ctx);
|
|
139
142
|
}
|
|
140
143
|
|
|
141
|
-
this.log.verbose('
|
|
144
|
+
this.log.verbose('Checkpoint data syncing interrupted', ctx);
|
|
142
145
|
return false;
|
|
143
146
|
}
|
|
144
147
|
|
|
145
148
|
private async validateEpochProofSubmission(args: {
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
fromCheckpoint: CheckpointNumber;
|
|
150
|
+
toCheckpoint: CheckpointNumber;
|
|
148
151
|
publicInputs: RootRollupPublicInputs;
|
|
149
152
|
proof: Proof;
|
|
150
153
|
batchedBlobInputs: BatchedBlob;
|
|
151
154
|
attestations: ViemCommitteeAttestation[];
|
|
152
155
|
}) {
|
|
153
|
-
const {
|
|
156
|
+
const { fromCheckpoint, toCheckpoint, publicInputs, batchedBlobInputs } = args;
|
|
154
157
|
|
|
155
|
-
// Check that the
|
|
156
|
-
const {
|
|
157
|
-
// Don't publish if proven is beyond our
|
|
158
|
-
if (proven >
|
|
159
|
-
throw new Error(
|
|
158
|
+
// Check that the checkpoint numbers match the expected epoch to be proven
|
|
159
|
+
const { pending, proven } = await this.rollupContract.getTips();
|
|
160
|
+
// Don't publish if proven is beyond our toCheckpoint, pointless to do so
|
|
161
|
+
if (proven > toCheckpoint) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Cannot submit epoch proof for ${fromCheckpoint}-${toCheckpoint} as proven checkpoint is ${proven}`,
|
|
164
|
+
);
|
|
160
165
|
}
|
|
161
|
-
//
|
|
162
|
-
if (
|
|
163
|
-
throw new Error(
|
|
166
|
+
// toCheckpoint can't be greater than pending
|
|
167
|
+
if (toCheckpoint > pending) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Cannot submit epoch proof for ${fromCheckpoint}-${toCheckpoint} as pending checkpoint is ${pending}`,
|
|
170
|
+
);
|
|
164
171
|
}
|
|
165
172
|
|
|
166
|
-
// Check the archive for the immediate
|
|
167
|
-
const
|
|
168
|
-
if (publicInputs.previousArchiveRoot.toString() !==
|
|
173
|
+
// Check the archive for the immediate checkpoint before the epoch
|
|
174
|
+
const checkpointLog = await this.rollupContract.getCheckpoint(CheckpointNumber(fromCheckpoint - 1));
|
|
175
|
+
if (publicInputs.previousArchiveRoot.toString() !== checkpointLog.archive) {
|
|
169
176
|
throw new Error(
|
|
170
|
-
`Previous archive root mismatch: ${publicInputs.previousArchiveRoot.toString()} !== ${
|
|
177
|
+
`Previous archive root mismatch: ${publicInputs.previousArchiveRoot.toString()} !== ${checkpointLog.archive}`,
|
|
171
178
|
);
|
|
172
179
|
}
|
|
173
180
|
|
|
174
|
-
// Check the archive for the last
|
|
175
|
-
const
|
|
176
|
-
if (publicInputs.endArchiveRoot.toString() !==
|
|
181
|
+
// Check the archive for the last checkpoint in the epoch
|
|
182
|
+
const endCheckpointLog = await this.rollupContract.getCheckpoint(toCheckpoint);
|
|
183
|
+
if (publicInputs.endArchiveRoot.toString() !== endCheckpointLog.archive) {
|
|
177
184
|
throw new Error(
|
|
178
|
-
`End archive root mismatch: ${publicInputs.endArchiveRoot.toString()} !== ${
|
|
185
|
+
`End archive root mismatch: ${publicInputs.endArchiveRoot.toString()} !== ${endCheckpointLog.archive}`,
|
|
179
186
|
);
|
|
180
187
|
}
|
|
181
188
|
|
|
@@ -202,8 +209,8 @@ export class ProverNodePublisher {
|
|
|
202
209
|
}
|
|
203
210
|
|
|
204
211
|
private async sendSubmitEpochProofTx(args: {
|
|
205
|
-
|
|
206
|
-
|
|
212
|
+
fromCheckpoint: CheckpointNumber;
|
|
213
|
+
toCheckpoint: CheckpointNumber;
|
|
207
214
|
publicInputs: RootRollupPublicInputs;
|
|
208
215
|
proof: Proof;
|
|
209
216
|
batchedBlobInputs: BatchedBlob;
|
|
@@ -213,8 +220,8 @@ export class ProverNodePublisher {
|
|
|
213
220
|
|
|
214
221
|
this.log.info(`Submitting epoch proof to L1 rollup contract`, {
|
|
215
222
|
proofSize: args.proof.withoutPublicInputs().length,
|
|
216
|
-
|
|
217
|
-
|
|
223
|
+
fromCheckpoint: args.fromCheckpoint,
|
|
224
|
+
toCheckpoint: args.toCheckpoint,
|
|
218
225
|
});
|
|
219
226
|
const data = encodeFunctionData({
|
|
220
227
|
abi: RollupAbi,
|
|
@@ -223,36 +230,39 @@ export class ProverNodePublisher {
|
|
|
223
230
|
});
|
|
224
231
|
try {
|
|
225
232
|
const { receipt } = await this.l1TxUtils.sendAndMonitorTransaction({ to: this.rollupContract.address, data });
|
|
233
|
+
if (receipt.status !== 'success') {
|
|
234
|
+
const errorMsg = await this.l1TxUtils.tryGetErrorFromRevertedTx(
|
|
235
|
+
data,
|
|
236
|
+
{
|
|
237
|
+
args: [...txArgs],
|
|
238
|
+
functionName: 'submitEpochRootProof',
|
|
239
|
+
abi: RollupAbi,
|
|
240
|
+
address: this.rollupContract.address,
|
|
241
|
+
},
|
|
242
|
+
/*blobInputs*/ undefined,
|
|
243
|
+
/*stateOverride*/ [],
|
|
244
|
+
);
|
|
245
|
+
this.log.error(`Rollup submit epoch proof tx reverted with ${errorMsg ?? 'unknown error'}`);
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
226
248
|
return receipt;
|
|
227
249
|
} catch (err) {
|
|
228
250
|
this.log.error(`Rollup submit epoch proof failed`, err);
|
|
229
|
-
const errorMsg = await this.l1TxUtils.tryGetErrorFromRevertedTx(
|
|
230
|
-
data,
|
|
231
|
-
{
|
|
232
|
-
args: [...txArgs],
|
|
233
|
-
functionName: 'submitEpochRootProof',
|
|
234
|
-
abi: RollupAbi,
|
|
235
|
-
address: this.rollupContract.address,
|
|
236
|
-
},
|
|
237
|
-
/*blobInputs*/ undefined,
|
|
238
|
-
/*stateOverride*/ [],
|
|
239
|
-
);
|
|
240
|
-
this.log.error(`Rollup submit epoch proof tx reverted. ${errorMsg}`);
|
|
241
251
|
return undefined;
|
|
242
252
|
}
|
|
243
253
|
}
|
|
244
254
|
|
|
245
255
|
private getEpochProofPublicInputsArgs(args: {
|
|
246
|
-
|
|
247
|
-
|
|
256
|
+
fromCheckpoint: CheckpointNumber;
|
|
257
|
+
toCheckpoint: CheckpointNumber;
|
|
248
258
|
publicInputs: RootRollupPublicInputs;
|
|
249
259
|
batchedBlobInputs: BatchedBlob;
|
|
250
260
|
attestations: ViemCommitteeAttestation[];
|
|
251
261
|
}) {
|
|
252
262
|
// Returns arguments for EpochProofLib.sol -> getEpochProofPublicInputs()
|
|
253
263
|
return [
|
|
254
|
-
BigInt(args.
|
|
255
|
-
BigInt(args.
|
|
264
|
+
BigInt(args.fromCheckpoint) /*_start*/,
|
|
265
|
+
BigInt(args.toCheckpoint) /*_end*/,
|
|
256
266
|
{
|
|
257
267
|
previousArchive: args.publicInputs.previousArchiveRoot.toString(),
|
|
258
268
|
endArchive: args.publicInputs.endArchiveRoot.toString(),
|
|
@@ -263,13 +273,13 @@ export class ProverNodePublisher {
|
|
|
263
273
|
? args.publicInputs.fees[i / 2].recipient.toField().toString()
|
|
264
274
|
: args.publicInputs.fees[(i - 1) / 2].value.toString(),
|
|
265
275
|
) /*_fees*/,
|
|
266
|
-
args.batchedBlobInputs
|
|
276
|
+
getEthBlobEvaluationInputs(args.batchedBlobInputs) /*_blobPublicInputs*/,
|
|
267
277
|
] as const;
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
private getSubmitEpochProofArgs(args: {
|
|
271
|
-
|
|
272
|
-
|
|
281
|
+
fromCheckpoint: CheckpointNumber;
|
|
282
|
+
toCheckpoint: CheckpointNumber;
|
|
273
283
|
publicInputs: RootRollupPublicInputs;
|
|
274
284
|
proof: Proof;
|
|
275
285
|
batchedBlobInputs: BatchedBlob;
|