@aztec/prover-node 0.85.0 → 0.86.0-nightly.20250425

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 (69) hide show
  1. package/dest/actions/download-epoch-proving-job.d.ts +15 -0
  2. package/dest/actions/download-epoch-proving-job.d.ts.map +1 -0
  3. package/dest/actions/download-epoch-proving-job.js +35 -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 +37 -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/config.d.ts +4 -4
  14. package/dest/config.d.ts.map +1 -1
  15. package/dest/config.js +12 -7
  16. package/dest/factory.d.ts +3 -2
  17. package/dest/factory.d.ts.map +1 -1
  18. package/dest/factory.js +13 -13
  19. package/dest/index.d.ts +1 -0
  20. package/dest/index.d.ts.map +1 -1
  21. package/dest/index.js +1 -0
  22. package/dest/job/epoch-proving-job-data.d.ts +17 -0
  23. package/dest/job/epoch-proving-job-data.d.ts.map +1 -0
  24. package/dest/job/epoch-proving-job-data.js +45 -0
  25. package/dest/job/epoch-proving-job.d.ts +9 -9
  26. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  27. package/dest/job/epoch-proving-job.js +38 -21
  28. package/dest/metrics.d.ts +27 -4
  29. package/dest/metrics.d.ts.map +1 -1
  30. package/dest/metrics.js +104 -36
  31. package/dest/monitors/epoch-monitor.d.ts +1 -1
  32. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  33. package/dest/monitors/epoch-monitor.js +7 -2
  34. package/dest/prover-coordination/combined-prover-coordination.d.ts +22 -0
  35. package/dest/prover-coordination/combined-prover-coordination.d.ts.map +1 -0
  36. package/dest/prover-coordination/combined-prover-coordination.js +136 -0
  37. package/dest/prover-coordination/config.d.ts +1 -1
  38. package/dest/prover-coordination/config.d.ts.map +1 -1
  39. package/dest/prover-coordination/config.js +5 -4
  40. package/dest/prover-coordination/factory.d.ts +5 -4
  41. package/dest/prover-coordination/factory.d.ts.map +1 -1
  42. package/dest/prover-coordination/factory.js +20 -14
  43. package/dest/prover-node-publisher.d.ts +1 -2
  44. package/dest/prover-node-publisher.d.ts.map +1 -1
  45. package/dest/prover-node-publisher.js +7 -13
  46. package/dest/prover-node.d.ts +26 -24
  47. package/dest/prover-node.d.ts.map +1 -1
  48. package/dest/prover-node.js +103 -51
  49. package/dest/test/index.d.ts +4 -2
  50. package/dest/test/index.d.ts.map +1 -1
  51. package/dest/test/index.js +1 -1
  52. package/package.json +20 -22
  53. package/src/actions/download-epoch-proving-job.ts +46 -0
  54. package/src/actions/index.ts +2 -0
  55. package/src/actions/rerun-epoch-proving-job.ts +59 -0
  56. package/src/actions/upload-epoch-proof-failure.ts +88 -0
  57. package/src/config.ts +16 -10
  58. package/src/factory.ts +31 -17
  59. package/src/index.ts +1 -0
  60. package/src/job/epoch-proving-job-data.ts +68 -0
  61. package/src/job/epoch-proving-job.ts +53 -23
  62. package/src/metrics.ts +111 -38
  63. package/src/monitors/epoch-monitor.ts +5 -3
  64. package/src/prover-coordination/combined-prover-coordination.ts +160 -0
  65. package/src/prover-coordination/config.ts +6 -5
  66. package/src/prover-coordination/factory.ts +36 -25
  67. package/src/prover-node-publisher.ts +9 -18
  68. package/src/prover-node.ts +151 -74
  69. package/src/test/index.ts +5 -2
@@ -1,12 +1,17 @@
1
- import { compact } from '@aztec/foundation/collection';
1
+ import type { Archiver } from '@aztec/archiver';
2
+ import type { ViemPublicClient } from '@aztec/ethereum';
3
+ import { assertRequired, compact, pick, sum } from '@aztec/foundation/collection';
2
4
  import { memoize } from '@aztec/foundation/decorators';
5
+ import { EthAddress } from '@aztec/foundation/eth-address';
6
+ import type { Fr } from '@aztec/foundation/fields';
3
7
  import { createLogger } from '@aztec/foundation/log';
4
8
  import { RunningPromise } from '@aztec/foundation/running-promise';
5
9
  import { DateProvider } from '@aztec/foundation/timer';
6
10
  import type { Maybe } from '@aztec/foundation/types';
7
- import type { P2P } from '@aztec/p2p';
11
+ import type { DataStoreConfig } from '@aztec/kv-store/config';
8
12
  import { PublicProcessorFactory } from '@aztec/simulator/server';
9
13
  import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
14
+ import type { ChainConfig } from '@aztec/stdlib/config';
10
15
  import type { ContractDataSource } from '@aztec/stdlib/contract';
11
16
  import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
12
17
  import {
@@ -20,8 +25,7 @@ import {
20
25
  tryStop,
21
26
  } from '@aztec/stdlib/interfaces/server';
22
27
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
23
- import type { P2PClientType } from '@aztec/stdlib/p2p';
24
- import type { Tx, TxHash } from '@aztec/stdlib/tx';
28
+ import type { TxHash } from '@aztec/stdlib/tx';
25
29
  import {
26
30
  Attributes,
27
31
  L1Metrics,
@@ -32,24 +36,20 @@ import {
32
36
  trackSpan,
33
37
  } from '@aztec/telemetry-client';
34
38
 
39
+ import { uploadEpochProofFailure } from './actions/upload-epoch-proof-failure.js';
40
+ import type { SpecificProverNodeConfig } from './config.js';
41
+ import type { EpochProvingJobData } from './job/epoch-proving-job-data.js';
35
42
  import { EpochProvingJob, type EpochProvingJobState } from './job/epoch-proving-job.js';
36
- import { ProverNodeMetrics } from './metrics.js';
43
+ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
37
44
  import type { EpochMonitor, EpochMonitorHandler } from './monitors/epoch-monitor.js';
38
45
  import type { ProverNodePublisher } from './prover-node-publisher.js';
39
46
 
40
- export type ProverNodeOptions = {
41
- pollingIntervalMs: number;
42
- maxPendingJobs: number;
43
- maxParallelBlocksPerEpoch: number;
44
- txGatheringTimeoutMs: number;
45
- txGatheringIntervalMs: number;
46
- txGatheringMaxParallelRequests: number;
47
- };
47
+ type ProverNodeOptions = SpecificProverNodeConfig & Partial<DataStoreOptions>;
48
+ type DataStoreOptions = Pick<DataStoreConfig, 'dataDirectory'> & Pick<ChainConfig, 'l1ChainId' | 'rollupVersion'>;
48
49
 
49
50
  /**
50
- * An Aztec Prover Node is a standalone process that monitors the unfinalised chain on L1 for unproven blocks,
51
- * submits bids for proving them, and monitors if they are accepted. If so, the prover node fetches the txs
52
- * from a tx source in the p2p network or an external node, re-executes their public functions, creates a rollup
51
+ * An Aztec Prover Node is a standalone process that monitors the unfinalised chain on L1 for unproven epochs,
52
+ * fetches their txs from the p2p network or external nodes, re-executes their public functions, creates a rollup
53
53
  * proof for the epoch, and submits it to L1.
54
54
  */
55
55
  export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable {
@@ -57,8 +57,9 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
57
57
  private dateProvider = new DateProvider();
58
58
 
59
59
  private jobs: Map<string, EpochProvingJob> = new Map();
60
- private options: ProverNodeOptions;
61
- private metrics: ProverNodeMetrics;
60
+ private config: ProverNodeOptions;
61
+ private jobMetrics: ProverNodeJobMetrics;
62
+ private rewardsMetrics: ProverNodeRewardsMetrics;
62
63
  private l1Metrics: L1Metrics;
63
64
 
64
65
  private txFetcher: RunningPromise;
@@ -73,28 +74,42 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
73
74
  protected readonly l1ToL2MessageSource: L1ToL2MessageSource,
74
75
  protected readonly contractDataSource: ContractDataSource,
75
76
  protected readonly worldState: WorldStateSynchronizer,
76
- protected readonly coordination: ProverCoordination & Maybe<Service>,
77
+ protected readonly coordination: ProverCoordination,
77
78
  protected readonly epochsMonitor: EpochMonitor,
78
- options: Partial<ProverNodeOptions> = {},
79
+ config: Partial<ProverNodeOptions> = {},
79
80
  protected readonly telemetryClient: TelemetryClient = getTelemetryClient(),
80
81
  ) {
81
- this.l1Metrics = new L1Metrics(telemetryClient.getMeter('ProverNodeL1Metrics'), publisher.l1TxUtils.publicClient, [
82
- publisher.getSenderAddress(),
83
- ]);
84
-
85
- this.options = {
86
- pollingIntervalMs: 1_000,
87
- maxPendingJobs: 100,
88
- maxParallelBlocksPerEpoch: 32,
89
- txGatheringTimeoutMs: 60_000,
82
+ this.l1Metrics = new L1Metrics(
83
+ telemetryClient.getMeter('ProverNodeL1Metrics'),
84
+ publisher.l1TxUtils.client as unknown as ViemPublicClient,
85
+ [publisher.getSenderAddress()],
86
+ );
87
+
88
+ this.config = {
89
+ proverNodePollingIntervalMs: 1_000,
90
+ proverNodeMaxPendingJobs: 100,
91
+ proverNodeMaxParallelBlocksPerEpoch: 32,
90
92
  txGatheringIntervalMs: 1_000,
91
- txGatheringMaxParallelRequests: 100,
92
- ...compact(options),
93
+ txGatheringBatchSize: 10,
94
+ txGatheringMaxParallelRequestsPerNode: 100,
95
+ proverNodeFailedEpochStore: undefined,
96
+ ...compact(config),
93
97
  };
94
98
 
95
- this.metrics = new ProverNodeMetrics(telemetryClient, 'ProverNode');
99
+ this.validateConfig();
100
+
101
+ const meter = telemetryClient.getMeter('ProverNode');
96
102
  this.tracer = telemetryClient.getTracer('ProverNode');
97
- this.txFetcher = new RunningPromise(() => this.checkForTxs(), this.log, this.options.txGatheringIntervalMs);
103
+
104
+ this.jobMetrics = new ProverNodeJobMetrics(meter, telemetryClient.getTracer('EpochProvingJob'));
105
+
106
+ this.rewardsMetrics = new ProverNodeRewardsMetrics(
107
+ meter,
108
+ EthAddress.fromField(this.prover.getProverId()),
109
+ this.publisher.getRollupContract(),
110
+ );
111
+
112
+ this.txFetcher = new RunningPromise(() => this.checkForTxs(), this.log, this.config.txGatheringIntervalMs);
98
113
  }
99
114
 
100
115
  public getProverId() {
@@ -102,18 +117,15 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
102
117
  }
103
118
 
104
119
  public getP2P() {
105
- const asP2PClient = this.coordination as P2P<P2PClientType.Prover>;
106
- if (typeof asP2PClient.isP2PClient === 'function' && asP2PClient.isP2PClient()) {
107
- return asP2PClient;
108
- }
109
- return undefined;
120
+ return this.coordination.getP2PClient();
110
121
  }
111
122
 
112
123
  /**
113
124
  * Handles an epoch being completed by starting a proof for it if there are no active jobs for it.
114
125
  * @param epochNumber - The epoch number that was just completed.
126
+ * @returns false if there is an error, true otherwise
115
127
  */
116
- async handleEpochReadyToProve(epochNumber: bigint): Promise<void> {
128
+ async handleEpochReadyToProve(epochNumber: bigint): Promise<boolean> {
117
129
  try {
118
130
  this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
119
131
  jobs: Array.from(this.jobs.values()).map(job => `${job.getEpochNumber()}:${job.getId()}`),
@@ -123,15 +135,17 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
123
135
  this.log.warn(`Not starting proof for ${epochNumber} since there are active jobs for the epoch`, {
124
136
  activeJobs: activeJobs.map(job => job.uuid),
125
137
  });
126
- return;
138
+ return true;
127
139
  }
128
140
  await this.startProof(epochNumber);
141
+ return true;
129
142
  } catch (err) {
130
143
  if (err instanceof EmptyEpochError) {
131
144
  this.log.info(`Not starting proof for ${epochNumber} since no blocks were found`);
132
145
  } else {
133
146
  this.log.error(`Error handling epoch completed`, err);
134
147
  }
148
+ return false;
135
149
  }
136
150
  }
137
151
 
@@ -139,11 +153,12 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
139
153
  * Starts the prover node so it periodically checks for unproven epochs in the unfinalised chain from L1 and
140
154
  * starts proving jobs for them.
141
155
  */
142
- start() {
156
+ async start() {
143
157
  this.txFetcher.start();
144
158
  this.epochsMonitor.start(this);
145
159
  this.l1Metrics.start();
146
- this.log.info(`Started Prover Node with prover id ${this.prover.getProverId().toString()}`, this.options);
160
+ await this.rewardsMetrics.start();
161
+ this.log.info(`Started Prover Node with prover id ${this.prover.getProverId().toString()}`, this.config);
147
162
  }
148
163
 
149
164
  /**
@@ -160,13 +175,15 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
160
175
  await this.worldState.stop();
161
176
  await tryStop(this.coordination);
162
177
  this.l1Metrics.stop();
178
+ this.rewardsMetrics.stop();
163
179
  await this.telemetryClient.stop();
164
180
  this.log.info('Stopped ProverNode');
165
181
  }
166
182
 
167
183
  /** Returns world state status. */
168
- public getWorldStateSyncStatus(): Promise<WorldStateSyncStatus> {
169
- return this.worldState.status().then(s => s.syncSummary);
184
+ public async getWorldStateSyncStatus(): Promise<WorldStateSyncStatus> {
185
+ const { syncSummary } = await this.worldState.status();
186
+ return syncSummary;
170
187
  }
171
188
 
172
189
  /** Returns archiver status. */
@@ -183,23 +200,44 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
183
200
  }
184
201
 
185
202
  private async runJob(job: EpochProvingJob) {
186
- const ctx = { id: job.getId(), epochNumber: job.getEpochNumber() };
203
+ const epochNumber = job.getEpochNumber();
204
+ const ctx = { id: job.getId(), epochNumber, state: undefined as EpochProvingJobState | undefined };
205
+
187
206
  try {
188
207
  await job.run();
189
208
  const state = job.getState();
209
+ ctx.state = state;
210
+
190
211
  if (state === 'reorg') {
191
- this.log.warn(`Running new job for epoch ${job.getEpochNumber()} due to reorg`, ctx);
192
- await this.createProvingJob(job.getEpochNumber());
212
+ this.log.warn(`Running new job for epoch ${epochNumber} due to reorg`, ctx);
213
+ await this.createProvingJob(epochNumber);
214
+ } else if (state === 'failed') {
215
+ this.log.error(`Job for ${epochNumber} exited with state ${state}`, ctx);
216
+ await this.tryUploadEpochFailure(job);
193
217
  } else {
194
- this.log.verbose(`Job for ${job.getEpochNumber()} exited with state ${state}`, ctx);
218
+ this.log.verbose(`Job for ${epochNumber} exited with state ${state}`, ctx);
195
219
  }
196
220
  } catch (err) {
197
- this.log.error(`Error proving epoch ${job.getEpochNumber()}`, err, ctx);
221
+ this.log.error(`Error proving epoch ${epochNumber}`, err, ctx);
198
222
  } finally {
199
223
  this.jobs.delete(job.getId());
200
224
  }
201
225
  }
202
226
 
227
+ protected async tryUploadEpochFailure(job: EpochProvingJob) {
228
+ if (this.config.proverNodeFailedEpochStore) {
229
+ return await uploadEpochProofFailure(
230
+ this.config.proverNodeFailedEpochStore,
231
+ job.getId(),
232
+ job.getProvingData(),
233
+ this.l2BlockSource as Archiver,
234
+ this.worldState,
235
+ assertRequired(pick(this.config, 'l1ChainId', 'rollupVersion', 'dataDirectory')),
236
+ this.log,
237
+ );
238
+ }
239
+ }
240
+
203
241
  /**
204
242
  * Returns the prover instance.
205
243
  */
@@ -229,36 +267,38 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
229
267
  }
230
268
 
231
269
  private checkMaximumPendingJobs() {
232
- const { maxPendingJobs } = this.options;
233
- return maxPendingJobs === 0 || this.jobs.size < maxPendingJobs;
270
+ const { proverNodeMaxPendingJobs: maxPendingJobs } = this.config;
271
+ if (maxPendingJobs > 0 && this.jobs.size >= maxPendingJobs) {
272
+ throw new Error(`Maximum pending proving jobs ${maxPendingJobs} reached. Cannot create new job.`);
273
+ }
234
274
  }
235
275
 
236
276
  @trackSpan('ProverNode.createProvingJob', epochNumber => ({ [Attributes.EPOCH_NUMBER]: Number(epochNumber) }))
237
277
  private async createProvingJob(epochNumber: bigint) {
238
- if (!this.checkMaximumPendingJobs()) {
239
- throw new Error(`Maximum pending proving jobs ${this.options.maxPendingJobs} reached. Cannot create new job.`);
240
- }
278
+ this.checkMaximumPendingJobs();
241
279
 
242
- // Gather blocks for this epoch
243
- const { blocks, txs } = await this.gatherEpochData(epochNumber);
280
+ // Gather all data for this epoch
281
+ const epochData = await this.gatherEpochData(epochNumber);
244
282
 
245
- const fromBlock = blocks[0].number;
246
- const toBlock = blocks.at(-1)!.number;
283
+ const fromBlock = epochData.blocks[0].number;
284
+ const toBlock = epochData.blocks.at(-1)!.number;
285
+ this.log.verbose(`Creating proving job for epoch ${epochNumber} for block range ${fromBlock} to ${toBlock}`);
247
286
 
248
287
  // Fast forward world state to right before the target block and get a fork
249
- this.log.verbose(`Creating proving job for epoch ${epochNumber} for block range ${fromBlock} to ${toBlock}`);
250
288
  await this.worldState.syncImmediate(toBlock);
251
289
 
252
- // Create a processor using the forked world state
290
+ // Create a processor factory
253
291
  const publicProcessorFactory = new PublicProcessorFactory(
254
292
  this.contractDataSource,
255
293
  this.dateProvider,
256
294
  this.telemetryClient,
257
295
  );
258
296
 
297
+ // Set deadline for this job to run. It will abort if it takes too long.
259
298
  const deadlineTs = getProofSubmissionDeadlineTimestamp(epochNumber, await this.getL1Constants());
260
299
  const deadline = new Date(Number(deadlineTs) * 1000);
261
- const job = this.doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory);
300
+
301
+ const job = this.doCreateEpochProvingJob(epochData, deadline, publicProcessorFactory);
262
302
  this.jobs.set(job.getId(), job);
263
303
  return job;
264
304
  }
@@ -279,18 +319,19 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
279
319
  }
280
320
  const txHashes = block.body.txEffects.map(tx => tx.txHash);
281
321
  this.log.verbose(`Fetching ${txHashes.length} tx hashes for block number ${blockNumber} from coordination`);
282
- await this.coordination.getTxsByHash(txHashes); // This stores the txs in the tx pool, no need to persist them here
322
+ await this.coordination.gatherTxs(txHashes); // This stores the txs in the tx pool, no need to persist them here
283
323
  this.lastBlockNumber = blockNumber;
284
324
  }
285
325
  }
286
326
 
287
327
  @trackSpan('ProverNode.gatherEpochData', epochNumber => ({ [Attributes.EPOCH_NUMBER]: Number(epochNumber) }))
288
- private async gatherEpochData(epochNumber: bigint) {
289
- // Gather blocks for this epoch and their txs
328
+ private async gatherEpochData(epochNumber: bigint): Promise<EpochProvingJobData> {
290
329
  const blocks = await this.gatherBlocks(epochNumber);
291
330
  const txs = await this.gatherTxs(epochNumber, blocks);
331
+ const l1ToL2Messages = await this.gatherMessages(epochNumber, blocks);
332
+ const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, blocks[0]);
292
333
 
293
- return { blocks, txs };
334
+ return { blocks, txs, l1ToL2Messages, epochNumber, previousBlockHeader };
294
335
  }
295
336
 
296
337
  private async gatherBlocks(epochNumber: bigint) {
@@ -318,27 +359,48 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
318
359
  throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxHashes}`);
319
360
  }
320
361
 
362
+ private async gatherMessages(epochNumber: bigint, blocks: L2Block[]) {
363
+ const messages = await Promise.all(blocks.map(b => this.l1ToL2MessageSource.getL1ToL2Messages(BigInt(b.number))));
364
+ const messageCount = sum(messages.map(m => m.length));
365
+ this.log.verbose(`Gathered all ${messageCount} messages for epoch ${epochNumber}`, { epochNumber });
366
+ const messagesByBlock: Record<number, Fr[]> = {};
367
+ for (let i = 0; i < blocks.length; i++) {
368
+ messagesByBlock[blocks[i].number] = messages[i];
369
+ }
370
+ return messagesByBlock;
371
+ }
372
+
373
+ private async gatherPreviousBlockHeader(epochNumber: bigint, initialBlock: L2Block) {
374
+ const previousBlockNumber = initialBlock.number - 1;
375
+ const header = await (previousBlockNumber === 0
376
+ ? this.worldState.getCommitted().getInitialHeader()
377
+ : this.l2BlockSource.getBlockHeader(previousBlockNumber));
378
+
379
+ if (!header) {
380
+ throw new Error(`Previous block header ${initialBlock.number} not found for proving epoch ${epochNumber}`);
381
+ }
382
+
383
+ this.log.verbose(`Gathered previous block header ${header.getBlockNumber()} for epoch ${epochNumber}`);
384
+ return header;
385
+ }
386
+
321
387
  /** Extracted for testing purposes. */
322
388
  protected doCreateEpochProvingJob(
323
- epochNumber: bigint,
389
+ data: EpochProvingJobData,
324
390
  deadline: Date | undefined,
325
- blocks: L2Block[],
326
- txs: Tx[],
327
391
  publicProcessorFactory: PublicProcessorFactory,
328
392
  ) {
393
+ const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit } = this.config;
329
394
  return new EpochProvingJob(
395
+ data,
330
396
  this.worldState,
331
- epochNumber,
332
- blocks,
333
- txs,
334
397
  this.prover.createEpochProver(),
335
398
  publicProcessorFactory,
336
399
  this.publisher,
337
400
  this.l2BlockSource,
338
- this.l1ToL2MessageSource,
339
- this.metrics,
401
+ this.jobMetrics,
340
402
  deadline,
341
- { parallelBlockLimit: this.options.maxParallelBlocksPerEpoch },
403
+ { parallelBlockLimit },
342
404
  );
343
405
  }
344
406
 
@@ -346,6 +408,21 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
346
408
  protected async triggerMonitors() {
347
409
  await this.epochsMonitor.work();
348
410
  }
411
+
412
+ private validateConfig() {
413
+ if (
414
+ this.config.proverNodeFailedEpochStore &&
415
+ (!this.config.dataDirectory || !this.config.l1ChainId || !this.config.rollupVersion)
416
+ ) {
417
+ this.log.warn(
418
+ `Invalid prover-node config (missing dataDirectory, l1ChainId, or rollupVersion)`,
419
+ pick(this.config, 'proverNodeFailedEpochStore', 'dataDirectory', 'l1ChainId', 'rollupVersion'),
420
+ );
421
+ throw new Error(
422
+ 'All of dataDirectory, l1ChainId, and rollupVersion are required if proverNodeFailedEpochStore is set.',
423
+ );
424
+ }
425
+ }
349
426
  }
350
427
 
351
428
  class EmptyEpochError extends Error {
package/src/test/index.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  import type { EpochProverManager } from '@aztec/stdlib/interfaces/server';
2
2
 
3
+ import type { EpochProvingJob } from '../job/epoch-proving-job.js';
3
4
  import type { ProverNodePublisher } from '../prover-node-publisher.js';
4
5
  import { ProverNode } from '../prover-node.js';
5
6
 
6
- class TestProverNode_ extends ProverNode {
7
+ abstract class TestProverNodeClass extends ProverNode {
7
8
  public declare prover: EpochProverManager;
8
9
  public declare publisher: ProverNodePublisher;
10
+
11
+ public abstract override tryUploadEpochFailure(job: EpochProvingJob): Promise<string | undefined>;
9
12
  }
10
13
 
11
- export type TestProverNode = TestProverNode_;
14
+ export type TestProverNode = TestProverNodeClass;