@aztec/prover-node 0.85.0-alpha-testnet.2 → 0.85.0-alpha-testnet.4

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