@aztec/prover-node 0.0.1-commit.03f7ef2 → 0.0.1-commit.04d373f
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 +1 -1
- package/dest/actions/download-epoch-proving-job.js +1 -1
- package/dest/actions/rerun-epoch-proving-job.d.ts +5 -3
- package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
- package/dest/actions/rerun-epoch-proving-job.js +9 -7
- package/dest/actions/upload-epoch-proof-failure.d.ts +2 -2
- package/dest/actions/upload-epoch-proof-failure.d.ts.map +1 -1
- package/dest/bin/run-failed-epoch.js +6 -5
- package/dest/config.d.ts +5 -8
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +16 -19
- package/dest/factory.d.ts +19 -15
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +45 -64
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/job/epoch-proving-job.d.ts +7 -2
- package/dest/job/epoch-proving-job.d.ts.map +1 -1
- package/dest/job/epoch-proving-job.js +600 -52
- package/dest/metrics.d.ts +21 -1
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +73 -100
- package/dest/monitors/epoch-monitor.d.ts +1 -1
- package/dest/monitors/epoch-monitor.d.ts.map +1 -1
- package/dest/monitors/epoch-monitor.js +12 -19
- package/dest/prover-node-publisher.d.ts +25 -5
- package/dest/prover-node-publisher.d.ts.map +1 -1
- package/dest/prover-node-publisher.js +210 -14
- package/dest/prover-node.d.ts +20 -11
- package/dest/prover-node.d.ts.map +1 -1
- package/dest/prover-node.js +429 -46
- package/dest/prover-publisher-factory.d.ts +7 -5
- package/dest/prover-publisher-factory.d.ts.map +1 -1
- package/dest/prover-publisher-factory.js +7 -5
- package/package.json +24 -23
- package/src/actions/download-epoch-proving-job.ts +1 -1
- package/src/actions/rerun-epoch-proving-job.ts +20 -7
- package/src/actions/upload-epoch-proof-failure.ts +1 -1
- package/src/bin/run-failed-epoch.ts +5 -3
- package/src/config.ts +23 -31
- package/src/factory.ts +77 -104
- package/src/index.ts +1 -0
- package/src/job/epoch-proving-job.ts +151 -47
- package/src/metrics.ts +91 -83
- package/src/monitors/epoch-monitor.ts +6 -14
- package/src/prover-node-publisher.ts +245 -19
- package/src/prover-node.ts +31 -31
- package/src/prover-publisher-factory.ts +16 -10
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
1
|
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
3
2
|
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
4
|
-
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
5
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
7
5
|
import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
8
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
7
|
+
import { AVM_MAX_CONCURRENT_SIMULATIONS } from '@aztec/native';
|
|
9
8
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
9
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
10
|
import { buildFinalBlobChallenges } from '@aztec/prover-client/helpers';
|
|
12
11
|
import type { PublicProcessor, PublicProcessorFactory } from '@aztec/simulator/server';
|
|
13
12
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
14
|
-
import type {
|
|
13
|
+
import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
15
14
|
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
16
15
|
import {
|
|
17
16
|
type EpochProver,
|
|
@@ -19,8 +18,8 @@ import {
|
|
|
19
18
|
EpochProvingJobTerminalState,
|
|
20
19
|
type ForkMerkleTreeOperations,
|
|
21
20
|
} from '@aztec/stdlib/interfaces/server';
|
|
21
|
+
import { appendL1ToL2MessagesToTree } from '@aztec/stdlib/messaging';
|
|
22
22
|
import { CheckpointConstantData } from '@aztec/stdlib/rollup';
|
|
23
|
-
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
24
23
|
import type { ProcessedTx, Tx } from '@aztec/stdlib/tx';
|
|
25
24
|
import { Attributes, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
26
25
|
|
|
@@ -43,10 +42,11 @@ export type EpochProvingJobOptions = {
|
|
|
43
42
|
*/
|
|
44
43
|
export class EpochProvingJob implements Traceable {
|
|
45
44
|
private state: EpochProvingJobState = 'initialized';
|
|
46
|
-
private log
|
|
45
|
+
private log: Logger;
|
|
47
46
|
private uuid: string;
|
|
48
47
|
|
|
49
48
|
private runPromise: Promise<void> | undefined;
|
|
49
|
+
private abortController = new AbortController();
|
|
50
50
|
private epochCheckPromise: RunningPromise | undefined;
|
|
51
51
|
private deadlineTimeoutHandler: NodeJS.Timeout | undefined;
|
|
52
52
|
|
|
@@ -57,14 +57,19 @@ export class EpochProvingJob implements Traceable {
|
|
|
57
57
|
private dbProvider: Pick<ForkMerkleTreeOperations, 'fork'>,
|
|
58
58
|
private prover: EpochProver,
|
|
59
59
|
private publicProcessorFactory: PublicProcessorFactory,
|
|
60
|
-
private publisher: Pick<ProverNodePublisher, 'submitEpochProof'>,
|
|
60
|
+
private publisher: Pick<ProverNodePublisher, 'submitEpochProof' | 'analyzeEpochProofSubmission'>,
|
|
61
61
|
private l2BlockSource: L2BlockSource | undefined,
|
|
62
62
|
private metrics: ProverNodeJobMetrics,
|
|
63
63
|
private deadline: Date | undefined,
|
|
64
64
|
private config: EpochProvingJobOptions,
|
|
65
|
+
bindings?: LoggerBindings,
|
|
65
66
|
) {
|
|
66
67
|
validateEpochProvingJobData(data);
|
|
67
68
|
this.uuid = crypto.randomUUID();
|
|
69
|
+
this.log = createLogger('prover-node:epoch-proving-job', {
|
|
70
|
+
...bindings,
|
|
71
|
+
instanceId: `epoch-${data.epochNumber}`,
|
|
72
|
+
});
|
|
68
73
|
this.tracer = metrics.tracer;
|
|
69
74
|
}
|
|
70
75
|
|
|
@@ -143,19 +148,32 @@ export class EpochProvingJob implements Traceable {
|
|
|
143
148
|
this.runPromise = promise;
|
|
144
149
|
|
|
145
150
|
try {
|
|
151
|
+
const blobTimer = new Timer();
|
|
146
152
|
const blobFieldsPerCheckpoint = this.checkpoints.map(checkpoint => checkpoint.toBlobFields());
|
|
147
153
|
const finalBlobBatchingChallenges = await buildFinalBlobChallenges(blobFieldsPerCheckpoint);
|
|
154
|
+
this.metrics.recordBlobProcessing(blobTimer.ms());
|
|
148
155
|
|
|
149
156
|
this.prover.startNewEpoch(epochNumber, epochSizeCheckpoints, finalBlobBatchingChallenges);
|
|
157
|
+
const chonkTimer = new Timer();
|
|
150
158
|
await this.prover.startChonkVerifierCircuits(Array.from(this.txs.values()));
|
|
159
|
+
this.metrics.recordChonkVerifier(chonkTimer.ms());
|
|
151
160
|
|
|
152
161
|
// Everything in the epoch should have the same chainId and version.
|
|
153
162
|
const { chainId, version } = this.checkpoints[0].blocks[0].header.globalVariables;
|
|
154
163
|
|
|
155
164
|
const previousBlockHeaders = this.gatherPreviousBlockHeaders();
|
|
156
165
|
|
|
157
|
-
|
|
166
|
+
const allCheckpointsTimer = new Timer();
|
|
167
|
+
|
|
168
|
+
const parallelism = this.config.parallelBlockLimit
|
|
169
|
+
? this.config.parallelBlockLimit
|
|
170
|
+
: AVM_MAX_CONCURRENT_SIMULATIONS > 0
|
|
171
|
+
? AVM_MAX_CONCURRENT_SIMULATIONS
|
|
172
|
+
: this.checkpoints.length;
|
|
173
|
+
|
|
174
|
+
await this.processCheckpoints(parallelism, async checkpoint => {
|
|
158
175
|
this.checkState();
|
|
176
|
+
const checkpointTimer = new Timer();
|
|
159
177
|
|
|
160
178
|
const checkpointIndex = checkpoint.number - fromCheckpoint;
|
|
161
179
|
const checkpointConstants = CheckpointConstantData.from({
|
|
@@ -172,11 +190,12 @@ export class EpochProvingJob implements Traceable {
|
|
|
172
190
|
const previousHeader = previousBlockHeaders[checkpointIndex];
|
|
173
191
|
const l1ToL2Messages = this.getL1ToL2Messages(checkpoint);
|
|
174
192
|
|
|
175
|
-
this.log.
|
|
193
|
+
this.log.debug(`Starting processing checkpoint ${checkpoint.number}`, {
|
|
176
194
|
number: checkpoint.number,
|
|
177
195
|
checkpointHash: checkpoint.hash().toString(),
|
|
178
|
-
|
|
179
|
-
|
|
196
|
+
headerHash: checkpoint.header.hash().toString(),
|
|
197
|
+
numL1ToL2Messages: l1ToL2Messages.length,
|
|
198
|
+
previousBlockNumber: previousHeader.globalVariables.blockNumber,
|
|
180
199
|
uuid: this.uuid,
|
|
181
200
|
});
|
|
182
201
|
|
|
@@ -188,7 +207,9 @@ export class EpochProvingJob implements Traceable {
|
|
|
188
207
|
previousHeader,
|
|
189
208
|
);
|
|
190
209
|
|
|
191
|
-
for (
|
|
210
|
+
for (let blockIndex = 0; blockIndex < checkpoint.blocks.length; blockIndex++) {
|
|
211
|
+
const blockTimer = new Timer();
|
|
212
|
+
const block = checkpoint.blocks[blockIndex];
|
|
192
213
|
const globalVariables = block.header.globalVariables;
|
|
193
214
|
const txs = this.getTxs(block);
|
|
194
215
|
|
|
@@ -206,20 +227,28 @@ export class EpochProvingJob implements Traceable {
|
|
|
206
227
|
// Start block proving
|
|
207
228
|
await this.prover.startNewBlock(block.number, globalVariables.timestamp, txs.length);
|
|
208
229
|
|
|
209
|
-
// Process public fns
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
230
|
+
// Process public fns. L1 to L2 messages are only inserted for the first block of a checkpoint,
|
|
231
|
+
// as the fork for subsequent blocks already includes them from the previous block's synced state.
|
|
232
|
+
{
|
|
233
|
+
await using db = await this.createFork(
|
|
234
|
+
BlockNumber(block.number - 1),
|
|
235
|
+
blockIndex === 0 ? l1ToL2Messages : undefined,
|
|
236
|
+
);
|
|
237
|
+
this.checkState();
|
|
238
|
+
const config = PublicSimulatorConfig.from({
|
|
239
|
+
proverId: this.prover.getProverId().toField(),
|
|
240
|
+
skipFeeEnforcement: false,
|
|
241
|
+
collectDebugLogs: false,
|
|
242
|
+
collectHints: true,
|
|
243
|
+
collectPublicInputs: true,
|
|
244
|
+
collectStatistics: false,
|
|
245
|
+
});
|
|
246
|
+
const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, config);
|
|
247
|
+
const processed = await this.processTxs(publicProcessor, txs);
|
|
248
|
+
this.checkState();
|
|
249
|
+
await this.prover.addTxs(processed);
|
|
250
|
+
}
|
|
251
|
+
this.checkState();
|
|
223
252
|
this.log.verbose(`Processed all ${txs.length} txs for block ${block.number}`, {
|
|
224
253
|
blockNumber: block.number,
|
|
225
254
|
blockHash: (await block.hash()).toString(),
|
|
@@ -229,8 +258,11 @@ export class EpochProvingJob implements Traceable {
|
|
|
229
258
|
// Mark block as completed to pad it
|
|
230
259
|
const expectedBlockHeader = block.header;
|
|
231
260
|
await this.prover.setBlockCompleted(block.number, expectedBlockHeader);
|
|
261
|
+
this.metrics.recordBlockProcessing(blockTimer.ms());
|
|
232
262
|
}
|
|
263
|
+
this.metrics.recordCheckpointProcessing(checkpointTimer.ms());
|
|
233
264
|
});
|
|
265
|
+
this.metrics.recordAllCheckpointsProcessing(allCheckpointsTimer.ms());
|
|
234
266
|
|
|
235
267
|
const executionTime = timer.ms();
|
|
236
268
|
|
|
@@ -242,8 +274,21 @@ export class EpochProvingJob implements Traceable {
|
|
|
242
274
|
|
|
243
275
|
if (this.config.skipSubmitProof) {
|
|
244
276
|
this.log.info(
|
|
245
|
-
`Proof publishing is disabled.
|
|
277
|
+
`Proof publishing is disabled. Analyzing estimated L1 fees for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`,
|
|
246
278
|
);
|
|
279
|
+
try {
|
|
280
|
+
await this.publisher.analyzeEpochProofSubmission({
|
|
281
|
+
fromCheckpoint,
|
|
282
|
+
toCheckpoint,
|
|
283
|
+
epochNumber,
|
|
284
|
+
publicInputs,
|
|
285
|
+
proof,
|
|
286
|
+
batchedBlobInputs,
|
|
287
|
+
attestations,
|
|
288
|
+
});
|
|
289
|
+
} catch (err) {
|
|
290
|
+
this.log.warn(`Failed to analyze estimated L1 fees for epoch ${epochNumber}`, err);
|
|
291
|
+
}
|
|
247
292
|
this.state = 'completed';
|
|
248
293
|
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeCheckpoints, epochSizeBlocks, epochSizeTxs);
|
|
249
294
|
return;
|
|
@@ -290,25 +335,63 @@ export class EpochProvingJob implements Traceable {
|
|
|
290
335
|
}
|
|
291
336
|
|
|
292
337
|
/**
|
|
293
|
-
* Create a new db fork for tx processing, inserting
|
|
338
|
+
* Create a new db fork for tx processing, optionally inserting L1 to L2 messages.
|
|
339
|
+
* L1 to L2 messages should only be inserted for the first block in a checkpoint,
|
|
340
|
+
* as subsequent blocks' synced state already includes them.
|
|
294
341
|
* 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.
|
|
295
342
|
*/
|
|
296
|
-
private async createFork(blockNumber: BlockNumber, l1ToL2Messages: Fr[]) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
343
|
+
private async createFork(blockNumber: BlockNumber, l1ToL2Messages: Fr[] | undefined) {
|
|
344
|
+
this.log.verbose(`Creating fork at ${blockNumber}`, { blockNumber });
|
|
345
|
+
// temporary stack to control fork lifetime
|
|
346
|
+
await using cleanup = new AsyncDisposableStack();
|
|
347
|
+
const db = cleanup.use(await this.dbProvider.fork(blockNumber));
|
|
348
|
+
|
|
349
|
+
if (l1ToL2Messages !== undefined) {
|
|
350
|
+
this.log.verbose(`Inserting ${l1ToL2Messages.length} L1 to L2 messages in fork`, {
|
|
351
|
+
blockNumber,
|
|
352
|
+
l1ToL2Messages: l1ToL2Messages.map(m => m.toString()),
|
|
353
|
+
});
|
|
354
|
+
await appendL1ToL2MessagesToTree(db, l1ToL2Messages);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// everything run succesfully so we can release this stack and give control of the fork's lifetime to the caller
|
|
358
|
+
cleanup.move();
|
|
309
359
|
return db;
|
|
310
360
|
}
|
|
311
361
|
|
|
362
|
+
private async processCheckpoints(
|
|
363
|
+
parallelism: number,
|
|
364
|
+
processCheckpoint: (checkpoint: Checkpoint) => Promise<void>,
|
|
365
|
+
): Promise<void> {
|
|
366
|
+
let hasError = false;
|
|
367
|
+
let firstError: unknown;
|
|
368
|
+
|
|
369
|
+
await asyncPool(Math.max(parallelism, 1), this.checkpoints, async checkpoint => {
|
|
370
|
+
if (hasError || this.abortController.signal.aborted) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
this.checkState();
|
|
376
|
+
await processCheckpoint(checkpoint);
|
|
377
|
+
} catch (err) {
|
|
378
|
+
if (!hasError) {
|
|
379
|
+
hasError = true;
|
|
380
|
+
firstError = err;
|
|
381
|
+
this.failProcessing();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
if (hasError) {
|
|
387
|
+
throw firstError;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (this.abortController.signal.aborted) {
|
|
391
|
+
this.checkState();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
312
395
|
private progressState(state: EpochProvingJobState) {
|
|
313
396
|
this.checkState();
|
|
314
397
|
this.state = state;
|
|
@@ -322,12 +405,24 @@ export class EpochProvingJob implements Traceable {
|
|
|
322
405
|
|
|
323
406
|
public async stop(state: EpochProvingJobTerminalState = 'stopped') {
|
|
324
407
|
this.state = state;
|
|
325
|
-
this.
|
|
408
|
+
this.interruptProcessing();
|
|
326
409
|
if (this.runPromise) {
|
|
327
410
|
await this.runPromise;
|
|
328
411
|
}
|
|
329
412
|
}
|
|
330
413
|
|
|
414
|
+
private failProcessing() {
|
|
415
|
+
if (!EpochProvingJobTerminalState.includes(this.state)) {
|
|
416
|
+
this.state = 'failed';
|
|
417
|
+
}
|
|
418
|
+
this.interruptProcessing();
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private interruptProcessing() {
|
|
422
|
+
this.abortController.abort();
|
|
423
|
+
this.prover.cancel();
|
|
424
|
+
}
|
|
425
|
+
|
|
331
426
|
private scheduleDeadlineStop() {
|
|
332
427
|
const deadline = this.deadline;
|
|
333
428
|
if (deadline) {
|
|
@@ -362,11 +457,16 @@ export class EpochProvingJob implements Traceable {
|
|
|
362
457
|
const intervalMs = Math.ceil((await l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
|
|
363
458
|
this.epochCheckPromise = new RunningPromise(
|
|
364
459
|
async () => {
|
|
365
|
-
const
|
|
366
|
-
|
|
460
|
+
const blockHeaders = (
|
|
461
|
+
await l2BlockSource.getBlocksData({ epoch: this.epochNumber, onlyCheckpointed: true })
|
|
462
|
+
).map(d => d.header);
|
|
463
|
+
const blockHashes = await Promise.all(blockHeaders.map(header => header.hash()));
|
|
367
464
|
const thisBlocks = this.checkpoints.flatMap(checkpoint => checkpoint.blocks);
|
|
368
465
|
const thisBlockHashes = await Promise.all(thisBlocks.map(block => block.hash()));
|
|
369
|
-
if (
|
|
466
|
+
if (
|
|
467
|
+
blockHeaders.length !== thisBlocks.length ||
|
|
468
|
+
!blockHashes.every((block, i) => block.equals(thisBlockHashes[i]))
|
|
469
|
+
) {
|
|
370
470
|
this.log.warn('Epoch blocks changed underfoot', {
|
|
371
471
|
uuid: this.uuid,
|
|
372
472
|
epochNumber: this.epochNumber,
|
|
@@ -388,7 +488,7 @@ export class EpochProvingJob implements Traceable {
|
|
|
388
488
|
return [this.data.previousBlockHeader, ...lastBlocks.map(block => block.header).slice(0, -1)];
|
|
389
489
|
}
|
|
390
490
|
|
|
391
|
-
private getTxs(block:
|
|
491
|
+
private getTxs(block: L2Block): Tx[] {
|
|
392
492
|
return block.body.txEffects.map(txEffect => this.txs.get(txEffect.txHash.toString())!);
|
|
393
493
|
}
|
|
394
494
|
|
|
@@ -398,7 +498,11 @@ export class EpochProvingJob implements Traceable {
|
|
|
398
498
|
|
|
399
499
|
private async processTxs(publicProcessor: PublicProcessor, txs: Tx[]): Promise<ProcessedTx[]> {
|
|
400
500
|
const { deadline } = this;
|
|
401
|
-
const [processedTxs, failedTxs] = await publicProcessor.process(txs, {
|
|
501
|
+
const [processedTxs, failedTxs] = await publicProcessor.process(txs, {
|
|
502
|
+
deadline,
|
|
503
|
+
signal: this.abortController.signal,
|
|
504
|
+
});
|
|
505
|
+
this.checkState();
|
|
402
506
|
|
|
403
507
|
if (failedTxs.length) {
|
|
404
508
|
const failedTxHashes = await Promise.all(failedTxs.map(({ tx }) => tx.getTxHash()));
|
package/src/metrics.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
type TelemetryClient,
|
|
14
14
|
type Tracer,
|
|
15
15
|
type UpDownCounter,
|
|
16
|
-
|
|
16
|
+
createUpDownCounterWithDefault,
|
|
17
17
|
} from '@aztec/telemetry-client';
|
|
18
18
|
|
|
19
19
|
import { formatEther, formatUnits } from 'viem';
|
|
@@ -25,33 +25,30 @@ export class ProverNodeJobMetrics {
|
|
|
25
25
|
provingJobBlocks: Gauge;
|
|
26
26
|
provingJobTransactions: Gauge;
|
|
27
27
|
|
|
28
|
+
private blobProcessingDuration: Gauge;
|
|
29
|
+
private chonkVerifierDuration: Gauge;
|
|
30
|
+
private blockProcessingDuration: Histogram;
|
|
31
|
+
private checkpointProcessingDuration: Histogram;
|
|
32
|
+
private allCheckpointsProcessingDuration: Gauge;
|
|
33
|
+
|
|
28
34
|
constructor(
|
|
29
35
|
private meter: Meter,
|
|
30
36
|
public readonly tracer: Tracer,
|
|
31
37
|
private logger = createLogger('prover-node:publisher:metrics'),
|
|
32
38
|
) {
|
|
33
|
-
this.proverEpochExecutionDuration = this.meter.createHistogram(Metrics.PROVER_NODE_EXECUTION_DURATION
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
});
|
|
47
|
-
this.provingJobBlocks = this.meter.createGauge(Metrics.PROVER_NODE_JOB_BLOCKS, {
|
|
48
|
-
description: 'Number of blocks in a proven epoch',
|
|
49
|
-
valueType: ValueType.INT,
|
|
50
|
-
});
|
|
51
|
-
this.provingJobTransactions = this.meter.createGauge(Metrics.PROVER_NODE_JOB_TRANSACTIONS, {
|
|
52
|
-
description: 'Number of transactions in a proven epoch',
|
|
53
|
-
valueType: ValueType.INT,
|
|
54
|
-
});
|
|
39
|
+
this.proverEpochExecutionDuration = this.meter.createHistogram(Metrics.PROVER_NODE_EXECUTION_DURATION);
|
|
40
|
+
this.provingJobDuration = this.meter.createHistogram(Metrics.PROVER_NODE_JOB_DURATION);
|
|
41
|
+
this.provingJobCheckpoints = this.meter.createGauge(Metrics.PROVER_NODE_JOB_CHECKPOINTS);
|
|
42
|
+
this.provingJobBlocks = this.meter.createGauge(Metrics.PROVER_NODE_JOB_BLOCKS);
|
|
43
|
+
this.provingJobTransactions = this.meter.createGauge(Metrics.PROVER_NODE_JOB_TRANSACTIONS);
|
|
44
|
+
|
|
45
|
+
this.blobProcessingDuration = this.meter.createGauge(Metrics.PROVER_NODE_BLOB_PROCESSING_LAST_DURATION);
|
|
46
|
+
this.chonkVerifierDuration = this.meter.createGauge(Metrics.PROVER_NODE_CHONK_VERIFIER_LAST_DURATION);
|
|
47
|
+
this.blockProcessingDuration = this.meter.createHistogram(Metrics.PROVER_NODE_BLOCK_PROCESSING_DURATION);
|
|
48
|
+
this.checkpointProcessingDuration = this.meter.createHistogram(Metrics.PROVER_NODE_CHECKPOINT_PROCESSING_DURATION);
|
|
49
|
+
this.allCheckpointsProcessingDuration = this.meter.createGauge(
|
|
50
|
+
Metrics.PROVER_NODE_ALL_CHECKPOINTS_PROCESSING_LAST_DURATION,
|
|
51
|
+
);
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
public recordProvingJob(
|
|
@@ -67,6 +64,26 @@ export class ProverNodeJobMetrics {
|
|
|
67
64
|
this.provingJobBlocks.record(Math.floor(numBlocks));
|
|
68
65
|
this.provingJobTransactions.record(Math.floor(numTxs));
|
|
69
66
|
}
|
|
67
|
+
|
|
68
|
+
public recordBlobProcessing(durationMs: number) {
|
|
69
|
+
this.blobProcessingDuration.record(Math.ceil(durationMs));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public recordChonkVerifier(durationMs: number) {
|
|
73
|
+
this.chonkVerifierDuration.record(Math.ceil(durationMs));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public recordBlockProcessing(durationMs: number) {
|
|
77
|
+
this.blockProcessingDuration.record(Math.ceil(durationMs));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public recordCheckpointProcessing(durationMs: number) {
|
|
81
|
+
this.checkpointProcessingDuration.record(Math.ceil(durationMs));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public recordAllCheckpointsProcessing(durationMs: number) {
|
|
85
|
+
this.allCheckpointsProcessingDuration.record(Math.ceil(durationMs));
|
|
86
|
+
}
|
|
70
87
|
}
|
|
71
88
|
|
|
72
89
|
export class ProverNodeRewardsMetrics {
|
|
@@ -81,15 +98,9 @@ export class ProverNodeRewardsMetrics {
|
|
|
81
98
|
private rollup: RollupContract,
|
|
82
99
|
private logger = createLogger('prover-node:publisher:metrics'),
|
|
83
100
|
) {
|
|
84
|
-
this.rewards = this.meter.createObservableGauge(Metrics.PROVER_NODE_REWARDS_PER_EPOCH
|
|
85
|
-
valueType: ValueType.DOUBLE,
|
|
86
|
-
description: 'The rewards earned',
|
|
87
|
-
});
|
|
101
|
+
this.rewards = this.meter.createObservableGauge(Metrics.PROVER_NODE_REWARDS_PER_EPOCH);
|
|
88
102
|
|
|
89
|
-
this.accumulatedRewards = this.meter
|
|
90
|
-
valueType: ValueType.DOUBLE,
|
|
91
|
-
description: 'The rewards earned (total)',
|
|
92
|
-
});
|
|
103
|
+
this.accumulatedRewards = createUpDownCounterWithDefault(this.meter, Metrics.PROVER_NODE_REWARDS_TOTAL);
|
|
93
104
|
}
|
|
94
105
|
|
|
95
106
|
public async start() {
|
|
@@ -129,6 +140,13 @@ export class ProverNodeRewardsMetrics {
|
|
|
129
140
|
};
|
|
130
141
|
}
|
|
131
142
|
|
|
143
|
+
export type EstimatedSubmitProofStats = {
|
|
144
|
+
gasLimit: bigint;
|
|
145
|
+
baseFeePerGas: bigint;
|
|
146
|
+
maxPriorityFeePerGas: bigint;
|
|
147
|
+
estimatedTotalFee: bigint;
|
|
148
|
+
};
|
|
149
|
+
|
|
132
150
|
export class ProverNodePublisherMetrics {
|
|
133
151
|
gasPrice: Histogram;
|
|
134
152
|
txCount: UpDownCounter;
|
|
@@ -140,6 +158,10 @@ export class ProverNodePublisherMetrics {
|
|
|
140
158
|
txBlobDataGasCost: Histogram;
|
|
141
159
|
txTotalFee: Histogram;
|
|
142
160
|
|
|
161
|
+
private txGasEstimated: Histogram;
|
|
162
|
+
private gasPriceEstimated: Histogram;
|
|
163
|
+
private txTotalFeeEstimated: Histogram;
|
|
164
|
+
|
|
143
165
|
private senderBalance: Gauge;
|
|
144
166
|
private meter: Meter;
|
|
145
167
|
|
|
@@ -150,68 +172,34 @@ export class ProverNodePublisherMetrics {
|
|
|
150
172
|
) {
|
|
151
173
|
this.meter = client.getMeter(name);
|
|
152
174
|
|
|
153
|
-
this.gasPrice = this.meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE
|
|
154
|
-
description: 'The gas price used for transactions',
|
|
155
|
-
unit: 'gwei',
|
|
156
|
-
valueType: ValueType.DOUBLE,
|
|
157
|
-
});
|
|
175
|
+
this.gasPrice = this.meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE);
|
|
158
176
|
|
|
159
|
-
this.txCount = this.meter
|
|
160
|
-
|
|
177
|
+
this.txCount = createUpDownCounterWithDefault(this.meter, Metrics.L1_PUBLISHER_TX_COUNT, {
|
|
178
|
+
[Attributes.L1_TX_TYPE]: ['submitProof'],
|
|
179
|
+
[Attributes.OK]: [true, false],
|
|
161
180
|
});
|
|
162
181
|
|
|
163
|
-
this.txDuration = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_DURATION
|
|
164
|
-
description: 'The duration of transaction processing',
|
|
165
|
-
unit: 'ms',
|
|
166
|
-
valueType: ValueType.INT,
|
|
167
|
-
});
|
|
182
|
+
this.txDuration = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_DURATION);
|
|
168
183
|
|
|
169
|
-
this.txGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_GAS
|
|
170
|
-
description: 'The gas consumed by transactions',
|
|
171
|
-
unit: 'gas',
|
|
172
|
-
valueType: ValueType.INT,
|
|
173
|
-
});
|
|
184
|
+
this.txGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_GAS);
|
|
174
185
|
|
|
175
|
-
this.txCalldataSize = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_SIZE
|
|
176
|
-
description: 'The size of the calldata in transactions',
|
|
177
|
-
unit: 'By',
|
|
178
|
-
valueType: ValueType.INT,
|
|
179
|
-
});
|
|
186
|
+
this.txCalldataSize = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_SIZE);
|
|
180
187
|
|
|
181
|
-
this.txCalldataGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_GAS
|
|
182
|
-
description: 'The gas consumed by the calldata in transactions',
|
|
183
|
-
unit: 'gas',
|
|
184
|
-
valueType: ValueType.INT,
|
|
185
|
-
});
|
|
188
|
+
this.txCalldataGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_GAS);
|
|
186
189
|
|
|
187
|
-
this.txBlobDataGasUsed = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_USED
|
|
188
|
-
description: 'The amount of blob gas used in transactions',
|
|
189
|
-
unit: 'gas',
|
|
190
|
-
valueType: ValueType.INT,
|
|
191
|
-
});
|
|
190
|
+
this.txBlobDataGasUsed = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_USED);
|
|
192
191
|
|
|
193
|
-
this.txBlobDataGasCost = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_COST
|
|
194
|
-
description: 'The gas cost of blobs in transactions',
|
|
195
|
-
unit: 'gwei',
|
|
196
|
-
valueType: ValueType.INT,
|
|
197
|
-
});
|
|
192
|
+
this.txBlobDataGasCost = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_COST);
|
|
198
193
|
|
|
199
|
-
this.txTotalFee = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_TOTAL_FEE
|
|
200
|
-
description: 'How much L1 tx costs',
|
|
201
|
-
unit: 'gwei',
|
|
202
|
-
valueType: ValueType.DOUBLE,
|
|
203
|
-
advice: {
|
|
204
|
-
explicitBucketBoundaries: [
|
|
205
|
-
0.001, 0.002, 0.004, 0.008, 0.01, 0.02, 0.04, 0.08, 0.1, 0.2, 0.4, 0.8, 1, 1.2, 1.4, 1.8, 2,
|
|
206
|
-
],
|
|
207
|
-
},
|
|
208
|
-
});
|
|
194
|
+
this.txTotalFee = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_TOTAL_FEE);
|
|
209
195
|
|
|
210
|
-
this.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
196
|
+
this.txGasEstimated = this.meter.createHistogram(Metrics.PROVER_NODE_ESTIMATED_SUBMISSION_GAS);
|
|
197
|
+
|
|
198
|
+
this.gasPriceEstimated = this.meter.createHistogram(Metrics.PROVER_NODE_ESTIMATED_SUBMISSION_GAS_PRICE);
|
|
199
|
+
|
|
200
|
+
this.txTotalFeeEstimated = this.meter.createHistogram(Metrics.PROVER_NODE_ESTIMATED_SUBMISSION_TOTAL_FEE);
|
|
201
|
+
|
|
202
|
+
this.senderBalance = this.meter.createGauge(Metrics.L1_PUBLISHER_BALANCE);
|
|
215
203
|
}
|
|
216
204
|
|
|
217
205
|
recordFailedTx() {
|
|
@@ -225,6 +213,26 @@ export class ProverNodePublisherMetrics {
|
|
|
225
213
|
this.recordTx(durationMs, stats);
|
|
226
214
|
}
|
|
227
215
|
|
|
216
|
+
public recordEstimatedSubmitProof(stats: EstimatedSubmitProofStats) {
|
|
217
|
+
const attributes = { [Attributes.L1_TX_TYPE]: 'submitProof' } as const;
|
|
218
|
+
|
|
219
|
+
this.txGasEstimated.record(Number(stats.gasLimit), attributes);
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
this.gasPriceEstimated.record(
|
|
223
|
+
parseInt(formatEther(stats.baseFeePerGas + stats.maxPriorityFeePerGas, 'gwei'), 10),
|
|
224
|
+
);
|
|
225
|
+
} catch {
|
|
226
|
+
// ignore
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
this.txTotalFeeEstimated.record(parseFloat(formatEther(stats.estimatedTotalFee)));
|
|
231
|
+
} catch {
|
|
232
|
+
// ignore
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
228
236
|
public recordSenderBalance(wei: bigint, senderAddress: string) {
|
|
229
237
|
const eth = parseFloat(formatEther(wei, 'wei'));
|
|
230
238
|
this.senderBalance.record(eth, {
|
|
@@ -4,13 +4,7 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
|
4
4
|
import { sleep } from '@aztec/foundation/sleep';
|
|
5
5
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
6
6
|
import { type L1RollupConstants, getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
7
|
-
import {
|
|
8
|
-
type TelemetryClient,
|
|
9
|
-
type Traceable,
|
|
10
|
-
type Tracer,
|
|
11
|
-
getTelemetryClient,
|
|
12
|
-
trackSpan,
|
|
13
|
-
} from '@aztec/telemetry-client';
|
|
7
|
+
import { type TelemetryClient, type Traceable, type Tracer, getTelemetryClient } from '@aztec/telemetry-client';
|
|
14
8
|
|
|
15
9
|
export interface EpochMonitorHandler {
|
|
16
10
|
handleEpochReadyToProve(epochNumber: EpochNumber): Promise<boolean>;
|
|
@@ -73,12 +67,10 @@ export class EpochMonitor implements Traceable {
|
|
|
73
67
|
this.log.info('Stopped EpochMonitor');
|
|
74
68
|
}
|
|
75
69
|
|
|
76
|
-
@trackSpan('EpochMonitor.work')
|
|
77
70
|
public async work() {
|
|
78
71
|
const { epochToProve, blockNumber, slotNumber } = await this.getEpochNumberToProve();
|
|
79
|
-
this.log.debug(`Epoch to prove: ${epochToProve}`, { blockNumber, slotNumber });
|
|
80
72
|
if (epochToProve === undefined) {
|
|
81
|
-
this.log.trace(`Next block to prove ${blockNumber} not yet mined`, { blockNumber });
|
|
73
|
+
this.log.trace(`Next block to prove ${blockNumber} not yet mined`, { epochToProve, blockNumber, slotNumber });
|
|
82
74
|
return;
|
|
83
75
|
}
|
|
84
76
|
if (this.latestEpochNumber !== undefined && epochToProve <= this.latestEpochNumber) {
|
|
@@ -93,20 +85,20 @@ export class EpochMonitor implements Traceable {
|
|
|
93
85
|
}
|
|
94
86
|
|
|
95
87
|
if (this.options.provingDelayMs) {
|
|
96
|
-
this.log.
|
|
88
|
+
this.log.warn(`Waiting ${this.options.provingDelayMs}ms before proving epoch ${epochToProve}`);
|
|
97
89
|
await sleep(this.options.provingDelayMs);
|
|
98
90
|
}
|
|
99
91
|
|
|
100
|
-
this.log.
|
|
92
|
+
this.log.verbose(`Epoch ${epochToProve} is ready to be proven`);
|
|
101
93
|
if (await this.handler?.handleEpochReadyToProve(epochToProve)) {
|
|
102
94
|
this.latestEpochNumber = epochToProve;
|
|
103
95
|
}
|
|
104
96
|
}
|
|
105
97
|
|
|
106
98
|
private async getEpochNumberToProve() {
|
|
107
|
-
const lastBlockProven = await this.l2BlockSource.
|
|
99
|
+
const lastBlockProven = (await this.l2BlockSource.getBlockNumber({ tag: 'proven' })) ?? BlockNumber.ZERO;
|
|
108
100
|
const firstBlockToProve = BlockNumber(lastBlockProven + 1);
|
|
109
|
-
const firstBlockHeaderToProve = await this.l2BlockSource.
|
|
101
|
+
const firstBlockHeaderToProve = (await this.l2BlockSource.getBlockData({ number: firstBlockToProve }))?.header;
|
|
110
102
|
if (!firstBlockHeaderToProve) {
|
|
111
103
|
return { epochToProve: undefined, blockNumber: firstBlockToProve };
|
|
112
104
|
}
|