@aztec/prover-node 0.0.0-test.1 → 0.0.1-fake-ceab37513c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dest/actions/download-epoch-proving-job.d.ts +18 -0
  2. package/dest/actions/download-epoch-proving-job.d.ts.map +1 -0
  3. package/dest/actions/download-epoch-proving-job.js +37 -0
  4. package/dest/actions/index.d.ts +3 -0
  5. package/dest/actions/index.d.ts.map +1 -0
  6. package/dest/actions/index.js +2 -0
  7. package/dest/actions/rerun-epoch-proving-job.d.ts +11 -0
  8. package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -0
  9. package/dest/actions/rerun-epoch-proving-job.js +40 -0
  10. package/dest/actions/upload-epoch-proof-failure.d.ts +15 -0
  11. package/dest/actions/upload-epoch-proof-failure.d.ts.map +1 -0
  12. package/dest/actions/upload-epoch-proof-failure.js +78 -0
  13. package/dest/bin/run-failed-epoch.d.ts +2 -0
  14. package/dest/bin/run-failed-epoch.d.ts.map +1 -0
  15. package/dest/bin/run-failed-epoch.js +67 -0
  16. package/dest/config.d.ts +12 -9
  17. package/dest/config.d.ts.map +1 -1
  18. package/dest/config.js +81 -14
  19. package/dest/factory.d.ts +12 -8
  20. package/dest/factory.d.ts.map +1 -1
  21. package/dest/factory.js +94 -31
  22. package/dest/index.d.ts +1 -1
  23. package/dest/index.d.ts.map +1 -1
  24. package/dest/index.js +1 -1
  25. package/dest/job/epoch-proving-job-data.d.ts +16 -0
  26. package/dest/job/epoch-proving-job-data.d.ts.map +1 -0
  27. package/dest/job/epoch-proving-job-data.js +52 -0
  28. package/dest/job/epoch-proving-job.d.ts +30 -15
  29. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  30. package/dest/job/epoch-proving-job.js +119 -46
  31. package/dest/metrics.d.ts +28 -4
  32. package/dest/metrics.d.ts.map +1 -1
  33. package/dest/metrics.js +141 -35
  34. package/dest/monitors/epoch-monitor.d.ts +3 -1
  35. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  36. package/dest/monitors/epoch-monitor.js +15 -2
  37. package/dest/prover-node-publisher.d.ts +7 -10
  38. package/dest/prover-node-publisher.d.ts.map +1 -1
  39. package/dest/prover-node-publisher.js +58 -59
  40. package/dest/prover-node.d.ts +43 -39
  41. package/dest/prover-node.d.ts.map +1 -1
  42. package/dest/prover-node.js +171 -100
  43. package/dest/prover-publisher-factory.d.ts +21 -0
  44. package/dest/prover-publisher-factory.d.ts.map +1 -0
  45. package/dest/prover-publisher-factory.js +26 -0
  46. package/dest/test/index.d.ts +4 -2
  47. package/dest/test/index.d.ts.map +1 -1
  48. package/dest/test/index.js +1 -3
  49. package/package.json +36 -31
  50. package/src/actions/download-epoch-proving-job.ts +44 -0
  51. package/src/actions/index.ts +2 -0
  52. package/src/actions/rerun-epoch-proving-job.ts +61 -0
  53. package/src/actions/upload-epoch-proof-failure.ts +88 -0
  54. package/src/bin/run-failed-epoch.ts +77 -0
  55. package/src/config.ts +108 -24
  56. package/src/factory.ts +158 -43
  57. package/src/index.ts +1 -1
  58. package/src/job/epoch-proving-job-data.ts +76 -0
  59. package/src/job/epoch-proving-job.ts +177 -46
  60. package/src/metrics.ts +135 -37
  61. package/src/monitors/epoch-monitor.ts +16 -5
  62. package/src/prover-node-publisher.ts +90 -85
  63. package/src/prover-node.ts +203 -126
  64. package/src/prover-publisher-factory.ts +37 -0
  65. package/src/test/index.ts +7 -4
  66. package/dest/http.d.ts +0 -8
  67. package/dest/http.d.ts.map +0 -1
  68. package/dest/http.js +0 -9
  69. package/dest/prover-coordination/config.d.ts +0 -7
  70. package/dest/prover-coordination/config.d.ts.map +0 -1
  71. package/dest/prover-coordination/config.js +0 -11
  72. package/dest/prover-coordination/factory.d.ts +0 -22
  73. package/dest/prover-coordination/factory.d.ts.map +0 -1
  74. package/dest/prover-coordination/factory.js +0 -42
  75. package/dest/prover-coordination/index.d.ts +0 -3
  76. package/dest/prover-coordination/index.d.ts.map +0 -1
  77. package/dest/prover-coordination/index.js +0 -2
  78. package/src/http.ts +0 -13
  79. package/src/prover-coordination/config.ts +0 -17
  80. package/src/prover-coordination/factory.ts +0 -72
  81. package/src/prover-coordination/index.ts +0 -2
@@ -4,57 +4,55 @@ function _ts_decorate(decorators, target, key, desc) {
4
4
  else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  }
7
+ import { BatchedBlob, Blob } from '@aztec/blob-lib';
8
+ import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
7
9
  import { asyncPool } from '@aztec/foundation/async-pool';
10
+ import { padArrayEnd } from '@aztec/foundation/collection';
11
+ import { Fr } from '@aztec/foundation/fields';
8
12
  import { createLogger } from '@aztec/foundation/log';
9
- import { promiseWithResolvers } from '@aztec/foundation/promise';
13
+ import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
10
14
  import { Timer } from '@aztec/foundation/timer';
11
15
  import { EpochProvingJobTerminalState } from '@aztec/stdlib/interfaces/server';
16
+ import { MerkleTreeId } from '@aztec/stdlib/trees';
12
17
  import { Attributes, trackSpan } from '@aztec/telemetry-client';
13
18
  import * as crypto from 'node:crypto';
19
+ import { validateEpochProvingJobData } from './epoch-proving-job-data.js';
14
20
  /**
15
- * Job that grabs a range of blocks from the unfinalised chain from L1, gets their txs given their hashes,
21
+ * Job that grabs a range of blocks from the unfinalized chain from L1, gets their txs given their hashes,
16
22
  * re-executes their public calls, generates a rollup proof, and submits it to L1. This job will update the
17
23
  * world state as part of public call execution via the public processor.
18
24
  */ export class EpochProvingJob {
25
+ data;
19
26
  dbProvider;
20
- epochNumber;
21
- blocks;
22
- txs;
23
27
  prover;
24
28
  publicProcessorFactory;
25
29
  publisher;
26
30
  l2BlockSource;
27
- l1ToL2MessageSource;
28
31
  metrics;
29
32
  deadline;
30
33
  config;
31
- cleanUp;
32
34
  state;
33
35
  log;
34
36
  uuid;
35
37
  runPromise;
38
+ epochCheckPromise;
36
39
  deadlineTimeoutHandler;
37
40
  tracer;
38
- constructor(dbProvider, epochNumber, blocks, txs, prover, publicProcessorFactory, publisher, l2BlockSource, l1ToL2MessageSource, metrics, deadline, config = {
39
- parallelBlockLimit: 32
40
- }, cleanUp = ()=>Promise.resolve()){
41
+ constructor(data, dbProvider, prover, publicProcessorFactory, publisher, l2BlockSource, metrics, deadline, config){
42
+ this.data = data;
41
43
  this.dbProvider = dbProvider;
42
- this.epochNumber = epochNumber;
43
- this.blocks = blocks;
44
- this.txs = txs;
45
44
  this.prover = prover;
46
45
  this.publicProcessorFactory = publicProcessorFactory;
47
46
  this.publisher = publisher;
48
47
  this.l2BlockSource = l2BlockSource;
49
- this.l1ToL2MessageSource = l1ToL2MessageSource;
50
48
  this.metrics = metrics;
51
49
  this.deadline = deadline;
52
50
  this.config = config;
53
- this.cleanUp = cleanUp;
54
51
  this.state = 'initialized';
55
52
  this.log = createLogger('prover-node:epoch-proving-job');
53
+ validateEpochProvingJobData(data);
56
54
  this.uuid = crypto.randomUUID();
57
- this.tracer = metrics.client.getTracer('EpochProvingJob');
55
+ this.tracer = metrics.tracer;
58
56
  }
59
57
  getId() {
60
58
  return this.uuid;
@@ -63,12 +61,34 @@ import * as crypto from 'node:crypto';
63
61
  return this.state;
64
62
  }
65
63
  getEpochNumber() {
66
- return this.epochNumber;
64
+ return this.data.epochNumber;
65
+ }
66
+ getDeadline() {
67
+ return this.deadline;
68
+ }
69
+ getProvingData() {
70
+ return this.data;
71
+ }
72
+ get epochNumber() {
73
+ return this.data.epochNumber;
74
+ }
75
+ get blocks() {
76
+ return this.data.blocks;
77
+ }
78
+ get txs() {
79
+ return this.data.txs;
80
+ }
81
+ get attestations() {
82
+ return this.data.attestations;
67
83
  }
68
84
  /**
69
85
  * Proves the given epoch and submits the proof to L1.
70
86
  */ async run() {
71
87
  this.scheduleDeadlineStop();
88
+ if (!this.config.skipEpochCheck) {
89
+ await this.scheduleEpochCheck();
90
+ }
91
+ const attestations = this.attestations.map((attestation)=>attestation.toViem());
72
92
  const epochNumber = Number(this.epochNumber);
73
93
  const epochSizeBlocks = this.blocks.length;
74
94
  const epochSizeTxs = this.blocks.reduce((total, current)=>total + current.body.txEffects.length, 0);
@@ -88,14 +108,16 @@ import * as crypto from 'node:crypto';
88
108
  const { promise, resolve } = promiseWithResolvers();
89
109
  this.runPromise = promise;
90
110
  try {
91
- this.prover.startNewEpoch(epochNumber, fromBlock, epochSizeBlocks);
92
- await this.prover.startTubeCircuits(this.txs);
93
- await asyncPool(this.config.parallelBlockLimit, this.blocks, async (block)=>{
111
+ const allBlobs = (await Promise.all(this.blocks.map(async (block)=>await Blob.getBlobsPerBlock(block.body.toBlobFields())))).flat();
112
+ const finalBlobBatchingChallenges = await BatchedBlob.precomputeBatchedBlobChallenges(allBlobs);
113
+ this.prover.startNewEpoch(epochNumber, fromBlock, epochSizeBlocks, finalBlobBatchingChallenges);
114
+ await this.prover.startTubeCircuits(Array.from(this.txs.values()));
115
+ await asyncPool(this.config.parallelBlockLimit ?? 32, this.blocks, async (block)=>{
94
116
  this.checkState();
95
117
  const globalVariables = block.header.globalVariables;
96
- const txs = await this.getTxs(block);
97
- const l1ToL2Messages = await this.getL1ToL2Messages(block);
98
- const previousHeader = await this.getBlockHeader(block.number - 1);
118
+ const txs = this.getTxs(block);
119
+ const l1ToL2Messages = this.getL1ToL2Messages(block);
120
+ const previousHeader = this.getBlockHeader(block.number - 1);
99
121
  this.log.verbose(`Starting processing block ${block.number}`, {
100
122
  number: block.number,
101
123
  blockHash: (await block.hash()).toString(),
@@ -110,7 +132,7 @@ import * as crypto from 'node:crypto';
110
132
  // Start block proving
111
133
  await this.prover.startNewBlock(globalVariables, l1ToL2Messages, previousHeader);
112
134
  // Process public fns
113
- const db = await this.dbProvider.fork(block.number - 1);
135
+ const db = await this.createFork(block.number - 1, l1ToL2Messages);
114
136
  const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, true);
115
137
  const processed = await this.processTxs(publicProcessor, txs);
116
138
  await this.prover.addTxs(processed);
@@ -125,19 +147,27 @@ import * as crypto from 'node:crypto';
125
147
  });
126
148
  const executionTime = timer.ms();
127
149
  this.progressState('awaiting-prover');
128
- const { publicInputs, proof } = await this.prover.finaliseEpoch();
129
- this.log.info(`Finalised proof for epoch ${epochNumber}`, {
150
+ const { publicInputs, proof, batchedBlobInputs } = await this.prover.finalizeEpoch();
151
+ this.log.info(`Finalized proof for epoch ${epochNumber}`, {
130
152
  epochNumber,
131
153
  uuid: this.uuid,
132
154
  duration: timer.ms()
133
155
  });
134
156
  this.progressState('publishing-proof');
157
+ if (this.config.skipSubmitProof) {
158
+ this.log.info(`Proof publishing is disabled. Dropping valid proof for epoch ${epochNumber} (blocks ${fromBlock} to ${toBlock})`);
159
+ this.state = 'completed';
160
+ this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeBlocks, epochSizeTxs);
161
+ return;
162
+ }
135
163
  const success = await this.publisher.submitEpochProof({
136
164
  fromBlock,
137
165
  toBlock,
138
166
  epochNumber,
139
167
  publicInputs,
140
- proof
168
+ proof,
169
+ batchedBlobInputs,
170
+ attestations
141
171
  });
142
172
  if (!success) {
143
173
  throw new Error('Failed to submit epoch proof to L1');
@@ -152,7 +182,8 @@ import * as crypto from 'node:crypto';
152
182
  if (err && err.name === 'HaltExecutionError') {
153
183
  this.log.warn(`Halted execution of epoch ${epochNumber} prover job`, {
154
184
  uuid: this.uuid,
155
- epochNumber
185
+ epochNumber,
186
+ details: err.message
156
187
  });
157
188
  return;
158
189
  }
@@ -160,20 +191,35 @@ import * as crypto from 'node:crypto';
160
191
  uuid: this.uuid,
161
192
  epochNumber
162
193
  });
163
- this.state = 'failed';
194
+ if (this.state === 'processing' || this.state === 'awaiting-prover' || this.state === 'publishing-proof') {
195
+ this.state = 'failed';
196
+ }
164
197
  } finally{
165
198
  clearTimeout(this.deadlineTimeoutHandler);
166
- await this.cleanUp(this);
199
+ await this.epochCheckPromise?.stop();
167
200
  await this.prover.stop();
168
201
  resolve();
169
202
  }
170
203
  }
204
+ /**
205
+ * Create a new db fork for tx processing, inserting all L1 to L2.
206
+ * 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.
207
+ */ async createFork(blockNumber, l1ToL2Messages) {
208
+ const db = await this.dbProvider.fork(blockNumber);
209
+ const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 'Too many L1 to L2 messages');
210
+ this.log.verbose(`Creating fork at ${blockNumber} with ${l1ToL2Messages.length} L1 to L2 messages`, {
211
+ blockNumber,
212
+ l1ToL2Messages: l1ToL2MessagesPadded.map((m)=>m.toString())
213
+ });
214
+ await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
215
+ return db;
216
+ }
171
217
  progressState(state) {
172
218
  this.checkState();
173
219
  this.state = state;
174
220
  }
175
221
  checkState() {
176
- if (this.state === 'timed-out' || this.state === 'stopped' || this.state === 'failed') {
222
+ if (this.state === 'timed-out' || this.state === 'stopped' || this.state === 'failed' || this.state === 'reorg') {
177
223
  throw new HaltExecutionError(this.state);
178
224
  }
179
225
  }
@@ -209,22 +255,47 @@ import * as crypto from 'node:crypto';
209
255
  }, timeout);
210
256
  }
211
257
  }
212
- /* Returns the header for the given block number, or the genesis block for block zero. */ async getBlockHeader(blockNumber) {
213
- if (blockNumber === 0) {
214
- return (await this.dbProvider.fork()).getInitialHeader();
258
+ /**
259
+ * Kicks off a running promise that queries the archiver for the set of L2 blocks of the current epoch.
260
+ * If those change, stops the proving job with a `rerun` state, so the node re-enqueues it.
261
+ */ async scheduleEpochCheck() {
262
+ const l2BlockSource = this.l2BlockSource;
263
+ if (!l2BlockSource) {
264
+ this.log.warn(`No L2 block source available, skipping epoch check`);
265
+ return;
266
+ }
267
+ const intervalMs = Math.ceil((await l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
268
+ this.epochCheckPromise = new RunningPromise(async ()=>{
269
+ const blocks = await l2BlockSource.getBlockHeadersForEpoch(this.epochNumber);
270
+ const blockHashes = await Promise.all(blocks.map((block)=>block.hash()));
271
+ const thisBlockHashes = await Promise.all(this.blocks.map((block)=>block.hash()));
272
+ if (blocks.length !== this.blocks.length || !blockHashes.every((block, i)=>block.equals(thisBlockHashes[i]))) {
273
+ this.log.warn('Epoch blocks changed underfoot', {
274
+ uuid: this.uuid,
275
+ epochNumber: this.epochNumber,
276
+ oldBlockHashes: thisBlockHashes,
277
+ newBlockHashes: blockHashes
278
+ });
279
+ void this.stop('reorg');
280
+ }
281
+ }, this.log, intervalMs).start();
282
+ this.log.verbose(`Scheduled epoch check for epoch ${this.epochNumber} every ${intervalMs}ms`);
283
+ }
284
+ /* Returns the header for the given block number based on the epoch proving job data. */ getBlockHeader(blockNumber) {
285
+ const block = this.blocks.find((b)=>b.number === blockNumber);
286
+ if (block) {
287
+ return block.header;
215
288
  }
216
- return this.l2BlockSource.getBlockHeader(blockNumber);
289
+ if (blockNumber === Number(this.data.previousBlockHeader.getBlockNumber())) {
290
+ return this.data.previousBlockHeader;
291
+ }
292
+ throw new Error(`Block header not found for block number ${blockNumber} (got ${this.blocks.map((b)=>b.number).join(', ')} and previous header ${this.data.previousBlockHeader.getBlockNumber()})`);
217
293
  }
218
- async getTxs(block) {
219
- const txHashes = block.body.txEffects.map((tx)=>tx.txHash.toBigInt());
220
- const txsAndHashes = await Promise.all(this.txs.map(async (tx)=>({
221
- tx,
222
- hash: await tx.getTxHash()
223
- })));
224
- return txsAndHashes.filter((txAndHash)=>txHashes.includes(txAndHash.hash.toBigInt())).map((txAndHash)=>txAndHash.tx);
294
+ getTxs(block) {
295
+ return block.body.txEffects.map((txEffect)=>this.txs.get(txEffect.txHash.toString()));
225
296
  }
226
297
  getL1ToL2Messages(block) {
227
- return this.l1ToL2MessageSource.getL1ToL2Messages(BigInt(block.number));
298
+ return this.data.l1ToL2Messages[block.number];
228
299
  }
229
300
  async processTxs(publicProcessor, txs) {
230
301
  const { deadline } = this;
@@ -232,7 +303,8 @@ import * as crypto from 'node:crypto';
232
303
  deadline
233
304
  });
234
305
  if (failedTxs.length) {
235
- throw new Error(`Txs failed processing: ${failedTxs.map(({ tx, error })=>`${tx.getTxHash()} (${error})`).join(', ')}`);
306
+ const failedTxHashes = await Promise.all(failedTxs.map(({ tx })=>tx.getTxHash()));
307
+ throw new Error(`Txs failed processing: ${failedTxs.map(({ error }, index)=>`${failedTxHashes[index]} (${error})`).join(', ')}`);
236
308
  }
237
309
  if (processedTxs.length !== txs.length) {
238
310
  throw new Error(`Failed to process all txs: processed ${processedTxs.length} out of ${txs.length}`);
@@ -243,13 +315,14 @@ import * as crypto from 'node:crypto';
243
315
  _ts_decorate([
244
316
  trackSpan('EpochProvingJob.run', function() {
245
317
  return {
246
- [Attributes.EPOCH_NUMBER]: Number(this.epochNumber)
318
+ [Attributes.EPOCH_NUMBER]: Number(this.data.epochNumber)
247
319
  };
248
320
  })
249
321
  ], EpochProvingJob.prototype, "run", null);
250
322
  class HaltExecutionError extends Error {
323
+ state;
251
324
  constructor(state){
252
- super(`Halted execution due to state ${state}`);
325
+ super(`Halted execution due to state ${state}`), this.state = state;
253
326
  this.name = 'HaltExecutionError';
254
327
  }
255
328
  }
package/dest/metrics.d.ts CHANGED
@@ -1,12 +1,35 @@
1
+ import type { RollupContract } from '@aztec/ethereum';
2
+ import type { EthAddress } from '@aztec/foundation/eth-address';
1
3
  import type { L1PublishProofStats } from '@aztec/stdlib/stats';
2
- import { type Gauge, type Histogram, type TelemetryClient, type UpDownCounter } from '@aztec/telemetry-client';
3
- export declare class ProverNodeMetrics {
4
- readonly client: TelemetryClient;
4
+ import { type Gauge, type Histogram, type Meter, type TelemetryClient, type Tracer, type UpDownCounter } from '@aztec/telemetry-client';
5
+ export declare class ProverNodeJobMetrics {
6
+ private meter;
7
+ readonly tracer: Tracer;
5
8
  private logger;
6
9
  proverEpochExecutionDuration: Histogram;
7
10
  provingJobDuration: Histogram;
8
11
  provingJobBlocks: Gauge;
9
12
  provingJobTransactions: Gauge;
13
+ constructor(meter: Meter, tracer: Tracer, logger?: import("@aztec/foundation/log").Logger);
14
+ recordProvingJob(executionTimeMs: number, totalTimeMs: number, numBlocks: number, numTxs: number): void;
15
+ }
16
+ export declare class ProverNodeRewardsMetrics {
17
+ private meter;
18
+ private coinbase;
19
+ private rollup;
20
+ private logger;
21
+ private rewards;
22
+ private accumulatedRewards;
23
+ private prevEpoch;
24
+ private proofSubmissionEpochs;
25
+ constructor(meter: Meter, coinbase: EthAddress, rollup: RollupContract, logger?: import("@aztec/foundation/log").Logger);
26
+ start(): Promise<void>;
27
+ stop(): void;
28
+ private observe;
29
+ }
30
+ export declare class ProverNodePublisherMetrics {
31
+ readonly client: TelemetryClient;
32
+ private logger;
10
33
  gasPrice: Histogram;
11
34
  txCount: UpDownCounter;
12
35
  txDuration: Histogram;
@@ -15,11 +38,12 @@ export declare class ProverNodeMetrics {
15
38
  txCalldataGas: Histogram;
16
39
  txBlobDataGasUsed: Histogram;
17
40
  txBlobDataGasCost: Histogram;
41
+ txTotalFee: Histogram;
18
42
  private senderBalance;
43
+ private meter;
19
44
  constructor(client: TelemetryClient, name?: string, logger?: import("@aztec/foundation/log").Logger);
20
45
  recordFailedTx(): void;
21
46
  recordSubmitProof(durationMs: number, stats: L1PublishProofStats): void;
22
- recordProvingJob(executionTimeMs: number, totalTimeMs: number, numBlocks: number, numTxs: number): void;
23
47
  recordSenderBalance(wei: bigint, senderAddress: string): void;
24
48
  private recordTx;
25
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAEL,KAAK,KAAK,EACV,KAAK,SAAS,EAEd,KAAK,eAAe,EACpB,KAAK,aAAa,EAEnB,MAAM,yBAAyB,CAAC;AAIjC,qBAAa,iBAAiB;aAkBV,MAAM,EAAE,eAAe;IAEvC,OAAO,CAAC,MAAM;IAnBhB,4BAA4B,EAAE,SAAS,CAAC;IACxC,kBAAkB,EAAE,SAAS,CAAC;IAC9B,gBAAgB,EAAE,KAAK,CAAC;IACxB,sBAAsB,EAAE,KAAK,CAAC;IAE9B,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,EAAE,SAAS,CAAC;IACtB,KAAK,EAAE,SAAS,CAAC;IACjB,cAAc,EAAE,SAAS,CAAC;IAC1B,aAAa,EAAE,SAAS,CAAC;IACzB,iBAAiB,EAAE,SAAS,CAAC;IAC7B,iBAAiB,EAAE,SAAS,CAAC;IAE7B,OAAO,CAAC,aAAa,CAAQ;gBAGX,MAAM,EAAE,eAAe,EACvC,IAAI,SAAe,EACX,MAAM,yCAAgD;IA2EhE,cAAc;IAOd,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB;IAIzD,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAOhG,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;IAO7D,OAAO,CAAC,QAAQ;CA6BjB"}
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,KAAK,EAGV,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,KAAK,aAAa,EAEnB,MAAM,yBAAyB,CAAC;AAIjC,qBAAa,oBAAoB;IAO7B,OAAO,CAAC,KAAK;aACG,MAAM,EAAE,MAAM;IAC9B,OAAO,CAAC,MAAM;IARhB,4BAA4B,EAAE,SAAS,CAAC;IACxC,kBAAkB,EAAE,SAAS,CAAC;IAC9B,gBAAgB,EAAE,KAAK,CAAC;IACxB,sBAAsB,EAAE,KAAK,CAAC;gBAGpB,KAAK,EAAE,KAAK,EACJ,MAAM,EAAE,MAAM,EACtB,MAAM,yCAAgD;IAsBzD,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAMxG;AAED,qBAAa,wBAAwB;IAOjC,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IAThB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,kBAAkB,CAAgB;IAC1C,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,qBAAqB,CAAK;gBAGxB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,UAAU,EACpB,MAAM,EAAE,cAAc,EACtB,MAAM,yCAAgD;IAanD,KAAK;IAMX,IAAI;IAIX,OAAO,CAAC,OAAO,CAwBb;CACH;AAED,qBAAa,0BAA0B;aAenB,MAAM,EAAE,eAAe;IAEvC,OAAO,CAAC,MAAM;IAhBhB,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,EAAE,SAAS,CAAC;IACtB,KAAK,EAAE,SAAS,CAAC;IACjB,cAAc,EAAE,SAAS,CAAC;IAC1B,aAAa,EAAE,SAAS,CAAC;IACzB,iBAAiB,EAAE,SAAS,CAAC;IAC7B,iBAAiB,EAAE,SAAS,CAAC;IAC7B,UAAU,EAAE,SAAS,CAAC;IAEtB,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,KAAK,CAAQ;gBAGH,MAAM,EAAE,eAAe,EACvC,IAAI,SAAe,EACX,MAAM,yCAAgD;IAoEhE,cAAc;IAOd,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB;IAIzD,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;IAO7D,OAAO,CAAC,QAAQ;CAuCjB"}
package/dest/metrics.js CHANGED
@@ -1,83 +1,187 @@
1
1
  import { createLogger } from '@aztec/foundation/log';
2
2
  import { Attributes, Metrics, ValueType } from '@aztec/telemetry-client';
3
- import { formatEther } from 'viem';
4
- export class ProverNodeMetrics {
5
- client;
3
+ import { formatEther, formatUnits } from 'viem';
4
+ export class ProverNodeJobMetrics {
5
+ meter;
6
+ tracer;
6
7
  logger;
7
8
  proverEpochExecutionDuration;
8
9
  provingJobDuration;
9
10
  provingJobBlocks;
10
11
  provingJobTransactions;
11
- gasPrice;
12
- txCount;
13
- txDuration;
14
- txGas;
15
- txCalldataSize;
16
- txCalldataGas;
17
- txBlobDataGasUsed;
18
- txBlobDataGasCost;
19
- senderBalance;
20
- constructor(client, name = 'ProverNode', logger = createLogger('prover-node:publisher:metrics')){
21
- this.client = client;
12
+ constructor(meter, tracer, logger = createLogger('prover-node:publisher:metrics')){
13
+ this.meter = meter;
14
+ this.tracer = tracer;
22
15
  this.logger = logger;
23
- const meter = client.getMeter(name);
24
- this.proverEpochExecutionDuration = meter.createHistogram(Metrics.PROVER_NODE_EXECUTION_DURATION, {
16
+ this.proverEpochExecutionDuration = this.meter.createHistogram(Metrics.PROVER_NODE_EXECUTION_DURATION, {
25
17
  description: 'Duration of execution of an epoch by the prover',
26
18
  unit: 'ms',
27
19
  valueType: ValueType.INT
28
20
  });
29
- this.provingJobDuration = meter.createHistogram(Metrics.PROVER_NODE_JOB_DURATION, {
21
+ this.provingJobDuration = this.meter.createHistogram(Metrics.PROVER_NODE_JOB_DURATION, {
30
22
  description: 'Duration of proving job',
31
23
  unit: 's',
32
24
  valueType: ValueType.DOUBLE
33
25
  });
34
- this.provingJobBlocks = meter.createGauge(Metrics.PROVER_NODE_JOB_BLOCKS, {
26
+ this.provingJobBlocks = this.meter.createGauge(Metrics.PROVER_NODE_JOB_BLOCKS, {
35
27
  description: 'Number of blocks in a proven epoch',
36
28
  valueType: ValueType.INT
37
29
  });
38
- this.provingJobTransactions = meter.createGauge(Metrics.PROVER_NODE_JOB_TRANSACTIONS, {
30
+ this.provingJobTransactions = this.meter.createGauge(Metrics.PROVER_NODE_JOB_TRANSACTIONS, {
39
31
  description: 'Number of transactions in a proven epoch',
40
32
  valueType: ValueType.INT
41
33
  });
42
- this.gasPrice = meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE, {
34
+ }
35
+ recordProvingJob(executionTimeMs, totalTimeMs, numBlocks, numTxs) {
36
+ this.proverEpochExecutionDuration.record(Math.ceil(executionTimeMs));
37
+ this.provingJobDuration.record(totalTimeMs / 1000);
38
+ this.provingJobBlocks.record(Math.floor(numBlocks));
39
+ this.provingJobTransactions.record(Math.floor(numTxs));
40
+ }
41
+ }
42
+ export class ProverNodeRewardsMetrics {
43
+ meter;
44
+ coinbase;
45
+ rollup;
46
+ logger;
47
+ rewards;
48
+ accumulatedRewards;
49
+ prevEpoch;
50
+ proofSubmissionEpochs;
51
+ constructor(meter, coinbase, rollup, logger = createLogger('prover-node:publisher:metrics')){
52
+ this.meter = meter;
53
+ this.coinbase = coinbase;
54
+ this.rollup = rollup;
55
+ this.logger = logger;
56
+ this.prevEpoch = -1n;
57
+ this.proofSubmissionEpochs = 0;
58
+ this.observe = async (observer)=>{
59
+ const epoch = await this.rollup.getCurrentEpochNumber();
60
+ if (epoch > this.proofSubmissionEpochs) {
61
+ // look at the prev epoch so that we get an accurate value, after proof submission window has closed
62
+ // For example, if proof submission window is 1 epoch, and we are in epoch 2, we should be looking at epoch 0.
63
+ // Similarly, if the proof submission window is 0, and we are in epoch 1, we should be looking at epoch 0.
64
+ const closedEpoch = epoch - BigInt(this.proofSubmissionEpochs) - 1n;
65
+ const rewards = await this.rollup.getSpecificProverRewardsForEpoch(closedEpoch, this.coinbase);
66
+ const fmt = parseFloat(formatUnits(rewards, 18));
67
+ observer.observe(this.rewards, fmt, {
68
+ [Attributes.COINBASE]: this.coinbase.toString()
69
+ });
70
+ // only accumulate once per epoch
71
+ if (closedEpoch > this.prevEpoch) {
72
+ this.prevEpoch = closedEpoch;
73
+ this.accumulatedRewards.add(fmt, {
74
+ [Attributes.COINBASE]: this.coinbase.toString()
75
+ });
76
+ }
77
+ }
78
+ };
79
+ this.rewards = this.meter.createObservableGauge(Metrics.PROVER_NODE_REWARDS_PER_EPOCH, {
80
+ valueType: ValueType.DOUBLE,
81
+ description: 'The rewards earned'
82
+ });
83
+ this.accumulatedRewards = this.meter.createUpDownCounter(Metrics.PROVER_NODE_REWARDS_TOTAL, {
84
+ valueType: ValueType.DOUBLE,
85
+ description: 'The rewards earned (total)'
86
+ });
87
+ }
88
+ async start() {
89
+ const proofSubmissionEpochs = await this.rollup.getProofSubmissionEpochs();
90
+ this.proofSubmissionEpochs = Number(proofSubmissionEpochs);
91
+ this.meter.addBatchObservableCallback(this.observe, [
92
+ this.rewards
93
+ ]);
94
+ }
95
+ stop() {
96
+ this.meter.removeBatchObservableCallback(this.observe, [
97
+ this.rewards
98
+ ]);
99
+ }
100
+ observe;
101
+ }
102
+ export class ProverNodePublisherMetrics {
103
+ client;
104
+ logger;
105
+ gasPrice;
106
+ txCount;
107
+ txDuration;
108
+ txGas;
109
+ txCalldataSize;
110
+ txCalldataGas;
111
+ txBlobDataGasUsed;
112
+ txBlobDataGasCost;
113
+ txTotalFee;
114
+ senderBalance;
115
+ meter;
116
+ constructor(client, name = 'ProverNode', logger = createLogger('prover-node:publisher:metrics')){
117
+ this.client = client;
118
+ this.logger = logger;
119
+ this.meter = client.getMeter(name);
120
+ this.gasPrice = this.meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE, {
43
121
  description: 'The gas price used for transactions',
44
122
  unit: 'gwei',
45
123
  valueType: ValueType.DOUBLE
46
124
  });
47
- this.txCount = meter.createUpDownCounter(Metrics.L1_PUBLISHER_TX_COUNT, {
125
+ this.txCount = this.meter.createUpDownCounter(Metrics.L1_PUBLISHER_TX_COUNT, {
48
126
  description: 'The number of transactions processed'
49
127
  });
50
- this.txDuration = meter.createHistogram(Metrics.L1_PUBLISHER_TX_DURATION, {
128
+ this.txDuration = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_DURATION, {
51
129
  description: 'The duration of transaction processing',
52
130
  unit: 'ms',
53
131
  valueType: ValueType.INT
54
132
  });
55
- this.txGas = meter.createHistogram(Metrics.L1_PUBLISHER_TX_GAS, {
133
+ this.txGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_GAS, {
56
134
  description: 'The gas consumed by transactions',
57
135
  unit: 'gas',
58
136
  valueType: ValueType.INT
59
137
  });
60
- this.txCalldataSize = meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_SIZE, {
138
+ this.txCalldataSize = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_SIZE, {
61
139
  description: 'The size of the calldata in transactions',
62
140
  unit: 'By',
63
141
  valueType: ValueType.INT
64
142
  });
65
- this.txCalldataGas = meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_GAS, {
143
+ this.txCalldataGas = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_GAS, {
66
144
  description: 'The gas consumed by the calldata in transactions',
67
145
  unit: 'gas',
68
146
  valueType: ValueType.INT
69
147
  });
70
- this.txBlobDataGasUsed = meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_USED, {
148
+ this.txBlobDataGasUsed = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_USED, {
71
149
  description: 'The amount of blob gas used in transactions',
72
150
  unit: 'gas',
73
151
  valueType: ValueType.INT
74
152
  });
75
- this.txBlobDataGasCost = meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_COST, {
153
+ this.txBlobDataGasCost = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_COST, {
76
154
  description: 'The gas cost of blobs in transactions',
77
155
  unit: 'gwei',
78
156
  valueType: ValueType.INT
79
157
  });
80
- this.senderBalance = meter.createGauge(Metrics.L1_PUBLISHER_BALANCE, {
158
+ this.txTotalFee = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_TOTAL_FEE, {
159
+ description: 'How much L1 tx costs',
160
+ unit: 'gwei',
161
+ valueType: ValueType.DOUBLE,
162
+ advice: {
163
+ explicitBucketBoundaries: [
164
+ 0.001,
165
+ 0.002,
166
+ 0.004,
167
+ 0.008,
168
+ 0.01,
169
+ 0.02,
170
+ 0.04,
171
+ 0.08,
172
+ 0.1,
173
+ 0.2,
174
+ 0.4,
175
+ 0.8,
176
+ 1,
177
+ 1.2,
178
+ 1.4,
179
+ 1.8,
180
+ 2
181
+ ]
182
+ }
183
+ });
184
+ this.senderBalance = this.meter.createGauge(Metrics.L1_PUBLISHER_BALANCE, {
81
185
  unit: 'eth',
82
186
  description: 'The balance of the sender address',
83
187
  valueType: ValueType.DOUBLE
@@ -92,12 +196,6 @@ export class ProverNodeMetrics {
92
196
  recordSubmitProof(durationMs, stats) {
93
197
  this.recordTx(durationMs, stats);
94
198
  }
95
- recordProvingJob(executionTimeMs, totalTimeMs, numBlocks, numTxs) {
96
- this.proverEpochExecutionDuration.record(Math.ceil(executionTimeMs));
97
- this.provingJobDuration.record(totalTimeMs / 1000);
98
- this.provingJobBlocks.record(Math.floor(numBlocks));
99
- this.provingJobTransactions.record(Math.floor(numTxs));
100
- }
101
199
  recordSenderBalance(wei, senderAddress) {
102
200
  const eth = parseFloat(formatEther(wei, 'wei'));
103
201
  this.senderBalance.record(eth, {
@@ -122,7 +220,15 @@ export class ProverNodeMetrics {
122
220
  this.txBlobDataGasUsed.record(Number(stats.blobGasUsed), attributes);
123
221
  try {
124
222
  this.gasPrice.record(parseInt(formatEther(stats.gasPrice, 'gwei'), 10));
125
- } catch (e) {
223
+ } catch {
224
+ // ignore
225
+ }
226
+ const executionFee = stats.gasUsed * stats.gasPrice;
227
+ const blobFee = stats.blobGasUsed * stats.blobDataGas;
228
+ const totalFee = executionFee + blobFee;
229
+ try {
230
+ this.txTotalFee.record(parseFloat(formatEther(totalFee)));
231
+ } catch {
126
232
  // ignore
127
233
  }
128
234
  }
@@ -2,7 +2,7 @@ import type { L2BlockSource } from '@aztec/stdlib/block';
2
2
  import { type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
3
3
  import { type TelemetryClient, type Traceable, type Tracer } from '@aztec/telemetry-client';
4
4
  export interface EpochMonitorHandler {
5
- handleEpochReadyToProve(epochNumber: bigint): Promise<void>;
5
+ handleEpochReadyToProve(epochNumber: bigint): Promise<boolean>;
6
6
  }
7
7
  /**
8
8
  * Fires an event when a new epoch ready to prove is detected.
@@ -26,9 +26,11 @@ export declare class EpochMonitor implements Traceable {
26
26
  private latestEpochNumber;
27
27
  constructor(l2BlockSource: L2BlockSource, l1Constants: Pick<L1RollupConstants, 'epochDuration'>, options: {
28
28
  pollingIntervalMs: number;
29
+ provingDelayMs?: number;
29
30
  }, telemetry?: TelemetryClient);
30
31
  static create(l2BlockSource: L2BlockSource, options: {
31
32
  pollingIntervalMs: number;
33
+ provingDelayMs?: number;
32
34
  }, telemetry?: TelemetryClient): Promise<EpochMonitor>;
33
35
  start(handler: EpochMonitorHandler): void;
34
36
  /** Exposed for testing */
@@ -1 +1 @@
1
- {"version":3,"file":"epoch-monitor.d.ts","sourceRoot":"","sources":["../../src/monitors/epoch-monitor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,KAAK,iBAAiB,EAAkB,MAAM,6BAA6B,CAAC;AACrF,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,MAAM,EAGZ,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,mBAAmB;IAClC,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAED;;;;;;;;;;GAUG;AACH,qBAAa,YAAa,YAAW,SAAS;IAS1C,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,OAAO;IAVjB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,GAAG,CAA6C;IACxD,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,iBAAiB,CAAqB;gBAG3B,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,IAAI,CAAC,iBAAiB,EAAE,eAAe,CAAC,EAC9D,OAAO,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAA;KAAE,EAC9C,SAAS,GAAE,eAAsC;WAM/B,MAAM,CACxB,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAA;KAAE,EACtC,SAAS,GAAE,eAAsC,GAChD,OAAO,CAAC,YAAY,CAAC;IAKjB,KAAK,CAAC,OAAO,EAAE,mBAAmB;IAMzC,0BAA0B;IACnB,UAAU,CAAC,OAAO,EAAE,mBAAmB;IAIjC,IAAI;IAMJ,IAAI;YAsBH,qBAAqB;CAYpC"}
1
+ {"version":3,"file":"epoch-monitor.d.ts","sourceRoot":"","sources":["../../src/monitors/epoch-monitor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,KAAK,iBAAiB,EAAkB,MAAM,6BAA6B,CAAC;AACrF,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,MAAM,EAGZ,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,mBAAmB;IAClC,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChE;AAED;;;;;;;;;;GAUG;AACH,qBAAa,YAAa,YAAW,SAAS;IAS1C,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,OAAO;IAVjB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,GAAG,CAA6C;IACxD,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,iBAAiB,CAAqB;gBAG3B,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,IAAI,CAAC,iBAAiB,EAAE,eAAe,CAAC,EAC9D,OAAO,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,EACvE,SAAS,GAAE,eAAsC;WAS/B,MAAM,CACxB,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,EAC/D,SAAS,GAAE,eAAsC,GAChD,OAAO,CAAC,YAAY,CAAC;IAKjB,KAAK,CAAC,OAAO,EAAE,mBAAmB;IAMzC,0BAA0B;IACnB,UAAU,CAAC,OAAO,EAAE,mBAAmB;IAIjC,IAAI;IAMJ,IAAI;YA6BH,qBAAqB;CAYpC"}