@aztec/prover-node 0.81.0 → 0.82.0

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.
@@ -1,6 +1,6 @@
1
1
  import type { PublicProcessorFactory } from '@aztec/simulator/server';
2
2
  import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
3
- import { type EpochProver, type EpochProvingJobState, type ForkMerkleTreeOperations } from '@aztec/stdlib/interfaces/server';
3
+ import { type EpochProver, type EpochProvingJobState, EpochProvingJobTerminalState, type ForkMerkleTreeOperations } from '@aztec/stdlib/interfaces/server';
4
4
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
5
5
  import type { Tx } from '@aztec/stdlib/tx';
6
6
  import { type Traceable, type Tracer } from '@aztec/telemetry-client';
@@ -24,16 +24,16 @@ export declare class EpochProvingJob implements Traceable {
24
24
  private metrics;
25
25
  private deadline;
26
26
  private config;
27
- private cleanUp;
28
27
  private state;
29
28
  private log;
30
29
  private uuid;
31
30
  private runPromise;
31
+ private epochCheckPromise;
32
32
  private deadlineTimeoutHandler;
33
33
  readonly tracer: Tracer;
34
34
  constructor(dbProvider: ForkMerkleTreeOperations, epochNumber: bigint, blocks: L2Block[], txs: Tx[], prover: EpochProver, publicProcessorFactory: PublicProcessorFactory, publisher: ProverNodePublisher, l2BlockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, metrics: ProverNodeMetrics, deadline: Date | undefined, config?: {
35
35
  parallelBlockLimit: number;
36
- }, cleanUp?: (job: EpochProvingJob) => Promise<void>);
36
+ });
37
37
  getId(): string;
38
38
  getState(): EpochProvingJobState;
39
39
  getEpochNumber(): bigint;
@@ -43,8 +43,13 @@ export declare class EpochProvingJob implements Traceable {
43
43
  run(): Promise<void>;
44
44
  private progressState;
45
45
  private checkState;
46
- stop(state?: EpochProvingJobState): Promise<void>;
46
+ stop(state?: EpochProvingJobTerminalState): Promise<void>;
47
47
  private scheduleDeadlineStop;
48
+ /**
49
+ * Kicks off a running promise that queries the archiver for the set of L2 blocks of the current epoch.
50
+ * If those changed, stops the proving job with a `rerun` state, so the node re-enqueues it.
51
+ */
52
+ private scheduleEpochCheck;
48
53
  private getBlockHeader;
49
54
  private getTxs;
50
55
  private getL1ToL2Messages;
@@ -1 +1 @@
1
- {"version":3,"file":"epoch-proving-job.d.ts","sourceRoot":"","sources":["../../src/job/epoch-proving-job.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAmB,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EAEzB,KAAK,wBAAwB,EAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAe,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,MAAM,EAAa,MAAM,yBAAyB,CAAC;AAI7F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEvE;;;;GAIG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAW7C,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IAtBjB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,GAAG,CAAiD;IAC5D,OAAO,CAAC,IAAI,CAAS;IAErB,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,sBAAsB,CAA6B;IAE3D,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAGrB,UAAU,EAAE,wBAAwB,EACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,OAAO,EAAE,EACjB,GAAG,EAAE,EAAE,EAAE,EACT,MAAM,EAAE,WAAW,EACnB,sBAAsB,EAAE,sBAAsB,EAC9C,SAAS,EAAE,mBAAmB,EAC9B,aAAa,EAAE,aAAa,EAC5B,mBAAmB,EAAE,mBAAmB,EACxC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,IAAI,GAAG,SAAS,EAC1B,MAAM,GAAE;QAAE,kBAAkB,EAAE,MAAM,CAAA;KAA+B,EACnE,OAAO,GAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAA2B;IAM7E,KAAK,IAAI,MAAM;IAIf,QAAQ,IAAI,oBAAoB;IAIhC,cAAc,IAAI,MAAM;IAI/B;;OAEG;IAIU,GAAG;IAgGhB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,UAAU;IAML,IAAI,CAAC,KAAK,GAAE,oBAAgC;IASzD,OAAO,CAAC,oBAAoB;YAqBd,cAAc;YAOd,MAAM;IAQpB,OAAO,CAAC,iBAAiB;YAIX,UAAU;CAmBzB;AASD,OAAO,EAAE,KAAK,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"epoch-proving-job.d.ts","sourceRoot":"","sources":["../../src/job/epoch-proving-job.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAmB,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,4BAA4B,EAC5B,KAAK,wBAAwB,EAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAe,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,MAAM,EAAa,MAAM,yBAAyB,CAAC;AAI7F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEvE;;;;GAIG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAY7C,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IAtBhB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,GAAG,CAAiD;IAC5D,OAAO,CAAC,IAAI,CAAS;IAErB,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,sBAAsB,CAA6B;IAE3D,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAGrB,UAAU,EAAE,wBAAwB,EACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,OAAO,EAAE,EACjB,GAAG,EAAE,EAAE,EAAE,EACT,MAAM,EAAE,WAAW,EACnB,sBAAsB,EAAE,sBAAsB,EAC9C,SAAS,EAAE,mBAAmB,EAC9B,aAAa,EAAE,aAAa,EAC5B,mBAAmB,EAAE,mBAAmB,EACxC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,IAAI,GAAG,SAAS,EAC1B,MAAM,GAAE;QAAE,kBAAkB,EAAE,MAAM,CAAA;KAA+B;IAMtE,KAAK,IAAI,MAAM;IAIf,QAAQ,IAAI,oBAAoB;IAIhC,cAAc,IAAI,MAAM;IAI/B;;OAEG;IAIU,GAAG;IAqGhB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,UAAU;IAML,IAAI,CAAC,KAAK,GAAE,4BAAwC;IASjE,OAAO,CAAC,oBAAoB;IAoB5B;;;OAGG;YACW,kBAAkB;YA2BlB,cAAc;YAOd,MAAM;IAQpB,OAAO,CAAC,iBAAiB;YAIX,UAAU;CAmBzB;AASD,OAAO,EAAE,KAAK,oBAAoB,EAAE,CAAC"}
@@ -6,7 +6,7 @@ function _ts_decorate(decorators, target, key, desc) {
6
6
  }
7
7
  import { asyncPool } from '@aztec/foundation/async-pool';
8
8
  import { createLogger } from '@aztec/foundation/log';
9
- import { promiseWithResolvers } from '@aztec/foundation/promise';
9
+ import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
10
10
  import { Timer } from '@aztec/foundation/timer';
11
11
  import { EpochProvingJobTerminalState } from '@aztec/stdlib/interfaces/server';
12
12
  import { Attributes, trackSpan } from '@aztec/telemetry-client';
@@ -28,16 +28,16 @@ import * as crypto from 'node:crypto';
28
28
  metrics;
29
29
  deadline;
30
30
  config;
31
- cleanUp;
32
31
  state;
33
32
  log;
34
33
  uuid;
35
34
  runPromise;
35
+ epochCheckPromise;
36
36
  deadlineTimeoutHandler;
37
37
  tracer;
38
38
  constructor(dbProvider, epochNumber, blocks, txs, prover, publicProcessorFactory, publisher, l2BlockSource, l1ToL2MessageSource, metrics, deadline, config = {
39
39
  parallelBlockLimit: 32
40
- }, cleanUp = ()=>Promise.resolve()){
40
+ }){
41
41
  this.dbProvider = dbProvider;
42
42
  this.epochNumber = epochNumber;
43
43
  this.blocks = blocks;
@@ -50,7 +50,6 @@ import * as crypto from 'node:crypto';
50
50
  this.metrics = metrics;
51
51
  this.deadline = deadline;
52
52
  this.config = config;
53
- this.cleanUp = cleanUp;
54
53
  this.state = 'initialized';
55
54
  this.log = createLogger('prover-node:epoch-proving-job');
56
55
  this.uuid = crypto.randomUUID();
@@ -69,6 +68,7 @@ import * as crypto from 'node:crypto';
69
68
  * Proves the given epoch and submits the proof to L1.
70
69
  */ async run() {
71
70
  this.scheduleDeadlineStop();
71
+ await this.scheduleEpochCheck();
72
72
  const epochNumber = Number(this.epochNumber);
73
73
  const epochSizeBlocks = this.blocks.length;
74
74
  const epochSizeTxs = this.blocks.reduce((total, current)=>total + current.body.txEffects.length, 0);
@@ -152,7 +152,8 @@ import * as crypto from 'node:crypto';
152
152
  if (err && err.name === 'HaltExecutionError') {
153
153
  this.log.warn(`Halted execution of epoch ${epochNumber} prover job`, {
154
154
  uuid: this.uuid,
155
- epochNumber
155
+ epochNumber,
156
+ details: err.message
156
157
  });
157
158
  return;
158
159
  }
@@ -163,7 +164,7 @@ import * as crypto from 'node:crypto';
163
164
  this.state = 'failed';
164
165
  } finally{
165
166
  clearTimeout(this.deadlineTimeoutHandler);
166
- await this.cleanUp(this);
167
+ await this.epochCheckPromise?.stop();
167
168
  await this.prover.stop();
168
169
  resolve();
169
170
  }
@@ -173,7 +174,7 @@ import * as crypto from 'node:crypto';
173
174
  this.state = state;
174
175
  }
175
176
  checkState() {
176
- if (this.state === 'timed-out' || this.state === 'stopped' || this.state === 'failed') {
177
+ if (this.state === 'timed-out' || this.state === 'stopped' || this.state === 'failed' || this.state === 'reorg') {
177
178
  throw new HaltExecutionError(this.state);
178
179
  }
179
180
  }
@@ -209,6 +210,27 @@ import * as crypto from 'node:crypto';
209
210
  }, timeout);
210
211
  }
211
212
  }
213
+ /**
214
+ * Kicks off a running promise that queries the archiver for the set of L2 blocks of the current epoch.
215
+ * If those changed, stops the proving job with a `rerun` state, so the node re-enqueues it.
216
+ */ async scheduleEpochCheck() {
217
+ const intervalMs = Math.ceil((await this.l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
218
+ this.epochCheckPromise = new RunningPromise(async ()=>{
219
+ const blocks = await this.l2BlockSource.getBlockHeadersForEpoch(this.epochNumber);
220
+ const blockHashes = await Promise.all(blocks.map((block)=>block.hash()));
221
+ const thisBlockHashes = await Promise.all(this.blocks.map((block)=>block.hash()));
222
+ if (blocks.length !== this.blocks.length || !blockHashes.every((block, i)=>block.equals(thisBlockHashes[i]))) {
223
+ this.log.warn('Epoch blocks changed underfoot', {
224
+ uuid: this.uuid,
225
+ epochNumber: this.epochNumber,
226
+ oldBlockHashes: thisBlockHashes,
227
+ newBlockHashes: blockHashes
228
+ });
229
+ void this.stop('reorg');
230
+ }
231
+ }, this.log, intervalMs).start();
232
+ this.log.verbose(`Scheduled epoch check for epoch ${this.epochNumber} every ${intervalMs}ms`);
233
+ }
212
234
  /* Returns the header for the given block number, or the genesis block for block zero. */ async getBlockHeader(blockNumber) {
213
235
  if (blockNumber === 0) {
214
236
  return (await this.dbProvider.fork()).getInitialHeader();
@@ -249,8 +271,9 @@ _ts_decorate([
249
271
  })
250
272
  ], EpochProvingJob.prototype, "run", null);
251
273
  class HaltExecutionError extends Error {
274
+ state;
252
275
  constructor(state){
253
- super(`Halted execution due to state ${state}`);
276
+ super(`Halted execution due to state ${state}`), this.state = state;
254
277
  this.name = 'HaltExecutionError';
255
278
  }
256
279
  }
@@ -1 +1 @@
1
- {"version":3,"file":"prover-node-publisher.d.ts","sourceRoot":"","sources":["../src/prover-node-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAE9C,OAAO,EAAE,KAAK,KAAK,EAAqB,MAAM,6BAA6B,CAAC;AAI5E,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAMnF;;GAEG;AACH,sEAAsE;AACtE,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,EAAE,CAAC;IACpB,UAAU,EAAE,EAAE,CAAC;IACf,iBAAiB,EAAE,EAAE,CAAC;IACtB,YAAY,EAAE,EAAE,CAAC;IACjB,YAAY,EAAE,EAAE,CAAC;IACjB,OAAO,EAAE,EAAE,CAAC;IACZ,QAAQ,EAAE,EAAE,CAAC;IACb,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,wBAAwB,CAAC,CAAC;IAC3D,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAoB;IAEnC,SAAS,CAAC,GAAG,yCAA+C;IAE5D,SAAS,CAAC,cAAc,EAAE,cAAc,CAAC;IAEzC,SAAgB,SAAS,EAAE,SAAS,CAAC;gBAGnC,MAAM,EAAE,cAAc,GAAG,eAAe,EACxC,IAAI,EAAE;QACJ,cAAc,EAAE,cAAc,CAAC;QAC/B,SAAS,EAAE,SAAS,CAAC;QACrB,SAAS,CAAC,EAAE,eAAe,CAAC;KAC7B;IAYH;;;;;OAKG;IACI,SAAS;IAKhB,wDAAwD;IACjD,OAAO;IAIP,gBAAgB;IAIV,gBAAgB,CAAC,IAAI,EAAE;QAClC,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,sBAAsB,CAAC;QACrC,KAAK,EAAE,KAAK,CAAC;KACd,GAAG,OAAO,CAAC,OAAO,CAAC;YAgDN,4BAA4B;YAyD5B,sBAAsB;IAoDpC,OAAO,CAAC,uBAAuB;cA+Bf,kBAAkB;CAGnC"}
1
+ {"version":3,"file":"prover-node-publisher.d.ts","sourceRoot":"","sources":["../src/prover-node-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAE9C,OAAO,EAAE,KAAK,KAAK,EAAqB,MAAM,6BAA6B,CAAC;AAI5E,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAMnF;;GAEG;AACH,sEAAsE;AACtE,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,EAAE,CAAC;IACpB,UAAU,EAAE,EAAE,CAAC;IACf,iBAAiB,EAAE,EAAE,CAAC;IACtB,YAAY,EAAE,EAAE,CAAC;IACjB,YAAY,EAAE,EAAE,CAAC;IACjB,OAAO,EAAE,EAAE,CAAC;IACZ,QAAQ,EAAE,EAAE,CAAC;IACb,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,wBAAwB,CAAC,CAAC;IAC3D,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAoB;IAEnC,SAAS,CAAC,GAAG,yCAA+C;IAE5D,SAAS,CAAC,cAAc,EAAE,cAAc,CAAC;IAEzC,SAAgB,SAAS,EAAE,SAAS,CAAC;gBAGnC,MAAM,EAAE,cAAc,GAAG,eAAe,EACxC,IAAI,EAAE;QACJ,cAAc,EAAE,cAAc,CAAC;QAC/B,SAAS,EAAE,SAAS,CAAC;QACrB,SAAS,CAAC,EAAE,eAAe,CAAC;KAC7B;IAYH;;;;;OAKG;IACI,SAAS;IAKhB,wDAAwD;IACjD,OAAO;IAIP,gBAAgB;IAIV,gBAAgB,CAAC,IAAI,EAAE;QAClC,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,sBAAsB,CAAC;QACrC,KAAK,EAAE,KAAK,CAAC;KACd,GAAG,OAAO,CAAC,OAAO,CAAC;YAgDN,4BAA4B;YA2D5B,sBAAsB;IAoDpC,OAAO,CAAC,uBAAuB;cA+Bf,kBAAkB;CAGnC"}
@@ -93,14 +93,16 @@ export class ProverNodePublisher {
93
93
  const { fromBlock, toBlock, publicInputs, proof } = args;
94
94
  // Check that the block numbers match the expected epoch to be proven
95
95
  const { pendingBlockNumber: pending, provenBlockNumber: proven } = await this.rollupContract.getTips();
96
- if (proven !== BigInt(fromBlock) - 1n) {
96
+ // Don't publish if proven is beyond our toBlock, pointless to do so
97
+ if (proven > BigInt(toBlock)) {
97
98
  throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as proven block is ${proven}`);
98
99
  }
100
+ // toBlock can't be greater than pending
99
101
  if (toBlock > pending) {
100
102
  throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as pending block is ${pending}`);
101
103
  }
102
104
  // Check the block hash and archive for the immediate block before the epoch
103
- const blockLog = await this.rollupContract.getBlock(proven);
105
+ const blockLog = await this.rollupContract.getBlock(BigInt(fromBlock - 1));
104
106
  if (publicInputs.previousArchive.root.toString() !== blockLog.archive) {
105
107
  throw new Error(`Previous archive root mismatch: ${publicInputs.previousArchive.root.toString()} !== ${blockLog.archive}`);
106
108
  }
@@ -37,11 +37,10 @@ export declare class ProverNode implements EpochMonitorHandler, ProverNodeApi, T
37
37
  protected readonly telemetryClient: TelemetryClient;
38
38
  private log;
39
39
  private dateProvider;
40
- private latestEpochWeAreProving;
41
40
  private jobs;
42
- private cachedEpochData;
43
41
  private options;
44
42
  private metrics;
43
+ private l1Metrics;
45
44
  private txFetcher;
46
45
  private lastBlockNumber;
47
46
  readonly tracer: Tracer;
@@ -62,14 +61,11 @@ export declare class ProverNode implements EpochMonitorHandler, ProverNodeApi, T
62
61
  * Stops the prover node and all its dependencies.
63
62
  */
64
63
  stop(): Promise<void>;
65
- /**
66
- * Creates a proof for a block range. Returns once the proof has been submitted to L1.
67
- */
68
- prove(epochNumber: number | bigint): Promise<void>;
69
64
  /**
70
65
  * Starts a proving process and returns immediately.
71
66
  */
72
67
  startProof(epochNumber: number | bigint): Promise<void>;
68
+ private runJob;
73
69
  /**
74
70
  * Returns the prover instance.
75
71
  */
@@ -95,7 +91,7 @@ export declare class ProverNode implements EpochMonitorHandler, ProverNodeApi, T
95
91
  private gatherBlocks;
96
92
  private gatherTxs;
97
93
  /** Extracted for testing purposes. */
98
- protected doCreateEpochProvingJob(epochNumber: bigint, deadline: Date | undefined, blocks: L2Block[], txs: Tx[], publicProcessorFactory: PublicProcessorFactory, cleanUp: () => Promise<void>): EpochProvingJob;
94
+ protected doCreateEpochProvingJob(epochNumber: bigint, deadline: Date | undefined, blocks: L2Block[], txs: Tx[], publicProcessorFactory: PublicProcessorFactory): EpochProvingJob;
99
95
  /** Extracted for testing purposes. */
100
96
  protected triggerMonitors(): Promise<void>;
101
97
  }
@@ -1 +1 @@
1
- {"version":3,"file":"prover-node.d.ts","sourceRoot":"","sources":["../src/prover-node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prover-node.d.ts","sourceRoot":"","sources":["../src/prover-node.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ import { DateProvider } from '@aztec/foundation/timer';
12
12
  import { PublicProcessorFactory } from '@aztec/simulator/server';
13
13
  import { getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
14
14
  import { EpochProvingJobTerminalState, tryStop } from '@aztec/stdlib/interfaces/server';
15
- import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
15
+ import { Attributes, L1Metrics, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
16
16
  import { EpochProvingJob } from './job/epoch-proving-job.js';
17
17
  import { ProverNodeMetrics } from './metrics.js';
18
18
  /**
@@ -32,11 +32,10 @@ import { ProverNodeMetrics } from './metrics.js';
32
32
  telemetryClient;
33
33
  log;
34
34
  dateProvider;
35
- latestEpochWeAreProving;
36
35
  jobs;
37
- cachedEpochData;
38
36
  options;
39
37
  metrics;
38
+ l1Metrics;
40
39
  txFetcher;
41
40
  lastBlockNumber;
42
41
  tracer;
@@ -53,7 +52,9 @@ import { ProverNodeMetrics } from './metrics.js';
53
52
  this.log = createLogger('prover-node');
54
53
  this.dateProvider = new DateProvider();
55
54
  this.jobs = new Map();
56
- this.cachedEpochData = undefined;
55
+ this.l1Metrics = new L1Metrics(telemetryClient.getMeter('ProverNodeL1Metrics'), publisher.l1TxUtils.publicClient, [
56
+ publisher.getSenderAddress()
57
+ ]);
57
58
  this.options = {
58
59
  pollingIntervalMs: 1_000,
59
60
  maxPendingJobs: 100,
@@ -82,13 +83,16 @@ import { ProverNodeMetrics } from './metrics.js';
82
83
  * @param epochNumber - The epoch number that was just completed.
83
84
  */ async handleEpochReadyToProve(epochNumber) {
84
85
  try {
85
- this.log.debug('jobs', JSON.stringify(this.jobs, null, 2));
86
+ this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
87
+ jobs: Array.from(this.jobs.values()).map((job)=>`${job.getEpochNumber()}:${job.getId()}`)
88
+ });
86
89
  const activeJobs = await this.getActiveJobsForEpoch(epochNumber);
87
90
  if (activeJobs.length > 0) {
88
- this.log.info(`Not starting proof for ${epochNumber} since there are active jobs`);
91
+ this.log.warn(`Not starting proof for ${epochNumber} since there are active jobs for the epoch`, {
92
+ activeJobs: activeJobs.map((job)=>job.uuid)
93
+ });
89
94
  return;
90
95
  }
91
- // TODO: we probably want to skip starting a proof if we are too far into the current epoch
92
96
  await this.startProof(epochNumber);
93
97
  } catch (err) {
94
98
  if (err instanceof EmptyEpochError) {
@@ -104,6 +108,7 @@ import { ProverNodeMetrics } from './metrics.js';
104
108
  */ start() {
105
109
  this.txFetcher.start();
106
110
  this.epochsMonitor.start(this);
111
+ this.l1Metrics.start();
107
112
  this.log.info('Started ProverNode', this.options);
108
113
  }
109
114
  /**
@@ -118,20 +123,35 @@ import { ProverNodeMetrics } from './metrics.js';
118
123
  await Promise.all(Array.from(this.jobs.values()).map((job)=>job.stop()));
119
124
  await this.worldState.stop();
120
125
  await tryStop(this.coordination);
126
+ this.l1Metrics.stop();
121
127
  await this.telemetryClient.stop();
122
128
  this.log.info('Stopped ProverNode');
123
129
  }
124
130
  /**
125
- * Creates a proof for a block range. Returns once the proof has been submitted to L1.
126
- */ async prove(epochNumber) {
127
- const job = await this.createProvingJob(BigInt(epochNumber));
128
- return job.run();
129
- }
130
- /**
131
131
  * Starts a proving process and returns immediately.
132
132
  */ async startProof(epochNumber) {
133
133
  const job = await this.createProvingJob(BigInt(epochNumber));
134
- void job.run().catch((err)=>this.log.error(`Error proving epoch ${epochNumber}`, err));
134
+ void this.runJob(job);
135
+ }
136
+ async runJob(job) {
137
+ const ctx = {
138
+ id: job.getId(),
139
+ epochNumber: job.getEpochNumber()
140
+ };
141
+ try {
142
+ await job.run();
143
+ const state = job.getState();
144
+ if (state === 'reorg') {
145
+ this.log.warn(`Running new job for epoch ${job.getEpochNumber()} due to reorg`, ctx);
146
+ await this.createProvingJob(job.getEpochNumber());
147
+ } else {
148
+ this.log.verbose(`Job for ${job.getEpochNumber()} exited with state ${state}`, ctx);
149
+ }
150
+ } catch (err) {
151
+ this.log.error(`Error proving epoch ${job.getEpochNumber()}`, err, ctx);
152
+ } finally{
153
+ this.jobs.delete(job.getId());
154
+ }
135
155
  }
136
156
  /**
137
157
  * Returns the prover instance.
@@ -161,8 +181,7 @@ import { ProverNodeMetrics } from './metrics.js';
161
181
  throw new Error(`Maximum pending proving jobs ${this.options.maxPendingJobs} reached. Cannot create new job.`);
162
182
  }
163
183
  // Gather blocks for this epoch
164
- const cachedEpochData = this.cachedEpochData?.epochNumber === epochNumber ? this.cachedEpochData : undefined;
165
- const { blocks, txs } = cachedEpochData ?? await this.gatherEpochData(epochNumber);
184
+ const { blocks, txs } = await this.gatherEpochData(epochNumber);
166
185
  const fromBlock = blocks[0].number;
167
186
  const toBlock = blocks.at(-1).number;
168
187
  // Fast forward world state to right before the target block and get a fork
@@ -170,13 +189,9 @@ import { ProverNodeMetrics } from './metrics.js';
170
189
  await this.worldState.syncImmediate(toBlock);
171
190
  // Create a processor using the forked world state
172
191
  const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, this.dateProvider, this.telemetryClient);
173
- const cleanUp = ()=>{
174
- this.jobs.delete(job.getId());
175
- return Promise.resolve();
176
- };
177
192
  const [_, endTimestamp] = getTimestampRangeForEpoch(epochNumber + 1n, await this.getL1Constants());
178
193
  const deadline = new Date(Number(endTimestamp) * 1000);
179
- const job = this.doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory, cleanUp);
194
+ const job = this.doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory);
180
195
  this.jobs.set(job.getId(), job);
181
196
  return job;
182
197
  }
@@ -225,10 +240,10 @@ import { ProverNodeMetrics } from './metrics.js';
225
240
  const missingTxHashes = txsToFind.filter((txHashToFind)=>!txHashesFound.some((txHashFound)=>txHashToFind.equals(txHashFound))).join(', ');
226
241
  throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxHashes}`);
227
242
  }
228
- /** Extracted for testing purposes. */ doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory, cleanUp) {
243
+ /** Extracted for testing purposes. */ doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory) {
229
244
  return new EpochProvingJob(this.worldState, epochNumber, blocks, txs, this.prover.createEpochProver(), publicProcessorFactory, this.publisher, this.l2BlockSource, this.l1ToL2MessageSource, this.metrics, deadline, {
230
245
  parallelBlockLimit: this.options.maxParallelBlocksPerEpoch
231
- }, cleanUp);
246
+ });
232
247
  }
233
248
  /** Extracted for testing purposes. */ async triggerMonitors() {
234
249
  await this.epochsMonitor.work();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/prover-node",
3
- "version": "0.81.0",
3
+ "version": "0.82.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -53,24 +53,24 @@
53
53
  ]
54
54
  },
55
55
  "dependencies": {
56
- "@aztec/archiver": "0.81.0",
57
- "@aztec/bb-prover": "0.81.0",
58
- "@aztec/blob-sink": "0.81.0",
59
- "@aztec/constants": "0.81.0",
60
- "@aztec/epoch-cache": "0.81.0",
61
- "@aztec/ethereum": "0.81.0",
62
- "@aztec/foundation": "0.81.0",
63
- "@aztec/kv-store": "0.81.0",
64
- "@aztec/l1-artifacts": "0.81.0",
65
- "@aztec/noir-protocol-circuits-types": "0.81.0",
66
- "@aztec/p2p": "0.81.0",
67
- "@aztec/protocol-contracts": "0.81.0",
68
- "@aztec/prover-client": "0.81.0",
69
- "@aztec/sequencer-client": "0.81.0",
70
- "@aztec/simulator": "0.81.0",
71
- "@aztec/stdlib": "0.81.0",
72
- "@aztec/telemetry-client": "0.81.0",
73
- "@aztec/world-state": "0.81.0",
56
+ "@aztec/archiver": "0.82.0",
57
+ "@aztec/bb-prover": "0.82.0",
58
+ "@aztec/blob-sink": "0.82.0",
59
+ "@aztec/constants": "0.82.0",
60
+ "@aztec/epoch-cache": "0.82.0",
61
+ "@aztec/ethereum": "0.82.0",
62
+ "@aztec/foundation": "0.82.0",
63
+ "@aztec/kv-store": "0.82.0",
64
+ "@aztec/l1-artifacts": "0.82.0",
65
+ "@aztec/noir-protocol-circuits-types": "0.82.0",
66
+ "@aztec/p2p": "0.82.0",
67
+ "@aztec/protocol-contracts": "0.82.0",
68
+ "@aztec/prover-client": "0.82.0",
69
+ "@aztec/sequencer-client": "0.82.0",
70
+ "@aztec/simulator": "0.82.0",
71
+ "@aztec/stdlib": "0.82.0",
72
+ "@aztec/telemetry-client": "0.82.0",
73
+ "@aztec/world-state": "0.82.0",
74
74
  "source-map-support": "^0.5.21",
75
75
  "tslib": "^2.4.0",
76
76
  "viem": "2.23.7"
@@ -1,6 +1,6 @@
1
1
  import { asyncPool } from '@aztec/foundation/async-pool';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
- import { promiseWithResolvers } from '@aztec/foundation/promise';
3
+ import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
4
4
  import { Timer } from '@aztec/foundation/timer';
5
5
  import type { PublicProcessor, PublicProcessorFactory } from '@aztec/simulator/server';
6
6
  import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
@@ -30,6 +30,7 @@ export class EpochProvingJob implements Traceable {
30
30
  private uuid: string;
31
31
 
32
32
  private runPromise: Promise<void> | undefined;
33
+ private epochCheckPromise: RunningPromise | undefined;
33
34
  private deadlineTimeoutHandler: NodeJS.Timeout | undefined;
34
35
 
35
36
  public readonly tracer: Tracer;
@@ -47,7 +48,6 @@ export class EpochProvingJob implements Traceable {
47
48
  private metrics: ProverNodeMetrics,
48
49
  private deadline: Date | undefined,
49
50
  private config: { parallelBlockLimit: number } = { parallelBlockLimit: 32 },
50
- private cleanUp: (job: EpochProvingJob) => Promise<void> = () => Promise.resolve(),
51
51
  ) {
52
52
  this.uuid = crypto.randomUUID();
53
53
  this.tracer = metrics.client.getTracer('EpochProvingJob');
@@ -73,6 +73,7 @@ export class EpochProvingJob implements Traceable {
73
73
  })
74
74
  public async run() {
75
75
  this.scheduleDeadlineStop();
76
+ await this.scheduleEpochCheck();
76
77
 
77
78
  const epochNumber = Number(this.epochNumber);
78
79
  const epochSizeBlocks = this.blocks.length;
@@ -154,14 +155,18 @@ export class EpochProvingJob implements Traceable {
154
155
  this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeBlocks, epochSizeTxs);
155
156
  } catch (err: any) {
156
157
  if (err && err.name === 'HaltExecutionError') {
157
- this.log.warn(`Halted execution of epoch ${epochNumber} prover job`, { uuid: this.uuid, epochNumber });
158
+ this.log.warn(`Halted execution of epoch ${epochNumber} prover job`, {
159
+ uuid: this.uuid,
160
+ epochNumber,
161
+ details: err.message,
162
+ });
158
163
  return;
159
164
  }
160
165
  this.log.error(`Error running epoch ${epochNumber} prover job`, err, { uuid: this.uuid, epochNumber });
161
166
  this.state = 'failed';
162
167
  } finally {
163
168
  clearTimeout(this.deadlineTimeoutHandler);
164
- await this.cleanUp(this);
169
+ await this.epochCheckPromise?.stop();
165
170
  await this.prover.stop();
166
171
  resolve();
167
172
  }
@@ -173,12 +178,12 @@ export class EpochProvingJob implements Traceable {
173
178
  }
174
179
 
175
180
  private checkState() {
176
- if (this.state === 'timed-out' || this.state === 'stopped' || this.state === 'failed') {
181
+ if (this.state === 'timed-out' || this.state === 'stopped' || this.state === 'failed' || this.state === 'reorg') {
177
182
  throw new HaltExecutionError(this.state);
178
183
  }
179
184
  }
180
185
 
181
- public async stop(state: EpochProvingJobState = 'stopped') {
186
+ public async stop(state: EpochProvingJobTerminalState = 'stopped') {
182
187
  this.state = state;
183
188
  this.prover.cancel();
184
189
  // TODO(palla/prover): Stop the publisher as well
@@ -207,6 +212,36 @@ export class EpochProvingJob implements Traceable {
207
212
  }
208
213
  }
209
214
 
215
+ /**
216
+ * Kicks off a running promise that queries the archiver for the set of L2 blocks of the current epoch.
217
+ * If those changed, stops the proving job with a `rerun` state, so the node re-enqueues it.
218
+ */
219
+ private async scheduleEpochCheck() {
220
+ const intervalMs = Math.ceil((await this.l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
221
+ this.epochCheckPromise = new RunningPromise(
222
+ async () => {
223
+ const blocks = await this.l2BlockSource.getBlockHeadersForEpoch(this.epochNumber);
224
+ const blockHashes = await Promise.all(blocks.map(block => block.hash()));
225
+ const thisBlockHashes = await Promise.all(this.blocks.map(block => block.hash()));
226
+ if (
227
+ blocks.length !== this.blocks.length ||
228
+ !blockHashes.every((block, i) => block.equals(thisBlockHashes[i]))
229
+ ) {
230
+ this.log.warn('Epoch blocks changed underfoot', {
231
+ uuid: this.uuid,
232
+ epochNumber: this.epochNumber,
233
+ oldBlockHashes: thisBlockHashes,
234
+ newBlockHashes: blockHashes,
235
+ });
236
+ void this.stop('reorg');
237
+ }
238
+ },
239
+ this.log,
240
+ intervalMs,
241
+ ).start();
242
+ this.log.verbose(`Scheduled epoch check for epoch ${this.epochNumber} every ${intervalMs}ms`);
243
+ }
244
+
210
245
  /* Returns the header for the given block number, or the genesis block for block zero. */
211
246
  private async getBlockHeader(blockNumber: number) {
212
247
  if (blockNumber === 0) {
@@ -249,7 +284,7 @@ export class EpochProvingJob implements Traceable {
249
284
  }
250
285
 
251
286
  class HaltExecutionError extends Error {
252
- constructor(state: EpochProvingJobState) {
287
+ constructor(public readonly state: EpochProvingJobState) {
253
288
  super(`Halted execution due to state ${state}`);
254
289
  this.name = 'HaltExecutionError';
255
290
  }
@@ -150,15 +150,17 @@ export class ProverNodePublisher {
150
150
 
151
151
  // Check that the block numbers match the expected epoch to be proven
152
152
  const { pendingBlockNumber: pending, provenBlockNumber: proven } = await this.rollupContract.getTips();
153
- if (proven !== BigInt(fromBlock) - 1n) {
153
+ // Don't publish if proven is beyond our toBlock, pointless to do so
154
+ if (proven > BigInt(toBlock)) {
154
155
  throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as proven block is ${proven}`);
155
156
  }
157
+ // toBlock can't be greater than pending
156
158
  if (toBlock > pending) {
157
159
  throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as pending block is ${pending}`);
158
160
  }
159
161
 
160
162
  // Check the block hash and archive for the immediate block before the epoch
161
- const blockLog = await this.rollupContract.getBlock(proven);
163
+ const blockLog = await this.rollupContract.getBlock(BigInt(fromBlock - 1));
162
164
  if (publicInputs.previousArchive.root.toString() !== blockLog.archive) {
163
165
  throw new Error(
164
166
  `Previous archive root mismatch: ${publicInputs.previousArchive.root.toString()} !== ${blockLog.archive}`,
@@ -23,6 +23,7 @@ import type { P2PClientType } from '@aztec/stdlib/p2p';
23
23
  import type { Tx, TxHash } from '@aztec/stdlib/tx';
24
24
  import {
25
25
  Attributes,
26
+ L1Metrics,
26
27
  type TelemetryClient,
27
28
  type Traceable,
28
29
  type Tracer,
@@ -54,11 +55,10 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
54
55
  private log = createLogger('prover-node');
55
56
  private dateProvider = new DateProvider();
56
57
 
57
- private latestEpochWeAreProving: bigint | undefined;
58
58
  private jobs: Map<string, EpochProvingJob> = new Map();
59
- private cachedEpochData: { epochNumber: bigint; blocks: L2Block[]; txs: Tx[] } | undefined = undefined;
60
59
  private options: ProverNodeOptions;
61
60
  private metrics: ProverNodeMetrics;
61
+ private l1Metrics: L1Metrics;
62
62
 
63
63
  private txFetcher: RunningPromise;
64
64
  private lastBlockNumber: number | undefined;
@@ -77,6 +77,10 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
77
77
  options: Partial<ProverNodeOptions> = {},
78
78
  protected readonly telemetryClient: TelemetryClient = getTelemetryClient(),
79
79
  ) {
80
+ this.l1Metrics = new L1Metrics(telemetryClient.getMeter('ProverNodeL1Metrics'), publisher.l1TxUtils.publicClient, [
81
+ publisher.getSenderAddress(),
82
+ ]);
83
+
80
84
  this.options = {
81
85
  pollingIntervalMs: 1_000,
82
86
  maxPendingJobs: 100,
@@ -110,13 +114,16 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
110
114
  */
111
115
  async handleEpochReadyToProve(epochNumber: bigint): Promise<void> {
112
116
  try {
113
- this.log.debug('jobs', JSON.stringify(this.jobs, null, 2));
117
+ this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
118
+ jobs: Array.from(this.jobs.values()).map(job => `${job.getEpochNumber()}:${job.getId()}`),
119
+ });
114
120
  const activeJobs = await this.getActiveJobsForEpoch(epochNumber);
115
121
  if (activeJobs.length > 0) {
116
- this.log.info(`Not starting proof for ${epochNumber} since there are active jobs`);
122
+ this.log.warn(`Not starting proof for ${epochNumber} since there are active jobs for the epoch`, {
123
+ activeJobs: activeJobs.map(job => job.uuid),
124
+ });
117
125
  return;
118
126
  }
119
- // TODO: we probably want to skip starting a proof if we are too far into the current epoch
120
127
  await this.startProof(epochNumber);
121
128
  } catch (err) {
122
129
  if (err instanceof EmptyEpochError) {
@@ -134,6 +141,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
134
141
  start() {
135
142
  this.txFetcher.start();
136
143
  this.epochsMonitor.start(this);
144
+ this.l1Metrics.start();
137
145
  this.log.info('Started ProverNode', this.options);
138
146
  }
139
147
 
@@ -150,24 +158,35 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
150
158
  await Promise.all(Array.from(this.jobs.values()).map(job => job.stop()));
151
159
  await this.worldState.stop();
152
160
  await tryStop(this.coordination);
161
+ this.l1Metrics.stop();
153
162
  await this.telemetryClient.stop();
154
163
  this.log.info('Stopped ProverNode');
155
164
  }
156
165
 
157
- /**
158
- * Creates a proof for a block range. Returns once the proof has been submitted to L1.
159
- */
160
- public async prove(epochNumber: number | bigint) {
161
- const job = await this.createProvingJob(BigInt(epochNumber));
162
- return job.run();
163
- }
164
-
165
166
  /**
166
167
  * Starts a proving process and returns immediately.
167
168
  */
168
169
  public async startProof(epochNumber: number | bigint) {
169
170
  const job = await this.createProvingJob(BigInt(epochNumber));
170
- void job.run().catch(err => this.log.error(`Error proving epoch ${epochNumber}`, err));
171
+ void this.runJob(job);
172
+ }
173
+
174
+ private async runJob(job: EpochProvingJob) {
175
+ const ctx = { id: job.getId(), epochNumber: job.getEpochNumber() };
176
+ try {
177
+ await job.run();
178
+ const state = job.getState();
179
+ if (state === 'reorg') {
180
+ this.log.warn(`Running new job for epoch ${job.getEpochNumber()} due to reorg`, ctx);
181
+ await this.createProvingJob(job.getEpochNumber());
182
+ } else {
183
+ this.log.verbose(`Job for ${job.getEpochNumber()} exited with state ${state}`, ctx);
184
+ }
185
+ } catch (err) {
186
+ this.log.error(`Error proving epoch ${job.getEpochNumber()}`, err, ctx);
187
+ } finally {
188
+ this.jobs.delete(job.getId());
189
+ }
171
190
  }
172
191
 
173
192
  /**
@@ -210,8 +229,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
210
229
  }
211
230
 
212
231
  // Gather blocks for this epoch
213
- const cachedEpochData = this.cachedEpochData?.epochNumber === epochNumber ? this.cachedEpochData : undefined;
214
- const { blocks, txs } = cachedEpochData ?? (await this.gatherEpochData(epochNumber));
232
+ const { blocks, txs } = await this.gatherEpochData(epochNumber);
215
233
 
216
234
  const fromBlock = blocks[0].number;
217
235
  const toBlock = blocks.at(-1)!.number;
@@ -227,15 +245,10 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
227
245
  this.telemetryClient,
228
246
  );
229
247
 
230
- const cleanUp = () => {
231
- this.jobs.delete(job.getId());
232
- return Promise.resolve();
233
- };
234
-
235
248
  const [_, endTimestamp] = getTimestampRangeForEpoch(epochNumber + 1n, await this.getL1Constants());
236
249
  const deadline = new Date(Number(endTimestamp) * 1000);
237
250
 
238
- const job = this.doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory, cleanUp);
251
+ const job = this.doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory);
239
252
  this.jobs.set(job.getId(), job);
240
253
  return job;
241
254
  }
@@ -302,7 +315,6 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
302
315
  blocks: L2Block[],
303
316
  txs: Tx[],
304
317
  publicProcessorFactory: PublicProcessorFactory,
305
- cleanUp: () => Promise<void>,
306
318
  ) {
307
319
  return new EpochProvingJob(
308
320
  this.worldState,
@@ -317,7 +329,6 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
317
329
  this.metrics,
318
330
  deadline,
319
331
  { parallelBlockLimit: this.options.maxParallelBlocksPerEpoch },
320
- cleanUp,
321
332
  );
322
333
  }
323
334