@aztec/prover-node 0.0.1-commit.5daedc8 → 0.0.1-commit.5de5ca79e
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/rerun-epoch-proving-job.d.ts +4 -3
- package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
- package/dest/actions/rerun-epoch-proving-job.js +2 -2
- 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 +5 -2
- package/dest/config.d.ts +8 -10
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +19 -21
- package/dest/factory.d.ts +20 -16
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +28 -62
- 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-data.d.ts +7 -6
- package/dest/job/epoch-proving-job-data.d.ts.map +1 -1
- package/dest/job/epoch-proving-job-data.js +24 -18
- package/dest/job/epoch-proving-job.d.ts +5 -4
- package/dest/job/epoch-proving-job.d.ts.map +1 -1
- package/dest/job/epoch-proving-job.js +511 -108
- package/dest/metrics.d.ts +14 -3
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +54 -97
- 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 +8 -18
- package/dest/prover-node-publisher.d.ts +12 -10
- package/dest/prover-node-publisher.d.ts.map +1 -1
- package/dest/prover-node-publisher.js +46 -40
- package/dest/prover-node.d.ts +22 -12
- package/dest/prover-node.d.ts.map +1 -1
- package/dest/prover-node.js +442 -55
- package/dest/prover-publisher-factory.d.ts +9 -5
- package/dest/prover-publisher-factory.d.ts.map +1 -1
- package/dest/prover-publisher-factory.js +4 -2
- package/package.json +26 -25
- package/src/actions/rerun-epoch-proving-job.ts +5 -3
- package/src/actions/upload-epoch-proof-failure.ts +1 -1
- package/src/bin/run-failed-epoch.ts +5 -2
- package/src/config.ts +27 -33
- package/src/factory.ts +64 -104
- package/src/index.ts +1 -0
- package/src/job/epoch-proving-job-data.ts +28 -23
- package/src/job/epoch-proving-job.ts +151 -111
- package/src/metrics.ts +64 -81
- package/src/monitors/epoch-monitor.ts +6 -14
- package/src/prover-node-publisher.ts +67 -55
- package/src/prover-node.ts +54 -42
- package/src/prover-publisher-factory.ts +16 -8
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
2
|
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
3
|
-
import { EpochNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
4
4
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
5
|
-
import { Fr } from '@aztec/foundation/
|
|
6
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
5
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
7
7
|
import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
8
8
|
import { Timer } from '@aztec/foundation/timer';
|
|
9
|
+
import { AVM_MAX_CONCURRENT_SIMULATIONS } from '@aztec/native';
|
|
9
10
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
11
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
12
|
import { buildFinalBlobChallenges } from '@aztec/prover-client/helpers';
|
|
12
13
|
import type { PublicProcessor, PublicProcessorFactory } from '@aztec/simulator/server';
|
|
13
14
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
14
15
|
import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
16
|
+
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
15
17
|
import {
|
|
16
18
|
type EpochProver,
|
|
17
19
|
type EpochProvingJobState,
|
|
@@ -42,7 +44,7 @@ export type EpochProvingJobOptions = {
|
|
|
42
44
|
*/
|
|
43
45
|
export class EpochProvingJob implements Traceable {
|
|
44
46
|
private state: EpochProvingJobState = 'initialized';
|
|
45
|
-
private log
|
|
47
|
+
private log: Logger;
|
|
46
48
|
private uuid: string;
|
|
47
49
|
|
|
48
50
|
private runPromise: Promise<void> | undefined;
|
|
@@ -61,9 +63,14 @@ export class EpochProvingJob implements Traceable {
|
|
|
61
63
|
private metrics: ProverNodeJobMetrics,
|
|
62
64
|
private deadline: Date | undefined,
|
|
63
65
|
private config: EpochProvingJobOptions,
|
|
66
|
+
bindings?: LoggerBindings,
|
|
64
67
|
) {
|
|
65
68
|
validateEpochProvingJobData(data);
|
|
66
69
|
this.uuid = crypto.randomUUID();
|
|
70
|
+
this.log = createLogger('prover-node:epoch-proving-job', {
|
|
71
|
+
...bindings,
|
|
72
|
+
instanceId: `epoch-${data.epochNumber}`,
|
|
73
|
+
});
|
|
67
74
|
this.tracer = metrics.tracer;
|
|
68
75
|
}
|
|
69
76
|
|
|
@@ -91,8 +98,8 @@ export class EpochProvingJob implements Traceable {
|
|
|
91
98
|
return this.data.epochNumber;
|
|
92
99
|
}
|
|
93
100
|
|
|
94
|
-
private get
|
|
95
|
-
return this.data.
|
|
101
|
+
private get checkpoints() {
|
|
102
|
+
return this.data.checkpoints;
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
private get txs() {
|
|
@@ -117,13 +124,21 @@ export class EpochProvingJob implements Traceable {
|
|
|
117
124
|
|
|
118
125
|
const attestations = this.attestations.map(attestation => attestation.toViem());
|
|
119
126
|
const epochNumber = this.epochNumber;
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
|
|
127
|
+
const epochSizeCheckpoints = this.checkpoints.length;
|
|
128
|
+
const epochSizeBlocks = this.checkpoints.reduce((accum, checkpoint) => accum + checkpoint.blocks.length, 0);
|
|
129
|
+
const epochSizeTxs = this.checkpoints.reduce(
|
|
130
|
+
(accum, checkpoint) =>
|
|
131
|
+
accum + checkpoint.blocks.reduce((accumC, block) => accumC + block.body.txEffects.length, 0),
|
|
132
|
+
0,
|
|
133
|
+
);
|
|
134
|
+
const fromCheckpoint = this.checkpoints[0].number;
|
|
135
|
+
const toCheckpoint = this.checkpoints.at(-1)!.number;
|
|
136
|
+
const fromBlock = this.checkpoints[0].blocks[0].number;
|
|
137
|
+
const toBlock = this.checkpoints.at(-1)!.blocks.at(-1)!.number;
|
|
138
|
+
this.log.info(`Starting epoch ${epochNumber} proving job with checkpoints ${fromCheckpoint} to ${toCheckpoint}`, {
|
|
124
139
|
fromBlock,
|
|
125
140
|
toBlock,
|
|
126
|
-
|
|
141
|
+
epochSizeTxs,
|
|
127
142
|
epochNumber,
|
|
128
143
|
uuid: this.uuid,
|
|
129
144
|
});
|
|
@@ -134,87 +149,116 @@ export class EpochProvingJob implements Traceable {
|
|
|
134
149
|
this.runPromise = promise;
|
|
135
150
|
|
|
136
151
|
try {
|
|
137
|
-
const
|
|
152
|
+
const blobTimer = new Timer();
|
|
153
|
+
const blobFieldsPerCheckpoint = this.checkpoints.map(checkpoint => checkpoint.toBlobFields());
|
|
138
154
|
const finalBlobBatchingChallenges = await buildFinalBlobChallenges(blobFieldsPerCheckpoint);
|
|
155
|
+
this.metrics.recordBlobProcessing(blobTimer.ms());
|
|
139
156
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const totalNumCheckpoints = epochSizeBlocks;
|
|
143
|
-
|
|
144
|
-
this.prover.startNewEpoch(epochNumber, totalNumCheckpoints, finalBlobBatchingChallenges);
|
|
157
|
+
this.prover.startNewEpoch(epochNumber, epochSizeCheckpoints, finalBlobBatchingChallenges);
|
|
158
|
+
const chonkTimer = new Timer();
|
|
145
159
|
await this.prover.startChonkVerifierCircuits(Array.from(this.txs.values()));
|
|
160
|
+
this.metrics.recordChonkVerifier(chonkTimer.ms());
|
|
146
161
|
|
|
147
|
-
|
|
148
|
-
|
|
162
|
+
// Everything in the epoch should have the same chainId and version.
|
|
163
|
+
const { chainId, version } = this.checkpoints[0].blocks[0].header.globalVariables;
|
|
149
164
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
this.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
noteHashTreeRoot: block.header.state.partial.noteHashTree.root,
|
|
160
|
-
nullifierTreeRoot: block.header.state.partial.nullifierTree.root,
|
|
161
|
-
publicDataTreeRoot: block.header.state.partial.publicDataTree.root,
|
|
162
|
-
previousHeader: previousHeader.hash(),
|
|
163
|
-
uuid: this.uuid,
|
|
164
|
-
...globalVariables,
|
|
165
|
-
});
|
|
165
|
+
const previousBlockHeaders = this.gatherPreviousBlockHeaders();
|
|
166
|
+
|
|
167
|
+
const allCheckpointsTimer = new Timer();
|
|
168
|
+
|
|
169
|
+
const parallelism = this.config.parallelBlockLimit
|
|
170
|
+
? this.config.parallelBlockLimit
|
|
171
|
+
: AVM_MAX_CONCURRENT_SIMULATIONS > 0
|
|
172
|
+
? AVM_MAX_CONCURRENT_SIMULATIONS
|
|
173
|
+
: this.checkpoints.length;
|
|
166
174
|
|
|
175
|
+
await asyncPool(parallelism, this.checkpoints, async checkpoint => {
|
|
176
|
+
this.checkState();
|
|
177
|
+
const checkpointTimer = new Timer();
|
|
178
|
+
|
|
179
|
+
const checkpointIndex = checkpoint.number - fromCheckpoint;
|
|
167
180
|
const checkpointConstants = CheckpointConstantData.from({
|
|
168
|
-
chainId
|
|
169
|
-
version
|
|
181
|
+
chainId,
|
|
182
|
+
version,
|
|
170
183
|
vkTreeRoot: getVKTreeRoot(),
|
|
171
184
|
protocolContractsHash: protocolContractsHash,
|
|
172
185
|
proverId: this.prover.getProverId().toField(),
|
|
173
|
-
slotNumber:
|
|
174
|
-
coinbase:
|
|
175
|
-
feeRecipient:
|
|
176
|
-
gasFees:
|
|
186
|
+
slotNumber: checkpoint.header.slotNumber,
|
|
187
|
+
coinbase: checkpoint.header.coinbase,
|
|
188
|
+
feeRecipient: checkpoint.header.feeRecipient,
|
|
189
|
+
gasFees: checkpoint.header.gasFees,
|
|
190
|
+
});
|
|
191
|
+
const previousHeader = previousBlockHeaders[checkpointIndex];
|
|
192
|
+
const l1ToL2Messages = this.getL1ToL2Messages(checkpoint);
|
|
193
|
+
|
|
194
|
+
this.log.verbose(`Starting processing checkpoint ${checkpoint.number}`, {
|
|
195
|
+
number: checkpoint.number,
|
|
196
|
+
checkpointHash: checkpoint.hash().toString(),
|
|
197
|
+
lastArchive: checkpoint.header.lastArchiveRoot,
|
|
198
|
+
previousHeader: previousHeader.hash(),
|
|
199
|
+
uuid: this.uuid,
|
|
177
200
|
});
|
|
178
201
|
|
|
179
|
-
// TODO(#17027): Enable multiple blocks per checkpoint.
|
|
180
|
-
// Each checkpoint has only one block.
|
|
181
|
-
const totalNumBlocks = 1;
|
|
182
|
-
const checkpointIndex = block.number - fromBlock;
|
|
183
202
|
await this.prover.startNewCheckpoint(
|
|
184
203
|
checkpointIndex,
|
|
185
204
|
checkpointConstants,
|
|
186
205
|
l1ToL2Messages,
|
|
187
|
-
|
|
206
|
+
checkpoint.blocks.length,
|
|
188
207
|
previousHeader,
|
|
189
208
|
);
|
|
190
209
|
|
|
191
|
-
|
|
192
|
-
|
|
210
|
+
for (let blockIndex = 0; blockIndex < checkpoint.blocks.length; blockIndex++) {
|
|
211
|
+
const blockTimer = new Timer();
|
|
212
|
+
const block = checkpoint.blocks[blockIndex];
|
|
213
|
+
const globalVariables = block.header.globalVariables;
|
|
214
|
+
const txs = this.getTxs(block);
|
|
215
|
+
|
|
216
|
+
this.log.verbose(`Starting processing block ${block.number}`, {
|
|
217
|
+
number: block.number,
|
|
218
|
+
blockHash: (await block.hash()).toString(),
|
|
219
|
+
lastArchive: block.header.lastArchive.root,
|
|
220
|
+
noteHashTreeRoot: block.header.state.partial.noteHashTree.root,
|
|
221
|
+
nullifierTreeRoot: block.header.state.partial.nullifierTree.root,
|
|
222
|
+
publicDataTreeRoot: block.header.state.partial.publicDataTree.root,
|
|
223
|
+
...globalVariables,
|
|
224
|
+
numTxs: txs.length,
|
|
225
|
+
});
|
|
193
226
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
227
|
+
// Start block proving
|
|
228
|
+
await this.prover.startNewBlock(block.number, globalVariables.timestamp, txs.length);
|
|
229
|
+
|
|
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
|
+
const db = await this.createFork(
|
|
233
|
+
BlockNumber(block.number - 1),
|
|
234
|
+
blockIndex === 0 ? l1ToL2Messages : undefined,
|
|
235
|
+
);
|
|
236
|
+
const config = PublicSimulatorConfig.from({
|
|
237
|
+
proverId: this.prover.getProverId().toField(),
|
|
238
|
+
skipFeeEnforcement: false,
|
|
239
|
+
collectDebugLogs: false,
|
|
240
|
+
collectHints: true,
|
|
241
|
+
collectPublicInputs: true,
|
|
242
|
+
collectStatistics: false,
|
|
243
|
+
});
|
|
244
|
+
const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, config);
|
|
245
|
+
const processed = await this.processTxs(publicProcessor, txs);
|
|
246
|
+
await this.prover.addTxs(processed);
|
|
247
|
+
await db.close();
|
|
248
|
+
this.log.verbose(`Processed all ${txs.length} txs for block ${block.number}`, {
|
|
249
|
+
blockNumber: block.number,
|
|
250
|
+
blockHash: (await block.hash()).toString(),
|
|
251
|
+
uuid: this.uuid,
|
|
252
|
+
});
|
|
213
253
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
254
|
+
// Mark block as completed to pad it
|
|
255
|
+
const expectedBlockHeader = block.header;
|
|
256
|
+
await this.prover.setBlockCompleted(block.number, expectedBlockHeader);
|
|
257
|
+
this.metrics.recordBlockProcessing(blockTimer.ms());
|
|
258
|
+
}
|
|
259
|
+
this.metrics.recordCheckpointProcessing(checkpointTimer.ms());
|
|
217
260
|
});
|
|
261
|
+
this.metrics.recordAllCheckpointsProcessing(allCheckpointsTimer.ms());
|
|
218
262
|
|
|
219
263
|
const executionTime = timer.ms();
|
|
220
264
|
|
|
@@ -226,16 +270,16 @@ export class EpochProvingJob implements Traceable {
|
|
|
226
270
|
|
|
227
271
|
if (this.config.skipSubmitProof) {
|
|
228
272
|
this.log.info(
|
|
229
|
-
`Proof publishing is disabled. Dropping valid proof for epoch ${epochNumber} (
|
|
273
|
+
`Proof publishing is disabled. Dropping valid proof for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`,
|
|
230
274
|
);
|
|
231
275
|
this.state = 'completed';
|
|
232
|
-
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeBlocks, epochSizeTxs);
|
|
276
|
+
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeCheckpoints, epochSizeBlocks, epochSizeTxs);
|
|
233
277
|
return;
|
|
234
278
|
}
|
|
235
279
|
|
|
236
280
|
const success = await this.publisher.submitEpochProof({
|
|
237
|
-
|
|
238
|
-
|
|
281
|
+
fromCheckpoint,
|
|
282
|
+
toCheckpoint,
|
|
239
283
|
epochNumber,
|
|
240
284
|
publicInputs,
|
|
241
285
|
proof,
|
|
@@ -246,12 +290,12 @@ export class EpochProvingJob implements Traceable {
|
|
|
246
290
|
throw new Error('Failed to submit epoch proof to L1');
|
|
247
291
|
}
|
|
248
292
|
|
|
249
|
-
this.log.info(`Submitted proof for epoch ${epochNumber} (
|
|
293
|
+
this.log.info(`Submitted proof for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`, {
|
|
250
294
|
epochNumber,
|
|
251
295
|
uuid: this.uuid,
|
|
252
296
|
});
|
|
253
297
|
this.state = 'completed';
|
|
254
|
-
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeBlocks, epochSizeTxs);
|
|
298
|
+
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeCheckpoints, epochSizeBlocks, epochSizeTxs);
|
|
255
299
|
} catch (err: any) {
|
|
256
300
|
if (err && err.name === 'HaltExecutionError') {
|
|
257
301
|
this.log.warn(`Halted execution of epoch ${epochNumber} prover job`, {
|
|
@@ -274,22 +318,29 @@ export class EpochProvingJob implements Traceable {
|
|
|
274
318
|
}
|
|
275
319
|
|
|
276
320
|
/**
|
|
277
|
-
* Create a new db fork for tx processing, inserting
|
|
321
|
+
* Create a new db fork for tx processing, optionally inserting L1 to L2 messages.
|
|
322
|
+
* L1 to L2 messages should only be inserted for the first block in a checkpoint,
|
|
323
|
+
* as subsequent blocks' synced state already includes them.
|
|
278
324
|
* 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.
|
|
279
325
|
*/
|
|
280
|
-
private async createFork(blockNumber:
|
|
326
|
+
private async createFork(blockNumber: BlockNumber, l1ToL2Messages: Fr[] | undefined) {
|
|
327
|
+
this.log.verbose(`Creating fork at ${blockNumber}`, { blockNumber });
|
|
281
328
|
const db = await this.dbProvider.fork(blockNumber);
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
329
|
+
|
|
330
|
+
if (l1ToL2Messages !== undefined) {
|
|
331
|
+
this.log.verbose(`Inserting ${l1ToL2Messages.length} L1 to L2 messages in fork`, {
|
|
332
|
+
blockNumber,
|
|
333
|
+
l1ToL2Messages: l1ToL2Messages.map(m => m.toString()),
|
|
334
|
+
});
|
|
335
|
+
const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
|
|
336
|
+
l1ToL2Messages,
|
|
337
|
+
Fr.ZERO,
|
|
338
|
+
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
339
|
+
'Too many L1 to L2 messages',
|
|
340
|
+
);
|
|
341
|
+
await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
|
|
342
|
+
}
|
|
343
|
+
|
|
293
344
|
return db;
|
|
294
345
|
}
|
|
295
346
|
|
|
@@ -346,11 +397,12 @@ export class EpochProvingJob implements Traceable {
|
|
|
346
397
|
const intervalMs = Math.ceil((await l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
|
|
347
398
|
this.epochCheckPromise = new RunningPromise(
|
|
348
399
|
async () => {
|
|
349
|
-
const
|
|
350
|
-
const blockHashes = await Promise.all(
|
|
351
|
-
const
|
|
400
|
+
const blockHeaders = await l2BlockSource.getCheckpointedBlockHeadersForEpoch(this.epochNumber);
|
|
401
|
+
const blockHashes = await Promise.all(blockHeaders.map(header => header.hash()));
|
|
402
|
+
const thisBlocks = this.checkpoints.flatMap(checkpoint => checkpoint.blocks);
|
|
403
|
+
const thisBlockHashes = await Promise.all(thisBlocks.map(block => block.hash()));
|
|
352
404
|
if (
|
|
353
|
-
|
|
405
|
+
blockHeaders.length !== thisBlocks.length ||
|
|
354
406
|
!blockHashes.every((block, i) => block.equals(thisBlockHashes[i]))
|
|
355
407
|
) {
|
|
356
408
|
this.log.warn('Epoch blocks changed underfoot', {
|
|
@@ -368,30 +420,18 @@ export class EpochProvingJob implements Traceable {
|
|
|
368
420
|
this.log.verbose(`Scheduled epoch check for epoch ${this.epochNumber} every ${intervalMs}ms`);
|
|
369
421
|
}
|
|
370
422
|
|
|
371
|
-
/* Returns the header
|
|
372
|
-
private
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
return block.getBlockHeader();
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (blockNumber === Number(this.data.previousBlockHeader.getBlockNumber())) {
|
|
379
|
-
return this.data.previousBlockHeader;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
throw new Error(
|
|
383
|
-
`Block header not found for block number ${blockNumber} (got ${this.blocks
|
|
384
|
-
.map(b => b.number)
|
|
385
|
-
.join(', ')} and previous header ${this.data.previousBlockHeader.getBlockNumber()})`,
|
|
386
|
-
);
|
|
423
|
+
/* Returns the last block header in the previous checkpoint for all checkpoints in the epoch */
|
|
424
|
+
private gatherPreviousBlockHeaders() {
|
|
425
|
+
const lastBlocks = this.checkpoints.map(checkpoint => checkpoint.blocks.at(-1)!);
|
|
426
|
+
return [this.data.previousBlockHeader, ...lastBlocks.map(block => block.header).slice(0, -1)];
|
|
387
427
|
}
|
|
388
428
|
|
|
389
429
|
private getTxs(block: L2Block): Tx[] {
|
|
390
430
|
return block.body.txEffects.map(txEffect => this.txs.get(txEffect.txHash.toString())!);
|
|
391
431
|
}
|
|
392
432
|
|
|
393
|
-
private getL1ToL2Messages(
|
|
394
|
-
return this.data.l1ToL2Messages[
|
|
433
|
+
private getL1ToL2Messages(checkpoint: Checkpoint) {
|
|
434
|
+
return this.data.l1ToL2Messages[checkpoint.number];
|
|
395
435
|
}
|
|
396
436
|
|
|
397
437
|
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';
|
|
@@ -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';
|
|
@@ -21,40 +21,69 @@ 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
|
|
|
28
|
+
private blobProcessingDuration: Gauge;
|
|
29
|
+
private chonkVerifierDuration: Gauge;
|
|
30
|
+
private blockProcessingDuration: Histogram;
|
|
31
|
+
private checkpointProcessingDuration: Histogram;
|
|
32
|
+
private allCheckpointsProcessingDuration: Gauge;
|
|
33
|
+
|
|
27
34
|
constructor(
|
|
28
35
|
private meter: Meter,
|
|
29
36
|
public readonly tracer: Tracer,
|
|
30
37
|
private logger = createLogger('prover-node:publisher:metrics'),
|
|
31
38
|
) {
|
|
32
|
-
this.proverEpochExecutionDuration = this.meter.createHistogram(Metrics.PROVER_NODE_EXECUTION_DURATION
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
this.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
});
|
|
46
|
-
this.provingJobTransactions = this.meter.createGauge(Metrics.PROVER_NODE_JOB_TRANSACTIONS, {
|
|
47
|
-
description: 'Number of transactions in a proven epoch',
|
|
48
|
-
valueType: ValueType.INT,
|
|
49
|
-
});
|
|
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
|
+
);
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
public recordProvingJob(
|
|
54
|
+
public recordProvingJob(
|
|
55
|
+
executionTimeMs: number,
|
|
56
|
+
totalTimeMs: number,
|
|
57
|
+
numCheckpoints: number,
|
|
58
|
+
numBlocks: number,
|
|
59
|
+
numTxs: number,
|
|
60
|
+
) {
|
|
53
61
|
this.proverEpochExecutionDuration.record(Math.ceil(executionTimeMs));
|
|
54
62
|
this.provingJobDuration.record(totalTimeMs / 1000);
|
|
63
|
+
this.provingJobCheckpoints.record(Math.floor(numCheckpoints));
|
|
55
64
|
this.provingJobBlocks.record(Math.floor(numBlocks));
|
|
56
65
|
this.provingJobTransactions.record(Math.floor(numTxs));
|
|
57
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
|
+
}
|
|
58
87
|
}
|
|
59
88
|
|
|
60
89
|
export class ProverNodeRewardsMetrics {
|
|
@@ -69,15 +98,9 @@ export class ProverNodeRewardsMetrics {
|
|
|
69
98
|
private rollup: RollupContract,
|
|
70
99
|
private logger = createLogger('prover-node:publisher:metrics'),
|
|
71
100
|
) {
|
|
72
|
-
this.rewards = this.meter.createObservableGauge(Metrics.PROVER_NODE_REWARDS_PER_EPOCH
|
|
73
|
-
valueType: ValueType.DOUBLE,
|
|
74
|
-
description: 'The rewards earned',
|
|
75
|
-
});
|
|
101
|
+
this.rewards = this.meter.createObservableGauge(Metrics.PROVER_NODE_REWARDS_PER_EPOCH);
|
|
76
102
|
|
|
77
|
-
this.accumulatedRewards = this.meter
|
|
78
|
-
valueType: ValueType.DOUBLE,
|
|
79
|
-
description: 'The rewards earned (total)',
|
|
80
|
-
});
|
|
103
|
+
this.accumulatedRewards = createUpDownCounterWithDefault(this.meter, Metrics.PROVER_NODE_REWARDS_TOTAL);
|
|
81
104
|
}
|
|
82
105
|
|
|
83
106
|
public async start() {
|
|
@@ -138,68 +161,28 @@ export class ProverNodePublisherMetrics {
|
|
|
138
161
|
) {
|
|
139
162
|
this.meter = client.getMeter(name);
|
|
140
163
|
|
|
141
|
-
this.gasPrice = this.meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE
|
|
142
|
-
description: 'The gas price used for transactions',
|
|
143
|
-
unit: 'gwei',
|
|
144
|
-
valueType: ValueType.DOUBLE,
|
|
145
|
-
});
|
|
164
|
+
this.gasPrice = this.meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE);
|
|
146
165
|
|
|
147
|
-
this.txCount = this.meter
|
|
148
|
-
|
|
166
|
+
this.txCount = createUpDownCounterWithDefault(this.meter, Metrics.L1_PUBLISHER_TX_COUNT, {
|
|
167
|
+
[Attributes.L1_TX_TYPE]: ['submitProof'],
|
|
168
|
+
[Attributes.OK]: [true, false],
|
|
149
169
|
});
|
|
150
170
|
|
|
151
|
-
this.txDuration = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_DURATION
|
|
152
|
-
description: 'The duration of transaction processing',
|
|
153
|
-
unit: 'ms',
|
|
154
|
-
valueType: ValueType.INT,
|
|
155
|
-
});
|
|
171
|
+
this.txDuration = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_DURATION);
|
|
156
172
|
|
|
157
|
-
this.txGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_GAS
|
|
158
|
-
description: 'The gas consumed by transactions',
|
|
159
|
-
unit: 'gas',
|
|
160
|
-
valueType: ValueType.INT,
|
|
161
|
-
});
|
|
173
|
+
this.txGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_GAS);
|
|
162
174
|
|
|
163
|
-
this.txCalldataSize = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_SIZE
|
|
164
|
-
description: 'The size of the calldata in transactions',
|
|
165
|
-
unit: 'By',
|
|
166
|
-
valueType: ValueType.INT,
|
|
167
|
-
});
|
|
175
|
+
this.txCalldataSize = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_SIZE);
|
|
168
176
|
|
|
169
|
-
this.txCalldataGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_GAS
|
|
170
|
-
description: 'The gas consumed by the calldata in transactions',
|
|
171
|
-
unit: 'gas',
|
|
172
|
-
valueType: ValueType.INT,
|
|
173
|
-
});
|
|
177
|
+
this.txCalldataGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_GAS);
|
|
174
178
|
|
|
175
|
-
this.txBlobDataGasUsed = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_USED
|
|
176
|
-
description: 'The amount of blob gas used in transactions',
|
|
177
|
-
unit: 'gas',
|
|
178
|
-
valueType: ValueType.INT,
|
|
179
|
-
});
|
|
179
|
+
this.txBlobDataGasUsed = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_USED);
|
|
180
180
|
|
|
181
|
-
this.txBlobDataGasCost = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_COST
|
|
182
|
-
description: 'The gas cost of blobs in transactions',
|
|
183
|
-
unit: 'gwei',
|
|
184
|
-
valueType: ValueType.INT,
|
|
185
|
-
});
|
|
181
|
+
this.txBlobDataGasCost = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_COST);
|
|
186
182
|
|
|
187
|
-
this.txTotalFee = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_TOTAL_FEE
|
|
188
|
-
description: 'How much L1 tx costs',
|
|
189
|
-
unit: 'gwei',
|
|
190
|
-
valueType: ValueType.DOUBLE,
|
|
191
|
-
advice: {
|
|
192
|
-
explicitBucketBoundaries: [
|
|
193
|
-
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,
|
|
194
|
-
],
|
|
195
|
-
},
|
|
196
|
-
});
|
|
183
|
+
this.txTotalFee = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_TOTAL_FEE);
|
|
197
184
|
|
|
198
|
-
this.senderBalance = this.meter.createGauge(Metrics.L1_PUBLISHER_BALANCE
|
|
199
|
-
unit: 'eth',
|
|
200
|
-
description: 'The balance of the sender address',
|
|
201
|
-
valueType: ValueType.DOUBLE,
|
|
202
|
-
});
|
|
185
|
+
this.senderBalance = this.meter.createGauge(Metrics.L1_PUBLISHER_BALANCE);
|
|
203
186
|
}
|
|
204
187
|
|
|
205
188
|
recordFailedTx() {
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import { EpochNumber } from '@aztec/foundation/branded-types';
|
|
1
|
+
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
3
|
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,11 +85,11 @@ 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
|
}
|
|
@@ -105,7 +97,7 @@ export class EpochMonitor implements Traceable {
|
|
|
105
97
|
|
|
106
98
|
private async getEpochNumberToProve() {
|
|
107
99
|
const lastBlockProven = await this.l2BlockSource.getProvenBlockNumber();
|
|
108
|
-
const firstBlockToProve = lastBlockProven + 1;
|
|
100
|
+
const firstBlockToProve = BlockNumber(lastBlockProven + 1);
|
|
109
101
|
const firstBlockHeaderToProve = await this.l2BlockSource.getBlockHeader(firstBlockToProve);
|
|
110
102
|
if (!firstBlockHeaderToProve) {
|
|
111
103
|
return { epochToProve: undefined, blockNumber: firstBlockToProve };
|