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

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 (35) hide show
  1. package/dest/actions/download-epoch-proving-job.js +1 -1
  2. package/dest/actions/rerun-epoch-proving-job.d.ts +3 -2
  3. package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
  4. package/dest/actions/rerun-epoch-proving-job.js +105 -25
  5. package/dest/bin/run-failed-epoch.js +1 -3
  6. package/dest/factory.d.ts +1 -1
  7. package/dest/factory.d.ts.map +1 -1
  8. package/dest/factory.js +21 -2
  9. package/dest/job/epoch-proving-job.d.ts +6 -2
  10. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  11. package/dest/job/epoch-proving-job.js +186 -36
  12. package/dest/metrics.d.ts +11 -1
  13. package/dest/metrics.d.ts.map +1 -1
  14. package/dest/metrics.js +22 -0
  15. package/dest/monitors/epoch-monitor.js +6 -2
  16. package/dest/prover-node-publisher.d.ts +20 -1
  17. package/dest/prover-node-publisher.d.ts.map +1 -1
  18. package/dest/prover-node-publisher.js +200 -5
  19. package/dest/prover-node.d.ts +6 -6
  20. package/dest/prover-node.d.ts.map +1 -1
  21. package/dest/prover-node.js +77 -32
  22. package/dest/prover-publisher-factory.d.ts +2 -2
  23. package/dest/prover-publisher-factory.d.ts.map +1 -1
  24. package/dest/prover-publisher-factory.js +3 -3
  25. package/package.json +23 -23
  26. package/src/actions/download-epoch-proving-job.ts +1 -1
  27. package/src/actions/rerun-epoch-proving-job.ts +16 -5
  28. package/src/bin/run-failed-epoch.ts +1 -2
  29. package/src/factory.ts +18 -2
  30. package/src/job/epoch-proving-job.ts +102 -36
  31. package/src/metrics.ts +37 -0
  32. package/src/monitors/epoch-monitor.ts +2 -2
  33. package/src/prover-node-publisher.ts +232 -9
  34. package/src/prover-node.ts +81 -44
  35. package/src/prover-publisher-factory.ts +3 -3
@@ -378,7 +378,7 @@ import { createLogger } from '@aztec/foundation/log';
378
378
  import { DateProvider } from '@aztec/foundation/timer';
379
379
  import { PublicProcessorFactory } from '@aztec/simulator/server';
380
380
  import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
381
- import { EpochProvingJobTerminalState, tryStop } from '@aztec/stdlib/interfaces/server';
381
+ import { tryStop } from '@aztec/stdlib/interfaces/server';
382
382
  import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
383
383
  import { uploadEpochProofFailure } from './actions/upload-epoch-proof-failure.js';
384
384
  import { EpochProvingJob } from './job/epoch-proving-job.js';
@@ -430,6 +430,7 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
430
430
  config;
431
431
  jobMetrics;
432
432
  rewardsMetrics;
433
+ startingProofEpochs;
433
434
  tracer;
434
435
  publisher;
435
436
  constructor(prover, publisherFactory, l2BlockSource, l1ToL2MessageSource, contractDataSource, worldState, p2pClient, epochsMonitor, rollupContract, l1Metrics, config = {}, telemetryClient = getTelemetryClient(), delayer, dateProvider = new DateProvider()){
@@ -448,6 +449,7 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
448
449
  this.dateProvider = dateProvider;
449
450
  this.log = (_initProto(this), createLogger('prover-node'));
450
451
  this.jobs = new Map();
452
+ this.startingProofEpochs = new Set();
451
453
  this.config = {
452
454
  proverNodePollingIntervalMs: 1_000,
453
455
  proverNodeMaxPendingJobs: 100,
@@ -484,15 +486,7 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
484
486
  this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
485
487
  jobs: Array.from(this.jobs.values()).map((job)=>`${job.getEpochNumber()}:${job.getId()}`)
486
488
  });
487
- const activeJobs = await this.getActiveJobsForEpoch(epochNumber);
488
- if (activeJobs.length > 0) {
489
- this.log.warn(`Not starting proof for ${epochNumber} since there are active jobs for the epoch`, {
490
- activeJobs: activeJobs.map((job)=>job.uuid)
491
- });
492
- return true;
493
- }
494
- await this.startProof(epochNumber);
495
- return true;
489
+ return await this.startProofIfNeeded(epochNumber);
496
490
  } catch (err) {
497
491
  if (err instanceof EmptyEpochError) {
498
492
  this.log.info(`Not starting proof for ${epochNumber} since no blocks were found`);
@@ -519,10 +513,10 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
519
513
  */ async stop() {
520
514
  this.log.info('Stopping ProverNode');
521
515
  await this.epochsMonitor.stop();
522
- await this.prover.stop();
523
- await tryStop(this.publisherFactory);
524
516
  this.publisher?.interrupt();
525
517
  await Promise.all(Array.from(this.jobs.values()).map((job)=>job.stop()));
518
+ await this.prover.stop();
519
+ await tryStop(this.publisherFactory);
526
520
  this.rewardsMetrics.stop();
527
521
  this.l1Metrics.stop();
528
522
  await this.telemetryClient.stop();
@@ -538,9 +532,35 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
538
532
  /**
539
533
  * Starts a proving process and returns immediately.
540
534
  */ async startProof(epochNumber) {
541
- const job = await this.createProvingJob(epochNumber, {
535
+ await this.startProofIfNeeded(epochNumber, {
542
536
  skipEpochCheck: true
543
537
  });
538
+ }
539
+ async startProofIfNeeded(epochNumber, opts = {}) {
540
+ if (this.startingProofEpochs.has(epochNumber)) {
541
+ this.log.warn(`Not starting proof for ${epochNumber} since a proof is already being started for the epoch`, {
542
+ epochNumber
543
+ });
544
+ return false;
545
+ }
546
+ this.startingProofEpochs.add(epochNumber);
547
+ try {
548
+ const activeJobs = await this.activeJobsCoverEpoch(epochNumber);
549
+ if (activeJobs.length > 0) {
550
+ this.log.warn(`Not starting proof for ${epochNumber} since an active job already covers the epoch`, {
551
+ epochNumber,
552
+ activeJobs
553
+ });
554
+ return true;
555
+ }
556
+ await this.startProofInternal(epochNumber, opts);
557
+ return true;
558
+ } finally{
559
+ this.startingProofEpochs.delete(epochNumber);
560
+ }
561
+ }
562
+ async startProofInternal(epochNumber, opts = {}) {
563
+ const job = await this.createProvingJob(epochNumber, opts);
544
564
  void this.runJob(job);
545
565
  }
546
566
  async runJob(job) {
@@ -582,15 +602,40 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
582
602
  /**
583
603
  * Returns an array of jobs being processed.
584
604
  */ getJobs() {
585
- return Promise.resolve(Array.from(this.jobs.entries()).map(([uuid, job])=>({
605
+ return Promise.resolve(this.getJobsInternal());
606
+ }
607
+ getJobsInternal() {
608
+ return Array.from(this.jobs.entries()).map(([uuid, job])=>({
586
609
  uuid,
587
610
  status: job.getState(),
588
611
  epochNumber: job.getEpochNumber()
589
- })));
612
+ }));
590
613
  }
591
- async getActiveJobsForEpoch(epochNumber) {
592
- const jobs = await this.getJobs();
593
- return jobs.filter((job)=>job.epochNumber === epochNumber && !EpochProvingJobTerminalState.includes(job.status));
614
+ async activeJobsCoverEpoch(epochNumber) {
615
+ const checkpoints = await this.l2BlockSource.getCheckpointsData({
616
+ epoch: epochNumber
617
+ });
618
+ if (checkpoints.length === 0) {
619
+ return [];
620
+ }
621
+ const firstCheckpoint = checkpoints.at(0).checkpointNumber;
622
+ const latestCheckpoint = checkpoints.at(-1).checkpointNumber;
623
+ const jobs = [];
624
+ for (const job of this.jobs.values()){
625
+ if (job.getEpochNumber() !== epochNumber) {
626
+ continue;
627
+ }
628
+ const jobCheckpoints = job.getProvingData().checkpoints;
629
+ const checkpointOverlap = jobCheckpoints.at(0).number <= firstCheckpoint && jobCheckpoints.at(-1).number >= latestCheckpoint;
630
+ if (checkpointOverlap && ![
631
+ 'failed',
632
+ 'stopped',
633
+ 'timed-out'
634
+ ].includes(job.getState())) {
635
+ jobs.push(job.getId());
636
+ }
637
+ }
638
+ return jobs;
594
639
  }
595
640
  checkMaximumPendingJobs() {
596
641
  const { proverNodeMaxPendingJobs: maxPendingJobs } = this.config;
@@ -625,7 +670,14 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
625
670
  return this.l2BlockSource.getL1Constants();
626
671
  }
627
672
  async gatherEpochData(epochNumber) {
628
- const checkpoints = await this.gatherCheckpoints(epochNumber);
673
+ const publishedCheckpoints = await this.l2BlockSource.getCheckpoints({
674
+ epoch: epochNumber
675
+ });
676
+ if (publishedCheckpoints.length === 0) {
677
+ throw new EmptyEpochError(epochNumber);
678
+ }
679
+ const checkpoints = publishedCheckpoints.map((p)=>p.checkpoint);
680
+ const attestations = publishedCheckpoints.at(-1)?.attestations ?? [];
629
681
  const txArray = await this.gatherTxs(epochNumber, checkpoints);
630
682
  const txs = new Map(txArray.map((tx)=>[
631
683
  tx.getTxHash().toString(),
@@ -634,8 +686,6 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
634
686
  const l1ToL2Messages = await this.gatherMessages(epochNumber, checkpoints);
635
687
  const [firstBlock] = checkpoints[0].blocks;
636
688
  const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, firstBlock.number - 1);
637
- const [lastPublishedCheckpoint] = await this.l2BlockSource.getCheckpoints(checkpoints.at(-1).number, 1);
638
- const attestations = lastPublishedCheckpoint?.attestations ?? [];
639
689
  return {
640
690
  checkpoints,
641
691
  txs,
@@ -645,13 +695,6 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
645
695
  attestations
646
696
  };
647
697
  }
648
- async gatherCheckpoints(epochNumber) {
649
- const checkpoints = await this.l2BlockSource.getCheckpointsForEpoch(epochNumber);
650
- if (checkpoints.length === 0) {
651
- throw new EmptyEpochError(epochNumber);
652
- }
653
- return checkpoints;
654
- }
655
698
  async gatherTxs(epochNumber, checkpoints) {
656
699
  const deadline = new Date(this.dateProvider.now() + this.config.txGatheringTimeoutMs);
657
700
  const txProvider = this.p2pClient.getTxProvider();
@@ -682,12 +725,14 @@ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
682
725
  return messagesByCheckpoint;
683
726
  }
684
727
  async gatherPreviousBlockHeader(epochNumber, previousBlockNumber) {
685
- const header = await (previousBlockNumber === 0 ? this.worldState.getCommitted().getInitialHeader() : this.l2BlockSource.getBlockHeader(BlockNumber(previousBlockNumber)));
686
- if (!header) {
728
+ const data = await this.l2BlockSource.getBlockData({
729
+ number: BlockNumber(previousBlockNumber)
730
+ });
731
+ if (!data?.header) {
687
732
  throw new Error(`Previous block header ${previousBlockNumber} not found for proving epoch ${epochNumber}`);
688
733
  }
689
- this.log.verbose(`Gathered previous block header ${header.getBlockNumber()} for epoch ${epochNumber}`);
690
- return header;
734
+ this.log.verbose(`Gathered previous block header ${data.header.getBlockNumber()} for epoch ${epochNumber}`);
735
+ return data.header;
691
736
  }
692
737
  /** Extracted for testing purposes. */ doCreateEpochProvingJob(data, deadline, publicProcessorFactory, publisher, opts = {}) {
693
738
  const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit, proverNodeDisableProofPublish } = this.config;
@@ -15,11 +15,11 @@ export declare class ProverPublisherFactory {
15
15
  telemetry?: TelemetryClient;
16
16
  }, bindings?: LoggerBindings | undefined);
17
17
  start(): Promise<void>;
18
- stop(): void;
18
+ stop(): Promise<void>;
19
19
  /**
20
20
  * Creates a new Prover Publisher instance.
21
21
  * @returns A new ProverNodePublisher instance.
22
22
  */
23
23
  create(): Promise<ProverNodePublisher>;
24
24
  }
25
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmVyLXB1Ymxpc2hlci1mYWN0b3J5LmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJvdmVyLXB1Ymxpc2hlci1mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2hFLE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzdELE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDMUUsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDNUQsT0FBTyxLQUFLLEVBQUUscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUMzRixPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUUvRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVqRSxxQkFBYSxzQkFBc0I7SUFFL0IsT0FBTyxDQUFDLE1BQU07SUFDZCxPQUFPLENBQUMsSUFBSTtJQUtaLE9BQU8sQ0FBQyxRQUFRLENBQUM7SUFQbkIsWUFDVSxNQUFNLEVBQUUsb0JBQW9CLEdBQUcscUJBQXFCLEVBQ3BELElBQUksRUFBRTtRQUNaLGNBQWMsRUFBRSxjQUFjLENBQUM7UUFDL0IsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDOUMsU0FBUyxDQUFDLEVBQUUsZUFBZSxDQUFDO0tBQzdCLEVBQ08sUUFBUSxDQUFDLDRCQUFnQixFQUMvQjtJQUVTLEtBQUssa0JBRWpCO0lBRU0sSUFBSSxTQUVWO0lBRUQ7OztPQUdHO0lBQ1UsTUFBTSxJQUFJLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxDQVdsRDtDQUNGIn0=
25
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmVyLXB1Ymxpc2hlci1mYWN0b3J5LmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJvdmVyLXB1Ymxpc2hlci1mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2hFLE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzdELE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDMUUsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDNUQsT0FBTyxLQUFLLEVBQUUscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUMzRixPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUUvRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVqRSxxQkFBYSxzQkFBc0I7SUFFL0IsT0FBTyxDQUFDLE1BQU07SUFDZCxPQUFPLENBQUMsSUFBSTtJQUtaLE9BQU8sQ0FBQyxRQUFRLENBQUM7SUFQbkIsWUFDVSxNQUFNLEVBQUUsb0JBQW9CLEdBQUcscUJBQXFCLEVBQ3BELElBQUksRUFBRTtRQUNaLGNBQWMsRUFBRSxjQUFjLENBQUM7UUFDL0IsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDOUMsU0FBUyxDQUFDLEVBQUUsZUFBZSxDQUFDO0tBQzdCLEVBQ08sUUFBUSxDQUFDLDRCQUFnQixFQUMvQjtJQUVTLEtBQUssa0JBRWpCO0lBRVksSUFBSSxrQkFFaEI7SUFFRDs7O09BR0c7SUFDVSxNQUFNLElBQUksT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBV2xEO0NBQ0YifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"prover-publisher-factory.d.ts","sourceRoot":"","sources":["../src/prover-publisher-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,QAAQ,CAAC;IAPnB,YACU,MAAM,EAAE,oBAAoB,GAAG,qBAAqB,EACpD,IAAI,EAAE;QACZ,cAAc,EAAE,cAAc,CAAC;QAC/B,gBAAgB,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAC9C,SAAS,CAAC,EAAE,eAAe,CAAC;KAC7B,EACO,QAAQ,CAAC,4BAAgB,EAC/B;IAES,KAAK,kBAEjB;IAEM,IAAI,SAEV;IAED;;;OAGG;IACU,MAAM,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAWlD;CACF"}
1
+ {"version":3,"file":"prover-publisher-factory.d.ts","sourceRoot":"","sources":["../src/prover-publisher-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,QAAQ,CAAC;IAPnB,YACU,MAAM,EAAE,oBAAoB,GAAG,qBAAqB,EACpD,IAAI,EAAE;QACZ,cAAc,EAAE,cAAc,CAAC;QAC/B,gBAAgB,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAC9C,SAAS,CAAC,EAAE,eAAe,CAAC;KAC7B,EACO,QAAQ,CAAC,4BAAgB,EAC/B;IAES,KAAK,kBAEjB;IAEY,IAAI,kBAEhB;IAED;;;OAGG;IACU,MAAM,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAWlD;CACF"}
@@ -9,10 +9,10 @@ export class ProverPublisherFactory {
9
9
  this.bindings = bindings;
10
10
  }
11
11
  async start() {
12
- await this.deps.publisherManager.loadState();
12
+ await this.deps.publisherManager.start();
13
13
  }
14
- stop() {
15
- this.deps.publisherManager.interrupt();
14
+ async stop() {
15
+ await this.deps.publisherManager.stop();
16
16
  }
17
17
  /**
18
18
  * Creates a new Prover Publisher instance.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/prover-node",
3
- "version": "0.0.1-commit.b6e433891",
3
+ "version": "0.0.1-commit.b9865e97",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -56,28 +56,28 @@
56
56
  ]
57
57
  },
58
58
  "dependencies": {
59
- "@aztec/archiver": "0.0.1-commit.b6e433891",
60
- "@aztec/bb-prover": "0.0.1-commit.b6e433891",
61
- "@aztec/blob-client": "0.0.1-commit.b6e433891",
62
- "@aztec/blob-lib": "0.0.1-commit.b6e433891",
63
- "@aztec/constants": "0.0.1-commit.b6e433891",
64
- "@aztec/epoch-cache": "0.0.1-commit.b6e433891",
65
- "@aztec/ethereum": "0.0.1-commit.b6e433891",
66
- "@aztec/foundation": "0.0.1-commit.b6e433891",
67
- "@aztec/kv-store": "0.0.1-commit.b6e433891",
68
- "@aztec/l1-artifacts": "0.0.1-commit.b6e433891",
69
- "@aztec/native": "0.0.1-commit.b6e433891",
70
- "@aztec/node-keystore": "0.0.1-commit.b6e433891",
71
- "@aztec/node-lib": "0.0.1-commit.b6e433891",
72
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.b6e433891",
73
- "@aztec/p2p": "0.0.1-commit.b6e433891",
74
- "@aztec/protocol-contracts": "0.0.1-commit.b6e433891",
75
- "@aztec/prover-client": "0.0.1-commit.b6e433891",
76
- "@aztec/sequencer-client": "0.0.1-commit.b6e433891",
77
- "@aztec/simulator": "0.0.1-commit.b6e433891",
78
- "@aztec/stdlib": "0.0.1-commit.b6e433891",
79
- "@aztec/telemetry-client": "0.0.1-commit.b6e433891",
80
- "@aztec/world-state": "0.0.1-commit.b6e433891",
59
+ "@aztec/archiver": "0.0.1-commit.b9865e97",
60
+ "@aztec/bb-prover": "0.0.1-commit.b9865e97",
61
+ "@aztec/blob-client": "0.0.1-commit.b9865e97",
62
+ "@aztec/blob-lib": "0.0.1-commit.b9865e97",
63
+ "@aztec/constants": "0.0.1-commit.b9865e97",
64
+ "@aztec/epoch-cache": "0.0.1-commit.b9865e97",
65
+ "@aztec/ethereum": "0.0.1-commit.b9865e97",
66
+ "@aztec/foundation": "0.0.1-commit.b9865e97",
67
+ "@aztec/kv-store": "0.0.1-commit.b9865e97",
68
+ "@aztec/l1-artifacts": "0.0.1-commit.b9865e97",
69
+ "@aztec/native": "0.0.1-commit.b9865e97",
70
+ "@aztec/node-keystore": "0.0.1-commit.b9865e97",
71
+ "@aztec/node-lib": "0.0.1-commit.b9865e97",
72
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.b9865e97",
73
+ "@aztec/p2p": "0.0.1-commit.b9865e97",
74
+ "@aztec/protocol-contracts": "0.0.1-commit.b9865e97",
75
+ "@aztec/prover-client": "0.0.1-commit.b9865e97",
76
+ "@aztec/sequencer-client": "0.0.1-commit.b9865e97",
77
+ "@aztec/simulator": "0.0.1-commit.b9865e97",
78
+ "@aztec/stdlib": "0.0.1-commit.b9865e97",
79
+ "@aztec/telemetry-client": "0.0.1-commit.b9865e97",
80
+ "@aztec/world-state": "0.0.1-commit.b9865e97",
81
81
  "source-map-support": "^0.5.21",
82
82
  "tslib": "^2.4.0",
83
83
  "viem": "npm:@aztec/viem@2.38.2"
@@ -30,7 +30,7 @@ export async function downloadEpochProvingJob(
30
30
 
31
31
  const dataUrls = makeSnapshotPaths(location);
32
32
  log.info(`Downloading state snapshot from ${location} to local data directory`, { metadata, dataUrls });
33
- await snapshotSync({ dataUrls }, log, { ...config, ...metadata, snapshotsUrl: location });
33
+ await snapshotSync({ dataUrls }, log, { ...config, ...metadata, fileStore });
34
34
 
35
35
  const dataPath = urlJoin(location, 'data.bin');
36
36
  const localPath = config.jobDataDownloadPath;
@@ -1,10 +1,11 @@
1
- import { createArchiverStore } from '@aztec/archiver';
1
+ import { createArchiverStore, createContractDataSource } from '@aztec/archiver';
2
2
  import type { L1ContractsConfig } from '@aztec/ethereum/config';
3
3
  import type { Logger } from '@aztec/foundation/log';
4
4
  import { type ProverClientConfig, createProverClient } from '@aztec/prover-client';
5
5
  import { ProverBrokerConfig, createAndStartProvingBroker } from '@aztec/prover-client/broker';
6
6
  import { PublicProcessorFactory } from '@aztec/simulator/server';
7
7
  import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
8
+ import type { GenesisData } from '@aztec/stdlib/world-state';
8
9
  import { getTelemetryClient } from '@aztec/telemetry-client';
9
10
  import { createWorldState } from '@aztec/world-state';
10
11
 
@@ -23,17 +24,27 @@ export async function rerunEpochProvingJob(
23
24
  localPath: string,
24
25
  log: Logger,
25
26
  config: DataStoreConfig & ProverBrokerConfig & ProverClientConfig & Pick<L1ContractsConfig, 'aztecEpochDuration'>,
27
+ genesis?: GenesisData,
26
28
  ) {
27
29
  const jobData = deserializeEpochProvingJobData(readFileSync(localPath));
28
30
  log.info(`Loaded proving job data for epoch ${jobData.epochNumber}`);
29
31
 
30
32
  const telemetry = getTelemetryClient();
31
33
  const metrics = new ProverNodeJobMetrics(telemetry.getMeter('prover-job'), telemetry.getTracer('prover-job'));
32
- const worldState = await createWorldState(config);
33
- const archiver = await createArchiverStore(config);
34
- const publicProcessorFactory = new PublicProcessorFactory(archiver, undefined, undefined, log.getBindings());
34
+ await using worldState = await createWorldState(config, genesis);
35
+ const initialBlockHash = await worldState.getInitialHeader().hash();
36
+ const archiver = await createArchiverStore(config, initialBlockHash);
37
+ const publicProcessorFactory = new PublicProcessorFactory(
38
+ createContractDataSource(archiver),
39
+ undefined,
40
+ undefined,
41
+ log.getBindings(),
42
+ );
35
43
 
36
- const publisher = { submitEpochProof: () => Promise.resolve(true) };
44
+ const publisher = {
45
+ submitEpochProof: () => Promise.resolve(true),
46
+ analyzeEpochProofSubmission: () => Promise.resolve(),
47
+ };
37
48
  const l2BlockSourceForReorgDetection = undefined;
38
49
  const deadline = undefined;
39
50
 
@@ -1,6 +1,5 @@
1
1
  /* eslint-disable no-console */
2
2
  import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
3
- import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
4
3
  import { EthAddress } from '@aztec/foundation/eth-address';
5
4
  import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
6
5
  import { createLogger } from '@aztec/foundation/log';
@@ -50,7 +49,7 @@ async function rerunFailedEpoch(provingJobUrl: string, baseLocalDir: string) {
50
49
  logger.info(`Rerunning proving job from ${jobPath} with state from ${dataDir}`, metadata);
51
50
  const result = await rerunEpochProvingJob(jobPath, logger, {
52
51
  ...config,
53
- l1Contracts: { rollupAddress: metadata.rollupAddress } as L1ContractAddresses,
52
+ rollupAddress: metadata.rollupAddress,
54
53
  rollupVersion: metadata.rollupVersion,
55
54
  });
56
55
 
package/src/factory.ts CHANGED
@@ -100,7 +100,7 @@ export async function createProverNode(
100
100
  pollingInterval: config.viemPollingIntervalMS,
101
101
  });
102
102
 
103
- const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
103
+ const rollupContract = new RollupContract(publicClient, config.rollupAddress.toString());
104
104
 
105
105
  const l1TxUtils = deps.l1TxUtils
106
106
  ? [deps.l1TxUtils]
@@ -119,11 +119,27 @@ export async function createProverNode(
119
119
  { telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
120
120
  );
121
121
 
122
+ // Create a funder L1TxUtils from the keystore funding account (if configured)
123
+ const fundingSigner = keyStoreManager?.createFundingSigner();
124
+ let funderL1TxUtils: L1TxUtils | undefined;
125
+ if (fundingSigner) {
126
+ const [funder] = await createL1TxUtilsFromSigners(
127
+ publicClient,
128
+ [fundingSigner],
129
+ { ...config, scope: 'prover' },
130
+ { telemetry, logger: log.createChild('l1-tx-utils:funder'), dateProvider },
131
+ );
132
+ funderL1TxUtils = funder;
133
+ }
134
+
122
135
  const publisherFactory =
123
136
  deps.publisherFactory ??
124
137
  new ProverPublisherFactory(config, {
125
138
  rollupContract,
126
- publisherManager: new PublisherManager(l1TxUtils, getPublisherConfigFromProverConfig(config), log.getBindings()),
139
+ publisherManager: new PublisherManager(l1TxUtils, getPublisherConfigFromProverConfig(config), {
140
+ bindings: log.getBindings(),
141
+ funder: funderL1TxUtils,
142
+ }),
127
143
  telemetry,
128
144
  });
129
145
 
@@ -1,7 +1,5 @@
1
- import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
1
  import { asyncPool } from '@aztec/foundation/async-pool';
3
2
  import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
4
- import { padArrayEnd } from '@aztec/foundation/collection';
5
3
  import { Fr } from '@aztec/foundation/curves/bn254';
6
4
  import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
7
5
  import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
@@ -20,8 +18,8 @@ import {
20
18
  EpochProvingJobTerminalState,
21
19
  type ForkMerkleTreeOperations,
22
20
  } from '@aztec/stdlib/interfaces/server';
21
+ import { appendL1ToL2MessagesToTree } from '@aztec/stdlib/messaging';
23
22
  import { CheckpointConstantData } from '@aztec/stdlib/rollup';
24
- import { MerkleTreeId } from '@aztec/stdlib/trees';
25
23
  import type { ProcessedTx, Tx } from '@aztec/stdlib/tx';
26
24
  import { Attributes, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
27
25
 
@@ -48,6 +46,7 @@ export class EpochProvingJob implements Traceable {
48
46
  private uuid: string;
49
47
 
50
48
  private runPromise: Promise<void> | undefined;
49
+ private abortController = new AbortController();
51
50
  private epochCheckPromise: RunningPromise | undefined;
52
51
  private deadlineTimeoutHandler: NodeJS.Timeout | undefined;
53
52
 
@@ -58,7 +57,7 @@ export class EpochProvingJob implements Traceable {
58
57
  private dbProvider: Pick<ForkMerkleTreeOperations, 'fork'>,
59
58
  private prover: EpochProver,
60
59
  private publicProcessorFactory: PublicProcessorFactory,
61
- private publisher: Pick<ProverNodePublisher, 'submitEpochProof'>,
60
+ private publisher: Pick<ProverNodePublisher, 'submitEpochProof' | 'analyzeEpochProofSubmission'>,
62
61
  private l2BlockSource: L2BlockSource | undefined,
63
62
  private metrics: ProverNodeJobMetrics,
64
63
  private deadline: Date | undefined,
@@ -172,7 +171,7 @@ export class EpochProvingJob implements Traceable {
172
171
  ? AVM_MAX_CONCURRENT_SIMULATIONS
173
172
  : this.checkpoints.length;
174
173
 
175
- await asyncPool(parallelism, this.checkpoints, async checkpoint => {
174
+ await this.processCheckpoints(parallelism, async checkpoint => {
176
175
  this.checkState();
177
176
  const checkpointTimer = new Timer();
178
177
 
@@ -191,11 +190,12 @@ export class EpochProvingJob implements Traceable {
191
190
  const previousHeader = previousBlockHeaders[checkpointIndex];
192
191
  const l1ToL2Messages = this.getL1ToL2Messages(checkpoint);
193
192
 
194
- this.log.verbose(`Starting processing checkpoint ${checkpoint.number}`, {
193
+ this.log.debug(`Starting processing checkpoint ${checkpoint.number}`, {
195
194
  number: checkpoint.number,
196
195
  checkpointHash: checkpoint.hash().toString(),
197
- lastArchive: checkpoint.header.lastArchiveRoot,
198
- previousHeader: previousHeader.hash(),
196
+ headerHash: checkpoint.header.hash().toString(),
197
+ numL1ToL2Messages: l1ToL2Messages.length,
198
+ previousBlockNumber: previousHeader.globalVariables.blockNumber,
199
199
  uuid: this.uuid,
200
200
  });
201
201
 
@@ -229,22 +229,26 @@ export class EpochProvingJob implements Traceable {
229
229
 
230
230
  // Process public fns. L1 to L2 messages are only inserted for the first block of a checkpoint,
231
231
  // as the fork for subsequent blocks already includes them from the previous block's synced state.
232
- const db = await this.createFork(
233
- BlockNumber(block.number - 1),
234
- blockIndex === 0 ? l1ToL2Messages : undefined,
235
- );
236
- const config = PublicSimulatorConfig.from({
237
- proverId: this.prover.getProverId().toField(),
238
- skipFeeEnforcement: false,
239
- collectDebugLogs: false,
240
- collectHints: true,
241
- collectPublicInputs: true,
242
- collectStatistics: false,
243
- });
244
- const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, config);
245
- const processed = await this.processTxs(publicProcessor, txs);
246
- await this.prover.addTxs(processed);
247
- await db.close();
232
+ {
233
+ await using db = await this.createFork(
234
+ BlockNumber(block.number - 1),
235
+ blockIndex === 0 ? l1ToL2Messages : undefined,
236
+ );
237
+ this.checkState();
238
+ const config = PublicSimulatorConfig.from({
239
+ proverId: this.prover.getProverId().toField(),
240
+ skipFeeEnforcement: false,
241
+ collectDebugLogs: false,
242
+ collectHints: true,
243
+ collectPublicInputs: true,
244
+ collectStatistics: false,
245
+ });
246
+ const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, config);
247
+ const processed = await this.processTxs(publicProcessor, txs);
248
+ this.checkState();
249
+ await this.prover.addTxs(processed);
250
+ }
251
+ this.checkState();
248
252
  this.log.verbose(`Processed all ${txs.length} txs for block ${block.number}`, {
249
253
  blockNumber: block.number,
250
254
  blockHash: (await block.hash()).toString(),
@@ -270,8 +274,21 @@ export class EpochProvingJob implements Traceable {
270
274
 
271
275
  if (this.config.skipSubmitProof) {
272
276
  this.log.info(
273
- `Proof publishing is disabled. Dropping valid proof for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`,
277
+ `Proof publishing is disabled. Analyzing estimated L1 fees for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`,
274
278
  );
279
+ try {
280
+ await this.publisher.analyzeEpochProofSubmission({
281
+ fromCheckpoint,
282
+ toCheckpoint,
283
+ epochNumber,
284
+ publicInputs,
285
+ proof,
286
+ batchedBlobInputs,
287
+ attestations,
288
+ });
289
+ } catch (err) {
290
+ this.log.warn(`Failed to analyze estimated L1 fees for epoch ${epochNumber}`, err);
291
+ }
275
292
  this.state = 'completed';
276
293
  this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeCheckpoints, epochSizeBlocks, epochSizeTxs);
277
294
  return;
@@ -325,25 +342,56 @@ export class EpochProvingJob implements Traceable {
325
342
  */
326
343
  private async createFork(blockNumber: BlockNumber, l1ToL2Messages: Fr[] | undefined) {
327
344
  this.log.verbose(`Creating fork at ${blockNumber}`, { blockNumber });
328
- const db = await this.dbProvider.fork(blockNumber);
345
+ // temporary stack to control fork lifetime
346
+ await using cleanup = new AsyncDisposableStack();
347
+ const db = cleanup.use(await this.dbProvider.fork(blockNumber));
329
348
 
330
349
  if (l1ToL2Messages !== undefined) {
331
350
  this.log.verbose(`Inserting ${l1ToL2Messages.length} L1 to L2 messages in fork`, {
332
351
  blockNumber,
333
352
  l1ToL2Messages: l1ToL2Messages.map(m => m.toString()),
334
353
  });
335
- const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
336
- l1ToL2Messages,
337
- Fr.ZERO,
338
- NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
339
- 'Too many L1 to L2 messages',
340
- );
341
- await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
354
+ await appendL1ToL2MessagesToTree(db, l1ToL2Messages);
342
355
  }
343
356
 
357
+ // everything run succesfully so we can release this stack and give control of the fork's lifetime to the caller
358
+ cleanup.move();
344
359
  return db;
345
360
  }
346
361
 
362
+ private async processCheckpoints(
363
+ parallelism: number,
364
+ processCheckpoint: (checkpoint: Checkpoint) => Promise<void>,
365
+ ): Promise<void> {
366
+ let hasError = false;
367
+ let firstError: unknown;
368
+
369
+ await asyncPool(Math.max(parallelism, 1), this.checkpoints, async checkpoint => {
370
+ if (hasError || this.abortController.signal.aborted) {
371
+ return;
372
+ }
373
+
374
+ try {
375
+ this.checkState();
376
+ await processCheckpoint(checkpoint);
377
+ } catch (err) {
378
+ if (!hasError) {
379
+ hasError = true;
380
+ firstError = err;
381
+ this.failProcessing();
382
+ }
383
+ }
384
+ });
385
+
386
+ if (hasError) {
387
+ throw firstError;
388
+ }
389
+
390
+ if (this.abortController.signal.aborted) {
391
+ this.checkState();
392
+ }
393
+ }
394
+
347
395
  private progressState(state: EpochProvingJobState) {
348
396
  this.checkState();
349
397
  this.state = state;
@@ -357,12 +405,24 @@ export class EpochProvingJob implements Traceable {
357
405
 
358
406
  public async stop(state: EpochProvingJobTerminalState = 'stopped') {
359
407
  this.state = state;
360
- this.prover.cancel();
408
+ this.interruptProcessing();
361
409
  if (this.runPromise) {
362
410
  await this.runPromise;
363
411
  }
364
412
  }
365
413
 
414
+ private failProcessing() {
415
+ if (!EpochProvingJobTerminalState.includes(this.state)) {
416
+ this.state = 'failed';
417
+ }
418
+ this.interruptProcessing();
419
+ }
420
+
421
+ private interruptProcessing() {
422
+ this.abortController.abort();
423
+ this.prover.cancel();
424
+ }
425
+
366
426
  private scheduleDeadlineStop() {
367
427
  const deadline = this.deadline;
368
428
  if (deadline) {
@@ -397,7 +457,9 @@ export class EpochProvingJob implements Traceable {
397
457
  const intervalMs = Math.ceil((await l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
398
458
  this.epochCheckPromise = new RunningPromise(
399
459
  async () => {
400
- const blockHeaders = await l2BlockSource.getCheckpointedBlockHeadersForEpoch(this.epochNumber);
460
+ const blockHeaders = (
461
+ await l2BlockSource.getBlocksData({ epoch: this.epochNumber, onlyCheckpointed: true })
462
+ ).map(d => d.header);
401
463
  const blockHashes = await Promise.all(blockHeaders.map(header => header.hash()));
402
464
  const thisBlocks = this.checkpoints.flatMap(checkpoint => checkpoint.blocks);
403
465
  const thisBlockHashes = await Promise.all(thisBlocks.map(block => block.hash()));
@@ -436,7 +498,11 @@ export class EpochProvingJob implements Traceable {
436
498
 
437
499
  private async processTxs(publicProcessor: PublicProcessor, txs: Tx[]): Promise<ProcessedTx[]> {
438
500
  const { deadline } = this;
439
- const [processedTxs, failedTxs] = await publicProcessor.process(txs, { deadline });
501
+ const [processedTxs, failedTxs] = await publicProcessor.process(txs, {
502
+ deadline,
503
+ signal: this.abortController.signal,
504
+ });
505
+ this.checkState();
440
506
 
441
507
  if (failedTxs.length) {
442
508
  const failedTxHashes = await Promise.all(failedTxs.map(({ tx }) => tx.getTxHash()));