@aztec/prover-node 4.0.0-nightly.20250907 → 4.0.0-nightly.20260107

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 (48) 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 +2 -2
  4. package/dest/actions/upload-epoch-proof-failure.d.ts +1 -1
  5. package/dest/bin/run-failed-epoch.d.ts +1 -1
  6. package/dest/bin/run-failed-epoch.js +1 -1
  7. package/dest/config.d.ts +7 -4
  8. package/dest/config.d.ts.map +1 -1
  9. package/dest/config.js +21 -15
  10. package/dest/factory.d.ts +2 -4
  11. package/dest/factory.d.ts.map +1 -1
  12. package/dest/factory.js +24 -13
  13. package/dest/index.d.ts +1 -1
  14. package/dest/job/epoch-proving-job-data.d.ts +8 -6
  15. package/dest/job/epoch-proving-job-data.d.ts.map +1 -1
  16. package/dest/job/epoch-proving-job-data.js +25 -18
  17. package/dest/job/epoch-proving-job.d.ts +11 -16
  18. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  19. package/dest/job/epoch-proving-job.js +493 -77
  20. package/dest/metrics.d.ts +4 -3
  21. package/dest/metrics.d.ts.map +1 -1
  22. package/dest/metrics.js +9 -3
  23. package/dest/monitors/epoch-monitor.d.ts +5 -2
  24. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  25. package/dest/monitors/epoch-monitor.js +393 -10
  26. package/dest/monitors/index.d.ts +1 -1
  27. package/dest/prover-node-publisher.d.ts +9 -10
  28. package/dest/prover-node-publisher.d.ts.map +1 -1
  29. package/dest/prover-node-publisher.js +51 -53
  30. package/dest/prover-node.d.ts +8 -7
  31. package/dest/prover-node.d.ts.map +1 -1
  32. package/dest/prover-node.js +435 -50
  33. package/dest/prover-publisher-factory.d.ts +6 -2
  34. package/dest/prover-publisher-factory.d.ts.map +1 -1
  35. package/dest/prover-publisher-factory.js +6 -0
  36. package/dest/test/index.d.ts +1 -1
  37. package/dest/test/index.d.ts.map +1 -1
  38. package/package.json +26 -25
  39. package/src/bin/run-failed-epoch.ts +2 -2
  40. package/src/config.ts +33 -30
  41. package/src/factory.ts +26 -20
  42. package/src/job/epoch-proving-job-data.ts +31 -25
  43. package/src/job/epoch-proving-job.ts +138 -82
  44. package/src/metrics.ts +16 -4
  45. package/src/monitors/epoch-monitor.ts +15 -5
  46. package/src/prover-node-publisher.ts +74 -73
  47. package/src/prover-node.ts +52 -45
  48. package/src/prover-publisher-factory.ts +12 -1
@@ -1,21 +1,18 @@
1
- import { type BatchedBlob, FinalBlobAccumulatorPublicInputs } from '@aztec/blob-lib';
1
+ import { BatchedBlob, getEthBlobEvaluationInputs } from '@aztec/blob-lib';
2
2
  import { AZTEC_MAX_EPOCH_DURATION } from '@aztec/constants';
3
- import {
4
- type L1TxUtils,
5
- type RollupContract,
6
- RollupContract as RollupContractClass,
7
- type ViemCommitteeAttestation,
8
- } from '@aztec/ethereum';
3
+ import type { RollupContract, ViemCommitteeAttestation } from '@aztec/ethereum/contracts';
4
+ import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
9
5
  import { makeTuple } from '@aztec/foundation/array';
6
+ import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
10
7
  import { areArraysEqual } from '@aztec/foundation/collection';
8
+ import { Fr } from '@aztec/foundation/curves/bn254';
11
9
  import { EthAddress } from '@aztec/foundation/eth-address';
12
- import { Fr } from '@aztec/foundation/fields';
13
10
  import { createLogger } from '@aztec/foundation/log';
14
11
  import type { Tuple } from '@aztec/foundation/serialize';
15
- import { InterruptibleSleep } from '@aztec/foundation/sleep';
16
12
  import { Timer } from '@aztec/foundation/timer';
17
13
  import { RollupAbi } from '@aztec/l1-artifacts';
18
14
  import type { PublisherConfig, TxSenderConfig } from '@aztec/sequencer-client';
15
+ import { CommitteeAttestation, CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
19
16
  import type { Proof } from '@aztec/stdlib/proofs';
20
17
  import type { FeeRecipient, RootRollupPublicInputs } from '@aztec/stdlib/rollup';
21
18
  import type { L1PublishProofStats } from '@aztec/stdlib/stats';
@@ -39,8 +36,6 @@ export type L1SubmitEpochProofArgs = {
39
36
  };
40
37
 
41
38
  export class ProverNodePublisher {
42
- private interruptibleSleep = new InterruptibleSleep();
43
- private sleepTimeMs: number;
44
39
  private interrupted = false;
45
40
  private metrics: ProverNodePublisherMetrics;
46
41
 
@@ -58,8 +53,6 @@ export class ProverNodePublisher {
58
53
  telemetry?: TelemetryClient;
59
54
  },
60
55
  ) {
61
- this.sleepTimeMs = config?.l1PublishRetryIntervalMS ?? 60_000;
62
-
63
56
  const telemetry = deps.telemetry ?? getTelemetryClient();
64
57
 
65
58
  this.metrics = new ProverNodePublisherMetrics(telemetry, 'ProverNode');
@@ -80,12 +73,13 @@ export class ProverNodePublisher {
80
73
  */
81
74
  public interrupt() {
82
75
  this.interrupted = true;
83
- this.interruptibleSleep.interrupt();
76
+ this.l1TxUtils.interrupt();
84
77
  }
85
78
 
86
79
  /** Restarts the publisher after calling `interrupt`. */
87
80
  public restart() {
88
81
  this.interrupted = false;
82
+ this.l1TxUtils.restart();
89
83
  }
90
84
 
91
85
  public getSenderAddress() {
@@ -93,16 +87,17 @@ export class ProverNodePublisher {
93
87
  }
94
88
 
95
89
  public async submitEpochProof(args: {
96
- epochNumber: number;
97
- fromBlock: number;
98
- toBlock: number;
90
+ epochNumber: EpochNumber;
91
+ fromCheckpoint: CheckpointNumber;
92
+ toCheckpoint: CheckpointNumber;
99
93
  publicInputs: RootRollupPublicInputs;
100
94
  proof: Proof;
101
95
  batchedBlobInputs: BatchedBlob;
102
96
  attestations: ViemCommitteeAttestation[];
103
97
  }): Promise<boolean> {
104
- const { epochNumber, fromBlock, toBlock } = args;
105
- const ctx = { epochNumber, fromBlock, toBlock };
98
+ const { epochNumber, fromCheckpoint, toCheckpoint } = args;
99
+ const ctx = { epochNumber, fromCheckpoint, toCheckpoint };
100
+
106
101
  if (!this.interrupted) {
107
102
  const timer = new Timer();
108
103
  // Validate epoch proof range and hashes are correct before submitting
@@ -110,6 +105,7 @@ export class ProverNodePublisher {
110
105
 
111
106
  const txReceipt = await this.sendSubmitEpochProofTx(args);
112
107
  if (!txReceipt) {
108
+ this.log.error(`Failed to mine submitEpochProof tx`, undefined, ctx);
113
109
  return false;
114
110
  }
115
111
 
@@ -142,55 +138,59 @@ export class ProverNodePublisher {
142
138
  }
143
139
 
144
140
  this.metrics.recordFailedTx();
145
- this.log.error(`Rollup.submitEpochProof tx status failed ${txReceipt.transactionHash}`, undefined, ctx);
146
- await this.sleepOrInterrupted();
141
+ this.log.error(`Rollup submitEpochProof tx reverted ${txReceipt.transactionHash}`, undefined, ctx);
147
142
  }
148
143
 
149
- this.log.verbose('L2 block data syncing interrupted', ctx);
144
+ this.log.verbose('Checkpoint data syncing interrupted', ctx);
150
145
  return false;
151
146
  }
152
147
 
153
148
  private async validateEpochProofSubmission(args: {
154
- fromBlock: number;
155
- toBlock: number;
149
+ fromCheckpoint: CheckpointNumber;
150
+ toCheckpoint: CheckpointNumber;
156
151
  publicInputs: RootRollupPublicInputs;
157
152
  proof: Proof;
158
153
  batchedBlobInputs: BatchedBlob;
159
154
  attestations: ViemCommitteeAttestation[];
160
155
  }) {
161
- const { fromBlock, toBlock, publicInputs, batchedBlobInputs } = args;
156
+ const { fromCheckpoint, toCheckpoint, publicInputs, batchedBlobInputs } = args;
162
157
 
163
- // Check that the block numbers match the expected epoch to be proven
164
- const { pendingBlockNumber: pending, provenBlockNumber: proven } = await this.rollupContract.getTips();
165
- // Don't publish if proven is beyond our toBlock, pointless to do so
166
- if (proven > BigInt(toBlock)) {
167
- throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as proven block is ${proven}`);
158
+ // Check that the checkpoint numbers match the expected epoch to be proven
159
+ const { pending, proven } = await this.rollupContract.getTips();
160
+ // Don't publish if proven is beyond our toCheckpoint, pointless to do so
161
+ if (proven > toCheckpoint) {
162
+ throw new Error(
163
+ `Cannot submit epoch proof for ${fromCheckpoint}-${toCheckpoint} as proven checkpoint is ${proven}`,
164
+ );
168
165
  }
169
- // toBlock can't be greater than pending
170
- if (toBlock > pending) {
171
- throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as pending block is ${pending}`);
166
+ // toCheckpoint can't be greater than pending
167
+ if (toCheckpoint > pending) {
168
+ throw new Error(
169
+ `Cannot submit epoch proof for ${fromCheckpoint}-${toCheckpoint} as pending checkpoint is ${pending}`,
170
+ );
172
171
  }
173
172
 
174
- // Check the archive for the immediate block before the epoch
175
- const blockLog = await this.rollupContract.getBlock(BigInt(fromBlock - 1));
176
- if (publicInputs.previousArchiveRoot.toString() !== blockLog.archive) {
173
+ // Check the archive for the immediate checkpoint before the epoch
174
+ const checkpointLog = await this.rollupContract.getCheckpoint(CheckpointNumber(fromCheckpoint - 1));
175
+ if (!publicInputs.previousArchiveRoot.equals(checkpointLog.archive)) {
177
176
  throw new Error(
178
- `Previous archive root mismatch: ${publicInputs.previousArchiveRoot.toString()} !== ${blockLog.archive}`,
177
+ `Previous archive root mismatch: ${publicInputs.previousArchiveRoot.toString()} !== ${checkpointLog.archive.toString()}`,
179
178
  );
180
179
  }
181
180
 
182
- // Check the archive for the last block in the epoch
183
- const endBlockLog = await this.rollupContract.getBlock(BigInt(toBlock));
184
- if (publicInputs.endArchiveRoot.toString() !== endBlockLog.archive) {
181
+ // Check the archive for the last checkpoint in the epoch
182
+ const endCheckpointLog = await this.rollupContract.getCheckpoint(toCheckpoint);
183
+ if (!publicInputs.endArchiveRoot.equals(endCheckpointLog.archive)) {
185
184
  throw new Error(
186
- `End archive root mismatch: ${publicInputs.endArchiveRoot.toString()} !== ${endBlockLog.archive}`,
185
+ `End archive root mismatch: ${publicInputs.endArchiveRoot.toString()} !== ${endCheckpointLog.archive.toString()}`,
187
186
  );
188
187
  }
189
188
 
190
189
  // Check the batched blob inputs from the root rollup against the batched blob computed in ts
191
- if (!publicInputs.blobPublicInputs.equals(FinalBlobAccumulatorPublicInputs.fromBatchedBlob(batchedBlobInputs))) {
190
+ const finalBlobAccumulator = batchedBlobInputs.toFinalBlobAccumulator();
191
+ if (!publicInputs.blobPublicInputs.equals(finalBlobAccumulator)) {
192
192
  throw new Error(
193
- `Batched blob mismatch: ${inspect(publicInputs.blobPublicInputs)} !== ${inspect(FinalBlobAccumulatorPublicInputs.fromBatchedBlob(batchedBlobInputs))}`,
193
+ `Batched blob mismatch: ${inspect(publicInputs.blobPublicInputs)} !== ${inspect(finalBlobAccumulator)}`,
194
194
  );
195
195
  }
196
196
 
@@ -200,7 +200,7 @@ export class ProverNodePublisher {
200
200
  );
201
201
  const argsPublicInputs = [...publicInputs.toFields()];
202
202
 
203
- if (!areArraysEqual(rollupPublicInputs.map(Fr.fromHexString), argsPublicInputs, (a, b) => a.equals(b))) {
203
+ if (!areArraysEqual(rollupPublicInputs, argsPublicInputs, (a, b) => a.equals(b))) {
204
204
  const fmt = (inputs: Fr[] | readonly string[]) => inputs.map(x => x.toString()).join(', ');
205
205
  throw new Error(
206
206
  `Root rollup public inputs mismatch:\nRollup: ${fmt(rollupPublicInputs)}\nComputed:${fmt(argsPublicInputs)}`,
@@ -209,8 +209,8 @@ export class ProverNodePublisher {
209
209
  }
210
210
 
211
211
  private async sendSubmitEpochProofTx(args: {
212
- fromBlock: number;
213
- toBlock: number;
212
+ fromCheckpoint: CheckpointNumber;
213
+ toCheckpoint: CheckpointNumber;
214
214
  publicInputs: RootRollupPublicInputs;
215
215
  proof: Proof;
216
216
  batchedBlobInputs: BatchedBlob;
@@ -220,8 +220,8 @@ export class ProverNodePublisher {
220
220
 
221
221
  this.log.info(`Submitting epoch proof to L1 rollup contract`, {
222
222
  proofSize: args.proof.withoutPublicInputs().length,
223
- fromBlock: args.fromBlock,
224
- toBlock: args.toBlock,
223
+ fromCheckpoint: args.fromCheckpoint,
224
+ toCheckpoint: args.toCheckpoint,
225
225
  });
226
226
  const data = encodeFunctionData({
227
227
  abi: RollupAbi,
@@ -230,53 +230,56 @@ export class ProverNodePublisher {
230
230
  });
231
231
  try {
232
232
  const { receipt } = await this.l1TxUtils.sendAndMonitorTransaction({ to: this.rollupContract.address, data });
233
+ if (receipt.status !== 'success') {
234
+ const errorMsg = await this.l1TxUtils.tryGetErrorFromRevertedTx(
235
+ data,
236
+ {
237
+ args: [...txArgs],
238
+ functionName: 'submitEpochRootProof',
239
+ abi: RollupAbi,
240
+ address: this.rollupContract.address,
241
+ },
242
+ /*blobInputs*/ undefined,
243
+ /*stateOverride*/ [],
244
+ );
245
+ this.log.error(`Rollup submit epoch proof tx reverted with ${errorMsg ?? 'unknown error'}`);
246
+ return undefined;
247
+ }
233
248
  return receipt;
234
249
  } catch (err) {
235
250
  this.log.error(`Rollup submit epoch proof failed`, err);
236
- const errorMsg = await this.l1TxUtils.tryGetErrorFromRevertedTx(
237
- data,
238
- {
239
- args: [...txArgs],
240
- functionName: 'submitEpochRootProof',
241
- abi: RollupAbi,
242
- address: this.rollupContract.address,
243
- },
244
- /*blobInputs*/ undefined,
245
- /*stateOverride*/ [],
246
- );
247
- this.log.error(`Rollup submit epoch proof tx reverted. ${errorMsg}`);
248
251
  return undefined;
249
252
  }
250
253
  }
251
254
 
252
255
  private getEpochProofPublicInputsArgs(args: {
253
- fromBlock: number;
254
- toBlock: number;
256
+ fromCheckpoint: CheckpointNumber;
257
+ toCheckpoint: CheckpointNumber;
255
258
  publicInputs: RootRollupPublicInputs;
256
259
  batchedBlobInputs: BatchedBlob;
257
260
  attestations: ViemCommitteeAttestation[];
258
261
  }) {
259
262
  // Returns arguments for EpochProofLib.sol -> getEpochProofPublicInputs()
260
263
  return [
261
- BigInt(args.fromBlock) /*_start*/,
262
- BigInt(args.toBlock) /*_end*/,
264
+ BigInt(args.fromCheckpoint) /*_start*/,
265
+ BigInt(args.toCheckpoint) /*_end*/,
263
266
  {
264
267
  previousArchive: args.publicInputs.previousArchiveRoot.toString(),
265
268
  endArchive: args.publicInputs.endArchiveRoot.toString(),
266
- proverId: EthAddress.fromField(args.publicInputs.proverId).toString(),
269
+ proverId: EthAddress.fromField(args.publicInputs.constants.proverId).toString(),
267
270
  } /*_args*/,
268
271
  makeTuple(AZTEC_MAX_EPOCH_DURATION * 2, i =>
269
272
  i % 2 === 0
270
273
  ? args.publicInputs.fees[i / 2].recipient.toField().toString()
271
274
  : args.publicInputs.fees[(i - 1) / 2].value.toString(),
272
275
  ) /*_fees*/,
273
- args.batchedBlobInputs.getEthBlobEvaluationInputs() /*_blobPublicInputs*/,
276
+ getEthBlobEvaluationInputs(args.batchedBlobInputs) /*_blobPublicInputs*/,
274
277
  ] as const;
275
278
  }
276
279
 
277
280
  private getSubmitEpochProofArgs(args: {
278
- fromBlock: number;
279
- toBlock: number;
281
+ fromCheckpoint: CheckpointNumber;
282
+ toCheckpoint: CheckpointNumber;
280
283
  publicInputs: RootRollupPublicInputs;
281
284
  proof: Proof;
282
285
  batchedBlobInputs: BatchedBlob;
@@ -290,13 +293,11 @@ export class ProverNodePublisher {
290
293
  end: argsArray[1],
291
294
  args: argsArray[2],
292
295
  fees: argsArray[3],
293
- attestations: RollupContractClass.packAttestations(args.attestations),
296
+ attestations: new CommitteeAttestationsAndSigners(
297
+ args.attestations.map(a => CommitteeAttestation.fromViem(a)),
298
+ ).getPackedAttestations(),
294
299
  blobInputs: argsArray[4],
295
300
  proof: proofHex,
296
301
  };
297
302
  }
298
-
299
- protected async sleepOrInterrupted() {
300
- await this.interruptibleSleep.sleep(this.sleepTimeMs);
301
- }
302
303
  }
@@ -1,14 +1,16 @@
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 { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
3
4
  import { assertRequired, compact, pick, sum } from '@aztec/foundation/collection';
5
+ import type { Fr } from '@aztec/foundation/curves/bn254';
4
6
  import { memoize } from '@aztec/foundation/decorators';
5
- import type { Fr } from '@aztec/foundation/fields';
6
7
  import { createLogger } from '@aztec/foundation/log';
7
8
  import { DateProvider } from '@aztec/foundation/timer';
8
9
  import type { DataStoreConfig } from '@aztec/kv-store/config';
9
10
  import type { P2PClient } from '@aztec/p2p';
10
11
  import { PublicProcessorFactory } from '@aztec/simulator/server';
11
- import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
12
+ import type { L2BlockSource } from '@aztec/stdlib/block';
13
+ import type { Checkpoint } from '@aztec/stdlib/checkpoint';
12
14
  import type { ChainConfig } from '@aztec/stdlib/config';
13
15
  import type { ContractDataSource } from '@aztec/stdlib/contract';
14
16
  import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
@@ -87,6 +89,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
87
89
  txGatheringMaxParallelRequestsPerNode: 100,
88
90
  txGatheringTimeoutMs: 120_000,
89
91
  proverNodeFailedEpochStore: undefined,
92
+ proverNodeEpochProvingDelayMs: undefined,
90
93
  ...compact(config),
91
94
  };
92
95
 
@@ -113,7 +116,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
113
116
  * @param epochNumber - The epoch number that was just completed.
114
117
  * @returns false if there is an error, true otherwise
115
118
  */
116
- async handleEpochReadyToProve(epochNumber: bigint): Promise<boolean> {
119
+ async handleEpochReadyToProve(epochNumber: EpochNumber): Promise<boolean> {
117
120
  try {
118
121
  this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
119
122
  jobs: Array.from(this.jobs.values()).map(job => `${job.getEpochNumber()}:${job.getId()}`),
@@ -143,6 +146,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
143
146
  */
144
147
  async start() {
145
148
  this.epochsMonitor.start(this);
149
+ await this.publisherFactory.start();
146
150
  this.publisher = await this.publisherFactory.create();
147
151
  await this.rewardsMetrics.start();
148
152
  this.l1Metrics.start();
@@ -158,6 +162,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
158
162
  await this.prover.stop();
159
163
  await tryStop(this.p2pClient);
160
164
  await tryStop(this.l2BlockSource);
165
+ await tryStop(this.publisherFactory);
161
166
  this.publisher?.interrupt();
162
167
  await Promise.all(Array.from(this.jobs.values()).map(job => job.stop()));
163
168
  await this.worldState.stop();
@@ -181,8 +186,8 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
181
186
  /**
182
187
  * Starts a proving process and returns immediately.
183
188
  */
184
- public async startProof(epochNumber: number | bigint) {
185
- const job = await this.createProvingJob(BigInt(epochNumber), { skipEpochCheck: true });
189
+ public async startProof(epochNumber: EpochNumber) {
190
+ const job = await this.createProvingJob(epochNumber, { skipEpochCheck: true });
186
191
  void this.runJob(job);
187
192
  }
188
193
 
@@ -235,21 +240,20 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
235
240
  /**
236
241
  * Returns an array of jobs being processed.
237
242
  */
238
- public getJobs(): Promise<{ uuid: string; status: EpochProvingJobState; epochNumber: number }[]> {
243
+ public getJobs(): Promise<{ uuid: string; status: EpochProvingJobState; epochNumber: EpochNumber }[]> {
239
244
  return Promise.resolve(
240
245
  Array.from(this.jobs.entries()).map(([uuid, job]) => ({
241
246
  uuid,
242
247
  status: job.getState(),
243
- epochNumber: Number(job.getEpochNumber()),
248
+ epochNumber: job.getEpochNumber(),
244
249
  })),
245
250
  );
246
251
  }
247
252
 
248
253
  protected async getActiveJobsForEpoch(
249
- epochBigInt: bigint,
254
+ epochNumber: EpochNumber,
250
255
  ): Promise<{ uuid: string; status: EpochProvingJobState }[]> {
251
256
  const jobs = await this.getJobs();
252
- const epochNumber = Number(epochBigInt);
253
257
  return jobs.filter(job => job.epochNumber === epochNumber && !EpochProvingJobTerminalState.includes(job.status));
254
258
  }
255
259
 
@@ -260,18 +264,21 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
260
264
  }
261
265
  }
262
266
 
263
- @trackSpan('ProverNode.createProvingJob', epochNumber => ({ [Attributes.EPOCH_NUMBER]: Number(epochNumber) }))
264
- private async createProvingJob(epochNumber: bigint, opts: { skipEpochCheck?: boolean } = {}) {
267
+ @trackSpan('ProverNode.createProvingJob', epochNumber => ({ [Attributes.EPOCH_NUMBER]: epochNumber }))
268
+ private async createProvingJob(epochNumber: EpochNumber, opts: { skipEpochCheck?: boolean } = {}) {
265
269
  this.checkMaximumPendingJobs();
266
270
 
267
271
  this.publisher = await this.publisherFactory.create();
268
272
 
269
273
  // Gather all data for this epoch
270
274
  const epochData = await this.gatherEpochData(epochNumber);
271
-
272
- const fromBlock = epochData.blocks[0].number;
273
- const toBlock = epochData.blocks.at(-1)!.number;
274
- this.log.verbose(`Creating proving job for epoch ${epochNumber} for block range ${fromBlock} to ${toBlock}`);
275
+ const fromCheckpoint = epochData.checkpoints[0].number;
276
+ const toCheckpoint = epochData.checkpoints.at(-1)!.number;
277
+ const fromBlock = epochData.checkpoints[0].blocks[0].number;
278
+ const toBlock = epochData.checkpoints.at(-1)!.blocks.at(-1)!.number;
279
+ this.log.verbose(
280
+ `Creating proving job for epoch ${epochNumber} for checkpoint range ${fromCheckpoint} to ${toCheckpoint} and block range ${fromBlock} to ${toBlock}`,
281
+ );
275
282
 
276
283
  // Fast forward world state to right before the target block and get a fork
277
284
  await this.worldState.syncImmediate(toBlock);
@@ -286,7 +293,6 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
286
293
  // Set deadline for this job to run. It will abort if it takes too long.
287
294
  const deadlineTs = getProofSubmissionDeadlineTimestamp(epochNumber, await this.getL1Constants());
288
295
  const deadline = new Date(Number(deadlineTs) * 1000);
289
-
290
296
  const job = this.doCreateEpochProvingJob(epochData, deadline, publicProcessorFactory, this.publisher, opts);
291
297
  this.jobs.set(job.getId(), job);
292
298
  return job;
@@ -297,30 +303,32 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
297
303
  return this.l2BlockSource.getL1Constants();
298
304
  }
299
305
 
300
- @trackSpan('ProverNode.gatherEpochData', epochNumber => ({ [Attributes.EPOCH_NUMBER]: Number(epochNumber) }))
301
- private async gatherEpochData(epochNumber: bigint): Promise<EpochProvingJobData> {
302
- const blocks = await this.gatherBlocks(epochNumber);
303
- const txArray = await this.gatherTxs(epochNumber, blocks);
306
+ @trackSpan('ProverNode.gatherEpochData', epochNumber => ({ [Attributes.EPOCH_NUMBER]: epochNumber }))
307
+ private async gatherEpochData(epochNumber: EpochNumber): Promise<EpochProvingJobData> {
308
+ const checkpoints = await this.gatherCheckpoints(epochNumber);
309
+ const txArray = await this.gatherTxs(epochNumber, checkpoints);
304
310
  const txs = new Map<string, Tx>(txArray.map(tx => [tx.getTxHash().toString(), tx]));
305
- const l1ToL2Messages = await this.gatherMessages(epochNumber, blocks);
306
- const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, blocks[0]);
307
- const [lastBlock] = await this.l2BlockSource.getPublishedBlocks(blocks.at(-1)!.number, 1);
308
- const attestations = lastBlock?.attestations ?? [];
311
+ const l1ToL2Messages = await this.gatherMessages(epochNumber, checkpoints);
312
+ const [firstBlock] = checkpoints[0].blocks;
313
+ const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, firstBlock.number - 1);
314
+ const [lastPublishedCheckpoint] = await this.l2BlockSource.getPublishedCheckpoints(checkpoints.at(-1)!.number, 1);
315
+ const attestations = lastPublishedCheckpoint?.attestations ?? [];
309
316
 
310
- return { blocks, txs, l1ToL2Messages, epochNumber, previousBlockHeader, attestations };
317
+ return { checkpoints, txs, l1ToL2Messages, epochNumber, previousBlockHeader, attestations };
311
318
  }
312
319
 
313
- private async gatherBlocks(epochNumber: bigint) {
314
- const blocks = await this.l2BlockSource.getBlocksForEpoch(epochNumber);
315
- if (blocks.length === 0) {
320
+ private async gatherCheckpoints(epochNumber: EpochNumber) {
321
+ const checkpoints = await this.l2BlockSource.getCheckpointsForEpoch(epochNumber);
322
+ if (checkpoints.length === 0) {
316
323
  throw new EmptyEpochError(epochNumber);
317
324
  }
318
- return blocks;
325
+ return checkpoints;
319
326
  }
320
327
 
321
- private async gatherTxs(epochNumber: bigint, blocks: L2Block[]) {
328
+ private async gatherTxs(epochNumber: EpochNumber, checkpoints: Checkpoint[]) {
322
329
  const deadline = new Date(this.dateProvider.now() + this.config.txGatheringTimeoutMs);
323
330
  const txProvider = this.p2pClient.getTxProvider();
331
+ const blocks = checkpoints.flatMap(checkpoint => checkpoint.blocks);
324
332
  const txsByBlock = await Promise.all(blocks.map(block => txProvider.getTxsForBlock(block, { deadline })));
325
333
  const txs = txsByBlock.map(({ txs }) => txs).flat();
326
334
  const missingTxs = txsByBlock.map(({ missingTxs }) => missingTxs).flat();
@@ -333,25 +341,24 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
333
341
  throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxs.map(hash => hash.toString()).join(', ')}`);
334
342
  }
335
343
 
336
- private async gatherMessages(epochNumber: bigint, blocks: L2Block[]) {
337
- const messages = await Promise.all(blocks.map(b => this.l1ToL2MessageSource.getL1ToL2Messages(b.number)));
344
+ private async gatherMessages(epochNumber: EpochNumber, checkpoints: Checkpoint[]) {
345
+ const messages = await Promise.all(checkpoints.map(c => this.l1ToL2MessageSource.getL1ToL2Messages(c.number)));
338
346
  const messageCount = sum(messages.map(m => m.length));
339
347
  this.log.verbose(`Gathered all ${messageCount} messages for epoch ${epochNumber}`, { epochNumber });
340
- const messagesByBlock: Record<number, Fr[]> = {};
341
- for (let i = 0; i < blocks.length; i++) {
342
- messagesByBlock[blocks[i].number] = messages[i];
348
+ const messagesByCheckpoint: Record<CheckpointNumber, Fr[]> = {};
349
+ for (let i = 0; i < checkpoints.length; i++) {
350
+ messagesByCheckpoint[checkpoints[i].number] = messages[i];
343
351
  }
344
- return messagesByBlock;
352
+ return messagesByCheckpoint;
345
353
  }
346
354
 
347
- private async gatherPreviousBlockHeader(epochNumber: bigint, initialBlock: L2Block) {
348
- const previousBlockNumber = initialBlock.number - 1;
355
+ private async gatherPreviousBlockHeader(epochNumber: EpochNumber, previousBlockNumber: number) {
349
356
  const header = await (previousBlockNumber === 0
350
357
  ? this.worldState.getCommitted().getInitialHeader()
351
- : this.l2BlockSource.getBlockHeader(previousBlockNumber));
358
+ : this.l2BlockSource.getBlockHeader(BlockNumber(previousBlockNumber)));
352
359
 
353
360
  if (!header) {
354
- throw new Error(`Previous block header ${initialBlock.number} not found for proving epoch ${epochNumber}`);
361
+ throw new Error(`Previous block header ${previousBlockNumber} not found for proving epoch ${epochNumber}`);
355
362
  }
356
363
 
357
364
  this.log.verbose(`Gathered previous block header ${header.getBlockNumber()} for epoch ${epochNumber}`);
@@ -366,7 +373,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
366
373
  publisher: ProverNodePublisher,
367
374
  opts: { skipEpochCheck?: boolean } = {},
368
375
  ) {
369
- const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit } = this.config;
376
+ const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit, proverNodeDisableProofPublish } = this.config;
370
377
  return new EpochProvingJob(
371
378
  data,
372
379
  this.worldState,
@@ -376,7 +383,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
376
383
  this.l2BlockSource,
377
384
  this.jobMetrics,
378
385
  deadline,
379
- { parallelBlockLimit, ...opts },
386
+ { parallelBlockLimit, skipSubmitProof: proverNodeDisableProofPublish, ...opts },
380
387
  );
381
388
  }
382
389
 
@@ -388,7 +395,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
388
395
  private validateConfig() {
389
396
  if (
390
397
  this.config.proverNodeFailedEpochStore &&
391
- (!this.config.dataDirectory || !this.config.l1ChainId || !this.config.rollupVersion)
398
+ (!this.config.dataDirectory || !this.config.l1ChainId || this.config.rollupVersion === undefined)
392
399
  ) {
393
400
  this.log.warn(
394
401
  `Invalid prover-node config (missing dataDirectory, l1ChainId, or rollupVersion)`,
@@ -402,7 +409,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
402
409
  }
403
410
 
404
411
  class EmptyEpochError extends Error {
405
- constructor(epochNumber: bigint) {
412
+ constructor(epochNumber: EpochNumber) {
406
413
  super(`No blocks found for epoch ${epochNumber}`);
407
414
  this.name = 'EmptyEpochError';
408
415
  }
@@ -1,4 +1,6 @@
1
- import type { L1TxUtils, PublisherManager, RollupContract } from '@aztec/ethereum';
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';
2
4
  import type { PublisherConfig, TxSenderConfig } from '@aztec/sequencer-client';
3
5
  import type { TelemetryClient } from '@aztec/telemetry-client';
4
6
 
@@ -13,6 +15,15 @@ export class ProverPublisherFactory {
13
15
  telemetry?: TelemetryClient;
14
16
  },
15
17
  ) {}
18
+
19
+ public async start() {
20
+ await this.deps.publisherManager.loadState();
21
+ }
22
+
23
+ public stop() {
24
+ this.deps.publisherManager.interrupt();
25
+ }
26
+
16
27
  /**
17
28
  * Creates a new Prover Publisher instance.
18
29
  * @returns A new ProverNodePublisher instance.