@aztec/prover-node 0.0.1-commit.b655e406 → 0.0.1-commit.b6e433891

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 (56) hide show
  1. package/dest/actions/download-epoch-proving-job.d.ts +4 -4
  2. package/dest/actions/index.d.ts +1 -1
  3. package/dest/actions/rerun-epoch-proving-job.d.ts +4 -3
  4. package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
  5. package/dest/actions/rerun-epoch-proving-job.js +2 -2
  6. package/dest/actions/upload-epoch-proof-failure.d.ts +2 -2
  7. package/dest/actions/upload-epoch-proof-failure.d.ts.map +1 -1
  8. package/dest/bin/run-failed-epoch.d.ts +1 -1
  9. package/dest/bin/run-failed-epoch.js +5 -2
  10. package/dest/config.d.ts +8 -10
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +19 -21
  13. package/dest/factory.d.ts +20 -16
  14. package/dest/factory.d.ts.map +1 -1
  15. package/dest/factory.js +28 -62
  16. package/dest/index.d.ts +2 -1
  17. package/dest/index.d.ts.map +1 -1
  18. package/dest/index.js +1 -0
  19. package/dest/job/epoch-proving-job-data.d.ts +8 -6
  20. package/dest/job/epoch-proving-job-data.d.ts.map +1 -1
  21. package/dest/job/epoch-proving-job-data.js +25 -18
  22. package/dest/job/epoch-proving-job.d.ts +7 -13
  23. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  24. package/dest/job/epoch-proving-job.js +513 -105
  25. package/dest/metrics.d.ts +14 -3
  26. package/dest/metrics.d.ts.map +1 -1
  27. package/dest/metrics.js +55 -98
  28. package/dest/monitors/epoch-monitor.d.ts +3 -2
  29. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  30. package/dest/monitors/epoch-monitor.js +8 -18
  31. package/dest/monitors/index.d.ts +1 -1
  32. package/dest/prover-node-publisher.d.ts +14 -11
  33. package/dest/prover-node-publisher.d.ts.map +1 -1
  34. package/dest/prover-node-publisher.js +49 -42
  35. package/dest/prover-node.d.ts +27 -16
  36. package/dest/prover-node.d.ts.map +1 -1
  37. package/dest/prover-node.js +445 -59
  38. package/dest/prover-publisher-factory.d.ts +9 -5
  39. package/dest/prover-publisher-factory.d.ts.map +1 -1
  40. package/dest/prover-publisher-factory.js +4 -2
  41. package/dest/test/index.d.ts +1 -1
  42. package/dest/test/index.d.ts.map +1 -1
  43. package/package.json +27 -25
  44. package/src/actions/rerun-epoch-proving-job.ts +5 -3
  45. package/src/actions/upload-epoch-proof-failure.ts +1 -1
  46. package/src/bin/run-failed-epoch.ts +5 -2
  47. package/src/config.ts +27 -33
  48. package/src/factory.ts +64 -102
  49. package/src/index.ts +1 -0
  50. package/src/job/epoch-proving-job-data.ts +31 -25
  51. package/src/job/epoch-proving-job.ts +155 -110
  52. package/src/metrics.ts +65 -82
  53. package/src/monitors/epoch-monitor.ts +8 -15
  54. package/src/prover-node-publisher.ts +71 -58
  55. package/src/prover-node.ts +65 -53
  56. package/src/prover-publisher-factory.ts +16 -8
@@ -1,28 +1,30 @@
1
1
  import type { Archiver } from '@aztec/archiver';
2
- import type { RollupContract } from '@aztec/ethereum';
2
+ import type { RollupContract } from '@aztec/ethereum/contracts';
3
+ import type { Delayer } from '@aztec/ethereum/l1-tx-utils';
4
+ import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
3
5
  import { assertRequired, compact, pick, sum } from '@aztec/foundation/collection';
6
+ import type { Fr } from '@aztec/foundation/curves/bn254';
4
7
  import { memoize } from '@aztec/foundation/decorators';
5
- import type { Fr } from '@aztec/foundation/fields';
6
8
  import { createLogger } from '@aztec/foundation/log';
7
9
  import { DateProvider } from '@aztec/foundation/timer';
8
- import type { DataStoreConfig } from '@aztec/kv-store/config';
9
- import type { P2PClient } from '@aztec/p2p';
10
10
  import { PublicProcessorFactory } from '@aztec/simulator/server';
11
- import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
11
+ import type { L2BlockSource } from '@aztec/stdlib/block';
12
+ import type { Checkpoint } from '@aztec/stdlib/checkpoint';
12
13
  import type { ChainConfig } from '@aztec/stdlib/config';
13
14
  import type { ContractDataSource } from '@aztec/stdlib/contract';
14
15
  import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
15
16
  import {
16
17
  type EpochProverManager,
17
18
  EpochProvingJobTerminalState,
19
+ type ITxProvider,
18
20
  type ProverNodeApi,
19
21
  type Service,
20
22
  type WorldStateSyncStatus,
21
23
  type WorldStateSynchronizer,
22
24
  tryStop,
23
25
  } from '@aztec/stdlib/interfaces/server';
26
+ import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
24
27
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
25
- import type { P2PClientType } from '@aztec/stdlib/p2p';
26
28
  import type { Tx } from '@aztec/stdlib/tx';
27
29
  import {
28
30
  Attributes,
@@ -53,7 +55,6 @@ type DataStoreOptions = Pick<DataStoreConfig, 'dataDirectory'> & Pick<ChainConfi
53
55
  */
54
56
  export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable {
55
57
  private log = createLogger('prover-node');
56
- private dateProvider = new DateProvider();
57
58
 
58
59
  private jobs: Map<string, EpochProvingJob> = new Map();
59
60
  private config: ProverNodeOptions;
@@ -71,17 +72,19 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
71
72
  protected readonly l1ToL2MessageSource: L1ToL2MessageSource,
72
73
  protected readonly contractDataSource: ContractDataSource,
73
74
  protected readonly worldState: WorldStateSynchronizer,
74
- protected readonly p2pClient: Pick<P2PClient<P2PClientType.Prover>, 'getTxProvider'> & Partial<Service>,
75
+ protected readonly p2pClient: { getTxProvider(): ITxProvider } & Partial<Service>,
75
76
  protected readonly epochsMonitor: EpochMonitor,
76
77
  protected readonly rollupContract: RollupContract,
77
78
  protected readonly l1Metrics: L1Metrics,
78
79
  config: Partial<ProverNodeOptions> = {},
79
80
  protected readonly telemetryClient: TelemetryClient = getTelemetryClient(),
81
+ private delayer?: Delayer,
82
+ private readonly dateProvider: DateProvider = new DateProvider(),
80
83
  ) {
81
84
  this.config = {
82
85
  proverNodePollingIntervalMs: 1_000,
83
86
  proverNodeMaxPendingJobs: 100,
84
- proverNodeMaxParallelBlocksPerEpoch: 32,
87
+ proverNodeMaxParallelBlocksPerEpoch: 0,
85
88
  txGatheringIntervalMs: 1_000,
86
89
  txGatheringBatchSize: 10,
87
90
  txGatheringMaxParallelRequestsPerNode: 100,
@@ -109,12 +112,17 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
109
112
  return this.p2pClient;
110
113
  }
111
114
 
115
+ /** Returns the shared tx delayer for prover L1 txs, if enabled. Test-only. */
116
+ public getDelayer(): Delayer | undefined {
117
+ return this.delayer;
118
+ }
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.
115
123
  * @returns false if there is an error, true otherwise
116
124
  */
117
- async handleEpochReadyToProve(epochNumber: bigint): Promise<boolean> {
125
+ async handleEpochReadyToProve(epochNumber: EpochNumber): Promise<boolean> {
118
126
  try {
119
127
  this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
120
128
  jobs: Array.from(this.jobs.values()).map(job => `${job.getEpochNumber()}:${job.getId()}`),
@@ -153,17 +161,15 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
153
161
 
154
162
  /**
155
163
  * Stops the prover node and all its dependencies.
164
+ * Resources not owned by this node (shared with the parent aztec-node) are skipped.
156
165
  */
157
166
  async stop() {
158
167
  this.log.info('Stopping ProverNode');
159
168
  await this.epochsMonitor.stop();
160
169
  await this.prover.stop();
161
- await tryStop(this.p2pClient);
162
- await tryStop(this.l2BlockSource);
163
170
  await tryStop(this.publisherFactory);
164
171
  this.publisher?.interrupt();
165
172
  await Promise.all(Array.from(this.jobs.values()).map(job => job.stop()));
166
- await this.worldState.stop();
167
173
  this.rewardsMetrics.stop();
168
174
  this.l1Metrics.stop();
169
175
  await this.telemetryClient.stop();
@@ -184,8 +190,8 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
184
190
  /**
185
191
  * Starts a proving process and returns immediately.
186
192
  */
187
- public async startProof(epochNumber: number | bigint) {
188
- const job = await this.createProvingJob(BigInt(epochNumber), { skipEpochCheck: true });
193
+ public async startProof(epochNumber: EpochNumber) {
194
+ const job = await this.createProvingJob(epochNumber, { skipEpochCheck: true });
189
195
  void this.runJob(job);
190
196
  }
191
197
 
@@ -238,21 +244,20 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
238
244
  /**
239
245
  * Returns an array of jobs being processed.
240
246
  */
241
- public getJobs(): Promise<{ uuid: string; status: EpochProvingJobState; epochNumber: number }[]> {
247
+ public getJobs(): Promise<{ uuid: string; status: EpochProvingJobState; epochNumber: EpochNumber }[]> {
242
248
  return Promise.resolve(
243
249
  Array.from(this.jobs.entries()).map(([uuid, job]) => ({
244
250
  uuid,
245
251
  status: job.getState(),
246
- epochNumber: Number(job.getEpochNumber()),
252
+ epochNumber: job.getEpochNumber(),
247
253
  })),
248
254
  );
249
255
  }
250
256
 
251
257
  protected async getActiveJobsForEpoch(
252
- epochBigInt: bigint,
258
+ epochNumber: EpochNumber,
253
259
  ): Promise<{ uuid: string; status: EpochProvingJobState }[]> {
254
260
  const jobs = await this.getJobs();
255
- const epochNumber = Number(epochBigInt);
256
261
  return jobs.filter(job => job.epochNumber === epochNumber && !EpochProvingJobTerminalState.includes(job.status));
257
262
  }
258
263
 
@@ -263,33 +268,38 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
263
268
  }
264
269
  }
265
270
 
266
- @trackSpan('ProverNode.createProvingJob', epochNumber => ({ [Attributes.EPOCH_NUMBER]: Number(epochNumber) }))
267
- private async createProvingJob(epochNumber: bigint, opts: { skipEpochCheck?: boolean } = {}) {
271
+ @trackSpan('ProverNode.createProvingJob', epochNumber => ({ [Attributes.EPOCH_NUMBER]: epochNumber }))
272
+ private async createProvingJob(epochNumber: EpochNumber, opts: { skipEpochCheck?: boolean } = {}) {
268
273
  this.checkMaximumPendingJobs();
269
274
 
270
275
  this.publisher = await this.publisherFactory.create();
271
276
 
272
277
  // Gather all data for this epoch
273
278
  const epochData = await this.gatherEpochData(epochNumber);
274
-
275
- const fromBlock = epochData.blocks[0].number;
276
- const toBlock = epochData.blocks.at(-1)!.number;
277
- this.log.verbose(`Creating proving job for epoch ${epochNumber} for block range ${fromBlock} to ${toBlock}`);
279
+ const fromCheckpoint = epochData.checkpoints[0].number;
280
+ const toCheckpoint = epochData.checkpoints.at(-1)!.number;
281
+ const fromBlock = epochData.checkpoints[0].blocks[0].number;
282
+ const lastBlock = epochData.checkpoints.at(-1)!.blocks.at(-1)!;
283
+ const toBlock = lastBlock.number;
284
+ this.log.verbose(
285
+ `Creating proving job for epoch ${epochNumber} for checkpoint range ${fromCheckpoint} to ${toCheckpoint} and block range ${fromBlock} to ${toBlock}`,
286
+ );
278
287
 
279
288
  // Fast forward world state to right before the target block and get a fork
280
- await this.worldState.syncImmediate(toBlock);
289
+ const lastBlockHash = await lastBlock.header.hash();
290
+ await this.worldState.syncImmediate(toBlock, lastBlockHash);
281
291
 
282
292
  // Create a processor factory
283
293
  const publicProcessorFactory = new PublicProcessorFactory(
284
294
  this.contractDataSource,
285
295
  this.dateProvider,
286
296
  this.telemetryClient,
297
+ this.log.getBindings(),
287
298
  );
288
299
 
289
300
  // Set deadline for this job to run. It will abort if it takes too long.
290
301
  const deadlineTs = getProofSubmissionDeadlineTimestamp(epochNumber, await this.getL1Constants());
291
302
  const deadline = new Date(Number(deadlineTs) * 1000);
292
-
293
303
  const job = this.doCreateEpochProvingJob(epochData, deadline, publicProcessorFactory, this.publisher, opts);
294
304
  this.jobs.set(job.getId(), job);
295
305
  return job;
@@ -300,30 +310,32 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
300
310
  return this.l2BlockSource.getL1Constants();
301
311
  }
302
312
 
303
- @trackSpan('ProverNode.gatherEpochData', epochNumber => ({ [Attributes.EPOCH_NUMBER]: Number(epochNumber) }))
304
- private async gatherEpochData(epochNumber: bigint): Promise<EpochProvingJobData> {
305
- const blocks = await this.gatherBlocks(epochNumber);
306
- const txArray = await this.gatherTxs(epochNumber, blocks);
313
+ @trackSpan('ProverNode.gatherEpochData', epochNumber => ({ [Attributes.EPOCH_NUMBER]: epochNumber }))
314
+ private async gatherEpochData(epochNumber: EpochNumber): Promise<EpochProvingJobData> {
315
+ const checkpoints = await this.gatherCheckpoints(epochNumber);
316
+ const txArray = await this.gatherTxs(epochNumber, checkpoints);
307
317
  const txs = new Map<string, Tx>(txArray.map(tx => [tx.getTxHash().toString(), tx]));
308
- const l1ToL2Messages = await this.gatherMessages(epochNumber, blocks);
309
- const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, blocks[0]);
310
- const [lastBlock] = await this.l2BlockSource.getPublishedBlocks(blocks.at(-1)!.number, 1);
311
- const attestations = lastBlock?.attestations ?? [];
318
+ const l1ToL2Messages = await this.gatherMessages(epochNumber, checkpoints);
319
+ const [firstBlock] = checkpoints[0].blocks;
320
+ const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, firstBlock.number - 1);
321
+ const [lastPublishedCheckpoint] = await this.l2BlockSource.getCheckpoints(checkpoints.at(-1)!.number, 1);
322
+ const attestations = lastPublishedCheckpoint?.attestations ?? [];
312
323
 
313
- return { blocks, txs, l1ToL2Messages, epochNumber, previousBlockHeader, attestations };
324
+ return { checkpoints, txs, l1ToL2Messages, epochNumber, previousBlockHeader, attestations };
314
325
  }
315
326
 
316
- private async gatherBlocks(epochNumber: bigint) {
317
- const blocks = await this.l2BlockSource.getBlocksForEpoch(epochNumber);
318
- if (blocks.length === 0) {
327
+ private async gatherCheckpoints(epochNumber: EpochNumber) {
328
+ const checkpoints = await this.l2BlockSource.getCheckpointsForEpoch(epochNumber);
329
+ if (checkpoints.length === 0) {
319
330
  throw new EmptyEpochError(epochNumber);
320
331
  }
321
- return blocks;
332
+ return checkpoints;
322
333
  }
323
334
 
324
- private async gatherTxs(epochNumber: bigint, blocks: L2Block[]) {
335
+ private async gatherTxs(epochNumber: EpochNumber, checkpoints: Checkpoint[]) {
325
336
  const deadline = new Date(this.dateProvider.now() + this.config.txGatheringTimeoutMs);
326
337
  const txProvider = this.p2pClient.getTxProvider();
338
+ const blocks = checkpoints.flatMap(checkpoint => checkpoint.blocks);
327
339
  const txsByBlock = await Promise.all(blocks.map(block => txProvider.getTxsForBlock(block, { deadline })));
328
340
  const txs = txsByBlock.map(({ txs }) => txs).flat();
329
341
  const missingTxs = txsByBlock.map(({ missingTxs }) => missingTxs).flat();
@@ -336,25 +348,24 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
336
348
  throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxs.map(hash => hash.toString()).join(', ')}`);
337
349
  }
338
350
 
339
- private async gatherMessages(epochNumber: bigint, blocks: L2Block[]) {
340
- const messages = await Promise.all(blocks.map(b => this.l1ToL2MessageSource.getL1ToL2Messages(b.number)));
351
+ private async gatherMessages(epochNumber: EpochNumber, checkpoints: Checkpoint[]) {
352
+ const messages = await Promise.all(checkpoints.map(c => this.l1ToL2MessageSource.getL1ToL2Messages(c.number)));
341
353
  const messageCount = sum(messages.map(m => m.length));
342
354
  this.log.verbose(`Gathered all ${messageCount} messages for epoch ${epochNumber}`, { epochNumber });
343
- const messagesByBlock: Record<number, Fr[]> = {};
344
- for (let i = 0; i < blocks.length; i++) {
345
- messagesByBlock[blocks[i].number] = messages[i];
355
+ const messagesByCheckpoint: Record<CheckpointNumber, Fr[]> = {};
356
+ for (let i = 0; i < checkpoints.length; i++) {
357
+ messagesByCheckpoint[checkpoints[i].number] = messages[i];
346
358
  }
347
- return messagesByBlock;
359
+ return messagesByCheckpoint;
348
360
  }
349
361
 
350
- private async gatherPreviousBlockHeader(epochNumber: bigint, initialBlock: L2Block) {
351
- const previousBlockNumber = initialBlock.number - 1;
362
+ private async gatherPreviousBlockHeader(epochNumber: EpochNumber, previousBlockNumber: number) {
352
363
  const header = await (previousBlockNumber === 0
353
364
  ? this.worldState.getCommitted().getInitialHeader()
354
- : this.l2BlockSource.getBlockHeader(previousBlockNumber));
365
+ : this.l2BlockSource.getBlockHeader(BlockNumber(previousBlockNumber)));
355
366
 
356
367
  if (!header) {
357
- throw new Error(`Previous block header ${initialBlock.number} not found for proving epoch ${epochNumber}`);
368
+ throw new Error(`Previous block header ${previousBlockNumber} not found for proving epoch ${epochNumber}`);
358
369
  }
359
370
 
360
371
  this.log.verbose(`Gathered previous block header ${header.getBlockNumber()} for epoch ${epochNumber}`);
@@ -380,6 +391,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
380
391
  this.jobMetrics,
381
392
  deadline,
382
393
  { parallelBlockLimit, skipSubmitProof: proverNodeDisableProofPublish, ...opts },
394
+ this.log.getBindings(),
383
395
  );
384
396
  }
385
397
 
@@ -391,7 +403,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
391
403
  private validateConfig() {
392
404
  if (
393
405
  this.config.proverNodeFailedEpochStore &&
394
- (!this.config.dataDirectory || !this.config.l1ChainId || !this.config.rollupVersion)
406
+ (!this.config.dataDirectory || !this.config.l1ChainId || this.config.rollupVersion === undefined)
395
407
  ) {
396
408
  this.log.warn(
397
409
  `Invalid prover-node config (missing dataDirectory, l1ChainId, or rollupVersion)`,
@@ -405,7 +417,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
405
417
  }
406
418
 
407
419
  class EmptyEpochError extends Error {
408
- constructor(epochNumber: bigint) {
420
+ constructor(epochNumber: EpochNumber) {
409
421
  super(`No blocks found for epoch ${epochNumber}`);
410
422
  this.name = 'EmptyEpochError';
411
423
  }
@@ -1,17 +1,21 @@
1
- import type { L1TxUtils, PublisherManager, RollupContract } from '@aztec/ethereum';
2
- import type { PublisherConfig, TxSenderConfig } from '@aztec/sequencer-client';
1
+ import type { RollupContract } from '@aztec/ethereum/contracts';
2
+ import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
3
+ import type { PublisherManager } from '@aztec/ethereum/publisher-manager';
4
+ import type { LoggerBindings } from '@aztec/foundation/log';
5
+ import type { ProverPublisherConfig, ProverTxSenderConfig } from '@aztec/sequencer-client';
3
6
  import type { TelemetryClient } from '@aztec/telemetry-client';
4
7
 
5
8
  import { ProverNodePublisher } from './prover-node-publisher.js';
6
9
 
7
10
  export class ProverPublisherFactory {
8
11
  constructor(
9
- private config: TxSenderConfig & PublisherConfig,
12
+ private config: ProverTxSenderConfig & ProverPublisherConfig,
10
13
  private deps: {
11
14
  rollupContract: RollupContract;
12
15
  publisherManager: PublisherManager<L1TxUtils>;
13
16
  telemetry?: TelemetryClient;
14
17
  },
18
+ private bindings?: LoggerBindings,
15
19
  ) {}
16
20
 
17
21
  public async start() {
@@ -28,10 +32,14 @@ export class ProverPublisherFactory {
28
32
  */
29
33
  public async create(): Promise<ProverNodePublisher> {
30
34
  const l1Publisher = await this.deps.publisherManager.getAvailablePublisher();
31
- return new ProverNodePublisher(this.config, {
32
- rollupContract: this.deps.rollupContract,
33
- l1TxUtils: l1Publisher,
34
- telemetry: this.deps.telemetry,
35
- });
35
+ return new ProverNodePublisher(
36
+ this.config,
37
+ {
38
+ rollupContract: this.deps.rollupContract,
39
+ l1TxUtils: l1Publisher,
40
+ telemetry: this.deps.telemetry,
41
+ },
42
+ this.bindings,
43
+ );
36
44
  }
37
45
  }