@aztec/prover-node 0.0.1-commit.b655e406 → 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 (58) hide show
  1. package/dest/actions/download-epoch-proving-job.d.ts +4 -4
  2. package/dest/actions/download-epoch-proving-job.js +1 -1
  3. package/dest/actions/index.d.ts +1 -1
  4. package/dest/actions/rerun-epoch-proving-job.d.ts +5 -3
  5. package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
  6. package/dest/actions/rerun-epoch-proving-job.js +105 -25
  7. package/dest/actions/upload-epoch-proof-failure.d.ts +2 -2
  8. package/dest/actions/upload-epoch-proof-failure.d.ts.map +1 -1
  9. package/dest/bin/run-failed-epoch.d.ts +1 -1
  10. package/dest/bin/run-failed-epoch.js +6 -5
  11. package/dest/config.d.ts +8 -10
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +19 -21
  14. package/dest/factory.d.ts +20 -16
  15. package/dest/factory.d.ts.map +1 -1
  16. package/dest/factory.js +48 -63
  17. package/dest/index.d.ts +2 -1
  18. package/dest/index.d.ts.map +1 -1
  19. package/dest/index.js +1 -0
  20. package/dest/job/epoch-proving-job-data.d.ts +8 -6
  21. package/dest/job/epoch-proving-job-data.d.ts.map +1 -1
  22. package/dest/job/epoch-proving-job-data.js +25 -18
  23. package/dest/job/epoch-proving-job.d.ts +11 -13
  24. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  25. package/dest/job/epoch-proving-job.js +669 -111
  26. package/dest/metrics.d.ts +24 -3
  27. package/dest/metrics.d.ts.map +1 -1
  28. package/dest/metrics.js +77 -98
  29. package/dest/monitors/epoch-monitor.d.ts +3 -2
  30. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  31. package/dest/monitors/epoch-monitor.js +14 -20
  32. package/dest/monitors/index.d.ts +1 -1
  33. package/dest/prover-node-publisher.d.ts +33 -11
  34. package/dest/prover-node-publisher.d.ts.map +1 -1
  35. package/dest/prover-node-publisher.js +248 -46
  36. package/dest/prover-node.d.ts +30 -19
  37. package/dest/prover-node.d.ts.map +1 -1
  38. package/dest/prover-node.js +512 -81
  39. package/dest/prover-publisher-factory.d.ts +10 -6
  40. package/dest/prover-publisher-factory.d.ts.map +1 -1
  41. package/dest/prover-publisher-factory.js +7 -5
  42. package/dest/test/index.d.ts +1 -1
  43. package/dest/test/index.d.ts.map +1 -1
  44. package/package.json +27 -25
  45. package/src/actions/download-epoch-proving-job.ts +1 -1
  46. package/src/actions/rerun-epoch-proving-job.ts +20 -7
  47. package/src/actions/upload-epoch-proof-failure.ts +1 -1
  48. package/src/bin/run-failed-epoch.ts +5 -3
  49. package/src/config.ts +27 -33
  50. package/src/factory.ts +81 -103
  51. package/src/index.ts +1 -0
  52. package/src/job/epoch-proving-job-data.ts +31 -25
  53. package/src/job/epoch-proving-job.ts +228 -117
  54. package/src/metrics.ts +102 -82
  55. package/src/monitors/epoch-monitor.ts +10 -17
  56. package/src/prover-node-publisher.ts +302 -66
  57. package/src/prover-node.ts +135 -86
  58. package/src/prover-publisher-factory.ts +19 -11
@@ -1,20 +1,393 @@
1
- function _ts_decorate(decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1
+ function applyDecs2203RFactory() {
2
+ function createAddInitializerMethod(initializers, decoratorFinishedRef) {
3
+ return function addInitializer(initializer) {
4
+ assertNotFinished(decoratorFinishedRef, "addInitializer");
5
+ assertCallable(initializer, "An initializer");
6
+ initializers.push(initializer);
7
+ };
8
+ }
9
+ function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
10
+ var kindStr;
11
+ switch(kind){
12
+ case 1:
13
+ kindStr = "accessor";
14
+ break;
15
+ case 2:
16
+ kindStr = "method";
17
+ break;
18
+ case 3:
19
+ kindStr = "getter";
20
+ break;
21
+ case 4:
22
+ kindStr = "setter";
23
+ break;
24
+ default:
25
+ kindStr = "field";
26
+ }
27
+ var ctx = {
28
+ kind: kindStr,
29
+ name: isPrivate ? "#" + name : name,
30
+ static: isStatic,
31
+ private: isPrivate,
32
+ metadata: metadata
33
+ };
34
+ var decoratorFinishedRef = {
35
+ v: false
36
+ };
37
+ ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
38
+ var get, set;
39
+ if (kind === 0) {
40
+ if (isPrivate) {
41
+ get = desc.get;
42
+ set = desc.set;
43
+ } else {
44
+ get = function() {
45
+ return this[name];
46
+ };
47
+ set = function(v) {
48
+ this[name] = v;
49
+ };
50
+ }
51
+ } else if (kind === 2) {
52
+ get = function() {
53
+ return desc.value;
54
+ };
55
+ } else {
56
+ if (kind === 1 || kind === 3) {
57
+ get = function() {
58
+ return desc.get.call(this);
59
+ };
60
+ }
61
+ if (kind === 1 || kind === 4) {
62
+ set = function(v) {
63
+ desc.set.call(this, v);
64
+ };
65
+ }
66
+ }
67
+ ctx.access = get && set ? {
68
+ get: get,
69
+ set: set
70
+ } : get ? {
71
+ get: get
72
+ } : {
73
+ set: set
74
+ };
75
+ try {
76
+ return dec(value, ctx);
77
+ } finally{
78
+ decoratorFinishedRef.v = true;
79
+ }
80
+ }
81
+ function assertNotFinished(decoratorFinishedRef, fnName) {
82
+ if (decoratorFinishedRef.v) {
83
+ throw new Error("attempted to call " + fnName + " after decoration was finished");
84
+ }
85
+ }
86
+ function assertCallable(fn, hint) {
87
+ if (typeof fn !== "function") {
88
+ throw new TypeError(hint + " must be a function");
89
+ }
90
+ }
91
+ function assertValidReturnValue(kind, value) {
92
+ var type = typeof value;
93
+ if (kind === 1) {
94
+ if (type !== "object" || value === null) {
95
+ throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
96
+ }
97
+ if (value.get !== undefined) {
98
+ assertCallable(value.get, "accessor.get");
99
+ }
100
+ if (value.set !== undefined) {
101
+ assertCallable(value.set, "accessor.set");
102
+ }
103
+ if (value.init !== undefined) {
104
+ assertCallable(value.init, "accessor.init");
105
+ }
106
+ } else if (type !== "function") {
107
+ var hint;
108
+ if (kind === 0) {
109
+ hint = "field";
110
+ } else if (kind === 10) {
111
+ hint = "class";
112
+ } else {
113
+ hint = "method";
114
+ }
115
+ throw new TypeError(hint + " decorators must return a function or void 0");
116
+ }
117
+ }
118
+ function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
119
+ var decs = decInfo[0];
120
+ var desc, init, value;
121
+ if (isPrivate) {
122
+ if (kind === 0 || kind === 1) {
123
+ desc = {
124
+ get: decInfo[3],
125
+ set: decInfo[4]
126
+ };
127
+ } else if (kind === 3) {
128
+ desc = {
129
+ get: decInfo[3]
130
+ };
131
+ } else if (kind === 4) {
132
+ desc = {
133
+ set: decInfo[3]
134
+ };
135
+ } else {
136
+ desc = {
137
+ value: decInfo[3]
138
+ };
139
+ }
140
+ } else if (kind !== 0) {
141
+ desc = Object.getOwnPropertyDescriptor(base, name);
142
+ }
143
+ if (kind === 1) {
144
+ value = {
145
+ get: desc.get,
146
+ set: desc.set
147
+ };
148
+ } else if (kind === 2) {
149
+ value = desc.value;
150
+ } else if (kind === 3) {
151
+ value = desc.get;
152
+ } else if (kind === 4) {
153
+ value = desc.set;
154
+ }
155
+ var newValue, get, set;
156
+ if (typeof decs === "function") {
157
+ newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
158
+ if (newValue !== void 0) {
159
+ assertValidReturnValue(kind, newValue);
160
+ if (kind === 0) {
161
+ init = newValue;
162
+ } else if (kind === 1) {
163
+ init = newValue.init;
164
+ get = newValue.get || value.get;
165
+ set = newValue.set || value.set;
166
+ value = {
167
+ get: get,
168
+ set: set
169
+ };
170
+ } else {
171
+ value = newValue;
172
+ }
173
+ }
174
+ } else {
175
+ for(var i = decs.length - 1; i >= 0; i--){
176
+ var dec = decs[i];
177
+ newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
178
+ if (newValue !== void 0) {
179
+ assertValidReturnValue(kind, newValue);
180
+ var newInit;
181
+ if (kind === 0) {
182
+ newInit = newValue;
183
+ } else if (kind === 1) {
184
+ newInit = newValue.init;
185
+ get = newValue.get || value.get;
186
+ set = newValue.set || value.set;
187
+ value = {
188
+ get: get,
189
+ set: set
190
+ };
191
+ } else {
192
+ value = newValue;
193
+ }
194
+ if (newInit !== void 0) {
195
+ if (init === void 0) {
196
+ init = newInit;
197
+ } else if (typeof init === "function") {
198
+ init = [
199
+ init,
200
+ newInit
201
+ ];
202
+ } else {
203
+ init.push(newInit);
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ if (kind === 0 || kind === 1) {
210
+ if (init === void 0) {
211
+ init = function(instance, init) {
212
+ return init;
213
+ };
214
+ } else if (typeof init !== "function") {
215
+ var ownInitializers = init;
216
+ init = function(instance, init) {
217
+ var value = init;
218
+ for(var i = 0; i < ownInitializers.length; i++){
219
+ value = ownInitializers[i].call(instance, value);
220
+ }
221
+ return value;
222
+ };
223
+ } else {
224
+ var originalInitializer = init;
225
+ init = function(instance, init) {
226
+ return originalInitializer.call(instance, init);
227
+ };
228
+ }
229
+ ret.push(init);
230
+ }
231
+ if (kind !== 0) {
232
+ if (kind === 1) {
233
+ desc.get = value.get;
234
+ desc.set = value.set;
235
+ } else if (kind === 2) {
236
+ desc.value = value;
237
+ } else if (kind === 3) {
238
+ desc.get = value;
239
+ } else if (kind === 4) {
240
+ desc.set = value;
241
+ }
242
+ if (isPrivate) {
243
+ if (kind === 1) {
244
+ ret.push(function(instance, args) {
245
+ return value.get.call(instance, args);
246
+ });
247
+ ret.push(function(instance, args) {
248
+ return value.set.call(instance, args);
249
+ });
250
+ } else if (kind === 2) {
251
+ ret.push(value);
252
+ } else {
253
+ ret.push(function(instance, args) {
254
+ return value.call(instance, args);
255
+ });
256
+ }
257
+ } else {
258
+ Object.defineProperty(base, name, desc);
259
+ }
260
+ }
261
+ }
262
+ function applyMemberDecs(Class, decInfos, metadata) {
263
+ var ret = [];
264
+ var protoInitializers;
265
+ var staticInitializers;
266
+ var existingProtoNonFields = new Map();
267
+ var existingStaticNonFields = new Map();
268
+ for(var i = 0; i < decInfos.length; i++){
269
+ var decInfo = decInfos[i];
270
+ if (!Array.isArray(decInfo)) continue;
271
+ var kind = decInfo[1];
272
+ var name = decInfo[2];
273
+ var isPrivate = decInfo.length > 3;
274
+ var isStatic = kind >= 5;
275
+ var base;
276
+ var initializers;
277
+ if (isStatic) {
278
+ base = Class;
279
+ kind = kind - 5;
280
+ staticInitializers = staticInitializers || [];
281
+ initializers = staticInitializers;
282
+ } else {
283
+ base = Class.prototype;
284
+ protoInitializers = protoInitializers || [];
285
+ initializers = protoInitializers;
286
+ }
287
+ if (kind !== 0 && !isPrivate) {
288
+ var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
289
+ var existingKind = existingNonFields.get(name) || 0;
290
+ if (existingKind === true || existingKind === 3 && kind !== 4 || existingKind === 4 && kind !== 3) {
291
+ throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
292
+ } else if (!existingKind && kind > 2) {
293
+ existingNonFields.set(name, kind);
294
+ } else {
295
+ existingNonFields.set(name, true);
296
+ }
297
+ }
298
+ applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
299
+ }
300
+ pushInitializers(ret, protoInitializers);
301
+ pushInitializers(ret, staticInitializers);
302
+ return ret;
303
+ }
304
+ function pushInitializers(ret, initializers) {
305
+ if (initializers) {
306
+ ret.push(function(instance) {
307
+ for(var i = 0; i < initializers.length; i++){
308
+ initializers[i].call(instance);
309
+ }
310
+ return instance;
311
+ });
312
+ }
313
+ }
314
+ function applyClassDecs(targetClass, classDecs, metadata) {
315
+ if (classDecs.length > 0) {
316
+ var initializers = [];
317
+ var newClass = targetClass;
318
+ var name = targetClass.name;
319
+ for(var i = classDecs.length - 1; i >= 0; i--){
320
+ var decoratorFinishedRef = {
321
+ v: false
322
+ };
323
+ try {
324
+ var nextNewClass = classDecs[i](newClass, {
325
+ kind: "class",
326
+ name: name,
327
+ addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
328
+ metadata
329
+ });
330
+ } finally{
331
+ decoratorFinishedRef.v = true;
332
+ }
333
+ if (nextNewClass !== undefined) {
334
+ assertValidReturnValue(10, nextNewClass);
335
+ newClass = nextNewClass;
336
+ }
337
+ }
338
+ return [
339
+ defineMetadata(newClass, metadata),
340
+ function() {
341
+ for(var i = 0; i < initializers.length; i++){
342
+ initializers[i].call(newClass);
343
+ }
344
+ }
345
+ ];
346
+ }
347
+ }
348
+ function defineMetadata(Class, metadata) {
349
+ return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
350
+ configurable: true,
351
+ enumerable: true,
352
+ value: metadata
353
+ });
354
+ }
355
+ return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) {
356
+ if (parentClass !== void 0) {
357
+ var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
358
+ }
359
+ var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata);
360
+ var e = applyMemberDecs(targetClass, memberDecs, metadata);
361
+ if (!classDecs.length) defineMetadata(targetClass, metadata);
362
+ return {
363
+ e: e,
364
+ get c () {
365
+ return applyClassDecs(targetClass, classDecs, metadata);
366
+ }
367
+ };
368
+ };
369
+ }
370
+ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
371
+ return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
6
372
  }
373
+ var _dec, _dec1, _initProto;
374
+ import { BlockNumber } from '@aztec/foundation/branded-types';
7
375
  import { assertRequired, compact, pick, sum } from '@aztec/foundation/collection';
8
376
  import { memoize } from '@aztec/foundation/decorators';
9
377
  import { createLogger } from '@aztec/foundation/log';
10
378
  import { DateProvider } from '@aztec/foundation/timer';
11
379
  import { PublicProcessorFactory } from '@aztec/simulator/server';
12
380
  import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
13
- import { EpochProvingJobTerminalState, tryStop } from '@aztec/stdlib/interfaces/server';
381
+ import { tryStop } from '@aztec/stdlib/interfaces/server';
14
382
  import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
15
383
  import { uploadEpochProofFailure } from './actions/upload-epoch-proof-failure.js';
16
384
  import { EpochProvingJob } from './job/epoch-proving-job.js';
17
385
  import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
386
+ _dec = trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
387
+ [Attributes.EPOCH_NUMBER]: epochNumber
388
+ })), _dec1 = trackSpan('ProverNode.gatherEpochData', (epochNumber)=>({
389
+ [Attributes.EPOCH_NUMBER]: epochNumber
390
+ }));
18
391
  /**
19
392
  * An Aztec Prover Node is a standalone process that monitors the unfinalized chain on L1 for unproven epochs,
20
393
  * fetches their txs from the p2p network or external nodes, re-executes their public functions, creates a rollup
@@ -31,15 +404,36 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
31
404
  rollupContract;
32
405
  l1Metrics;
33
406
  telemetryClient;
34
- log;
407
+ delayer;
35
408
  dateProvider;
409
+ static{
410
+ ({ e: [_initProto] } = _apply_decs_2203_r(this, [
411
+ [
412
+ _dec,
413
+ 2,
414
+ "createProvingJob"
415
+ ],
416
+ [
417
+ memoize,
418
+ 2,
419
+ "getL1Constants"
420
+ ],
421
+ [
422
+ _dec1,
423
+ 2,
424
+ "gatherEpochData"
425
+ ]
426
+ ], []));
427
+ }
428
+ log;
36
429
  jobs;
37
430
  config;
38
431
  jobMetrics;
39
432
  rewardsMetrics;
433
+ startingProofEpochs;
40
434
  tracer;
41
435
  publisher;
42
- constructor(prover, publisherFactory, l2BlockSource, l1ToL2MessageSource, contractDataSource, worldState, p2pClient, epochsMonitor, rollupContract, l1Metrics, config = {}, telemetryClient = getTelemetryClient()){
436
+ constructor(prover, publisherFactory, l2BlockSource, l1ToL2MessageSource, contractDataSource, worldState, p2pClient, epochsMonitor, rollupContract, l1Metrics, config = {}, telemetryClient = getTelemetryClient(), delayer, dateProvider = new DateProvider()){
43
437
  this.prover = prover;
44
438
  this.publisherFactory = publisherFactory;
45
439
  this.l2BlockSource = l2BlockSource;
@@ -51,13 +445,15 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
51
445
  this.rollupContract = rollupContract;
52
446
  this.l1Metrics = l1Metrics;
53
447
  this.telemetryClient = telemetryClient;
54
- this.log = createLogger('prover-node');
55
- this.dateProvider = new DateProvider();
448
+ this.delayer = delayer;
449
+ this.dateProvider = dateProvider;
450
+ this.log = (_initProto(this), createLogger('prover-node'));
56
451
  this.jobs = new Map();
452
+ this.startingProofEpochs = new Set();
57
453
  this.config = {
58
454
  proverNodePollingIntervalMs: 1_000,
59
455
  proverNodeMaxPendingJobs: 100,
60
- proverNodeMaxParallelBlocksPerEpoch: 32,
456
+ proverNodeMaxParallelBlocksPerEpoch: 0,
61
457
  txGatheringIntervalMs: 1_000,
62
458
  txGatheringBatchSize: 10,
63
459
  txGatheringMaxParallelRequestsPerNode: 100,
@@ -78,6 +474,9 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
78
474
  getP2P() {
79
475
  return this.p2pClient;
80
476
  }
477
+ /** Returns the shared tx delayer for prover L1 txs, if enabled. Test-only. */ getDelayer() {
478
+ return this.delayer;
479
+ }
81
480
  /**
82
481
  * Handles an epoch being completed by starting a proof for it if there are no active jobs for it.
83
482
  * @param epochNumber - The epoch number that was just completed.
@@ -87,15 +486,7 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
87
486
  this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
88
487
  jobs: Array.from(this.jobs.values()).map((job)=>`${job.getEpochNumber()}:${job.getId()}`)
89
488
  });
90
- const activeJobs = await this.getActiveJobsForEpoch(epochNumber);
91
- if (activeJobs.length > 0) {
92
- this.log.warn(`Not starting proof for ${epochNumber} since there are active jobs for the epoch`, {
93
- activeJobs: activeJobs.map((job)=>job.uuid)
94
- });
95
- return true;
96
- }
97
- await this.startProof(epochNumber);
98
- return true;
489
+ return await this.startProofIfNeeded(epochNumber);
99
490
  } catch (err) {
100
491
  if (err instanceof EmptyEpochError) {
101
492
  this.log.info(`Not starting proof for ${epochNumber} since no blocks were found`);
@@ -118,16 +509,14 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
118
509
  }
119
510
  /**
120
511
  * Stops the prover node and all its dependencies.
512
+ * Resources not owned by this node (shared with the parent aztec-node) are skipped.
121
513
  */ async stop() {
122
514
  this.log.info('Stopping ProverNode');
123
515
  await this.epochsMonitor.stop();
124
- await this.prover.stop();
125
- await tryStop(this.p2pClient);
126
- await tryStop(this.l2BlockSource);
127
- await tryStop(this.publisherFactory);
128
516
  this.publisher?.interrupt();
129
517
  await Promise.all(Array.from(this.jobs.values()).map((job)=>job.stop()));
130
- await this.worldState.stop();
518
+ await this.prover.stop();
519
+ await tryStop(this.publisherFactory);
131
520
  this.rewardsMetrics.stop();
132
521
  this.l1Metrics.stop();
133
522
  await this.telemetryClient.stop();
@@ -143,9 +532,35 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
143
532
  /**
144
533
  * Starts a proving process and returns immediately.
145
534
  */ async startProof(epochNumber) {
146
- const job = await this.createProvingJob(BigInt(epochNumber), {
535
+ await this.startProofIfNeeded(epochNumber, {
147
536
  skipEpochCheck: true
148
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);
149
564
  void this.runJob(job);
150
565
  }
151
566
  async runJob(job) {
@@ -187,16 +602,40 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
187
602
  /**
188
603
  * Returns an array of jobs being processed.
189
604
  */ getJobs() {
190
- 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])=>({
191
609
  uuid,
192
610
  status: job.getState(),
193
- epochNumber: Number(job.getEpochNumber())
194
- })));
611
+ epochNumber: job.getEpochNumber()
612
+ }));
195
613
  }
196
- async getActiveJobsForEpoch(epochBigInt) {
197
- const jobs = await this.getJobs();
198
- const epochNumber = Number(epochBigInt);
199
- 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;
200
639
  }
201
640
  checkMaximumPendingJobs() {
202
641
  const { proverNodeMaxPendingJobs: maxPendingJobs } = this.config;
@@ -209,13 +648,17 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
209
648
  this.publisher = await this.publisherFactory.create();
210
649
  // Gather all data for this epoch
211
650
  const epochData = await this.gatherEpochData(epochNumber);
212
- const fromBlock = epochData.blocks[0].number;
213
- const toBlock = epochData.blocks.at(-1).number;
214
- this.log.verbose(`Creating proving job for epoch ${epochNumber} for block range ${fromBlock} to ${toBlock}`);
651
+ const fromCheckpoint = epochData.checkpoints[0].number;
652
+ const toCheckpoint = epochData.checkpoints.at(-1).number;
653
+ const fromBlock = epochData.checkpoints[0].blocks[0].number;
654
+ const lastBlock = epochData.checkpoints.at(-1).blocks.at(-1);
655
+ const toBlock = lastBlock.number;
656
+ this.log.verbose(`Creating proving job for epoch ${epochNumber} for checkpoint range ${fromCheckpoint} to ${toCheckpoint} and block range ${fromBlock} to ${toBlock}`);
215
657
  // Fast forward world state to right before the target block and get a fork
216
- await this.worldState.syncImmediate(toBlock);
658
+ const lastBlockHash = await lastBlock.header.hash();
659
+ await this.worldState.syncImmediate(toBlock, lastBlockHash);
217
660
  // Create a processor factory
218
- const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, this.dateProvider, this.telemetryClient);
661
+ const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, this.dateProvider, this.telemetryClient, this.log.getBindings());
219
662
  // Set deadline for this job to run. It will abort if it takes too long.
220
663
  const deadlineTs = getProofSubmissionDeadlineTimestamp(epochNumber, await this.getL1Constants());
221
664
  const deadline = new Date(Number(deadlineTs) * 1000);
@@ -227,18 +670,24 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
227
670
  return this.l2BlockSource.getL1Constants();
228
671
  }
229
672
  async gatherEpochData(epochNumber) {
230
- const blocks = await this.gatherBlocks(epochNumber);
231
- const txArray = await this.gatherTxs(epochNumber, blocks);
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 ?? [];
681
+ const txArray = await this.gatherTxs(epochNumber, checkpoints);
232
682
  const txs = new Map(txArray.map((tx)=>[
233
683
  tx.getTxHash().toString(),
234
684
  tx
235
685
  ]));
236
- const l1ToL2Messages = await this.gatherMessages(epochNumber, blocks);
237
- const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, blocks[0]);
238
- const [lastBlock] = await this.l2BlockSource.getPublishedBlocks(blocks.at(-1).number, 1);
239
- const attestations = lastBlock?.attestations ?? [];
686
+ const l1ToL2Messages = await this.gatherMessages(epochNumber, checkpoints);
687
+ const [firstBlock] = checkpoints[0].blocks;
688
+ const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, firstBlock.number - 1);
240
689
  return {
241
- blocks,
690
+ checkpoints,
242
691
  txs,
243
692
  l1ToL2Messages,
244
693
  epochNumber,
@@ -246,16 +695,10 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
246
695
  attestations
247
696
  };
248
697
  }
249
- async gatherBlocks(epochNumber) {
250
- const blocks = await this.l2BlockSource.getBlocksForEpoch(epochNumber);
251
- if (blocks.length === 0) {
252
- throw new EmptyEpochError(epochNumber);
253
- }
254
- return blocks;
255
- }
256
- async gatherTxs(epochNumber, blocks) {
698
+ async gatherTxs(epochNumber, checkpoints) {
257
699
  const deadline = new Date(this.dateProvider.now() + this.config.txGatheringTimeoutMs);
258
700
  const txProvider = this.p2pClient.getTxProvider();
701
+ const blocks = checkpoints.flatMap((checkpoint)=>checkpoint.blocks);
259
702
  const txsByBlock = await Promise.all(blocks.map((block)=>txProvider.getTxsForBlock(block, {
260
703
  deadline
261
704
  })));
@@ -269,26 +712,27 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
269
712
  }
270
713
  throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxs.map((hash)=>hash.toString()).join(', ')}`);
271
714
  }
272
- async gatherMessages(epochNumber, blocks) {
273
- const messages = await Promise.all(blocks.map((b)=>this.l1ToL2MessageSource.getL1ToL2Messages(b.number)));
715
+ async gatherMessages(epochNumber, checkpoints) {
716
+ const messages = await Promise.all(checkpoints.map((c)=>this.l1ToL2MessageSource.getL1ToL2Messages(c.number)));
274
717
  const messageCount = sum(messages.map((m)=>m.length));
275
718
  this.log.verbose(`Gathered all ${messageCount} messages for epoch ${epochNumber}`, {
276
719
  epochNumber
277
720
  });
278
- const messagesByBlock = {};
279
- for(let i = 0; i < blocks.length; i++){
280
- messagesByBlock[blocks[i].number] = messages[i];
721
+ const messagesByCheckpoint = {};
722
+ for(let i = 0; i < checkpoints.length; i++){
723
+ messagesByCheckpoint[checkpoints[i].number] = messages[i];
281
724
  }
282
- return messagesByBlock;
725
+ return messagesByCheckpoint;
283
726
  }
284
- async gatherPreviousBlockHeader(epochNumber, initialBlock) {
285
- const previousBlockNumber = initialBlock.number - 1;
286
- const header = await (previousBlockNumber === 0 ? this.worldState.getCommitted().getInitialHeader() : this.l2BlockSource.getBlockHeader(previousBlockNumber));
287
- if (!header) {
288
- throw new Error(`Previous block header ${initialBlock.number} not found for proving epoch ${epochNumber}`);
727
+ async gatherPreviousBlockHeader(epochNumber, previousBlockNumber) {
728
+ const data = await this.l2BlockSource.getBlockData({
729
+ number: BlockNumber(previousBlockNumber)
730
+ });
731
+ if (!data?.header) {
732
+ throw new Error(`Previous block header ${previousBlockNumber} not found for proving epoch ${epochNumber}`);
289
733
  }
290
- this.log.verbose(`Gathered previous block header ${header.getBlockNumber()} for epoch ${epochNumber}`);
291
- return header;
734
+ this.log.verbose(`Gathered previous block header ${data.header.getBlockNumber()} for epoch ${epochNumber}`);
735
+ return data.header;
292
736
  }
293
737
  /** Extracted for testing purposes. */ doCreateEpochProvingJob(data, deadline, publicProcessorFactory, publisher, opts = {}) {
294
738
  const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit, proverNodeDisableProofPublish } = this.config;
@@ -296,31 +740,18 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
296
740
  parallelBlockLimit,
297
741
  skipSubmitProof: proverNodeDisableProofPublish,
298
742
  ...opts
299
- });
743
+ }, this.log.getBindings());
300
744
  }
301
745
  /** Extracted for testing purposes. */ async triggerMonitors() {
302
746
  await this.epochsMonitor.work();
303
747
  }
304
748
  validateConfig() {
305
- if (this.config.proverNodeFailedEpochStore && (!this.config.dataDirectory || !this.config.l1ChainId || !this.config.rollupVersion)) {
749
+ if (this.config.proverNodeFailedEpochStore && (!this.config.dataDirectory || !this.config.l1ChainId || this.config.rollupVersion === undefined)) {
306
750
  this.log.warn(`Invalid prover-node config (missing dataDirectory, l1ChainId, or rollupVersion)`, pick(this.config, 'proverNodeFailedEpochStore', 'dataDirectory', 'l1ChainId', 'rollupVersion'));
307
751
  throw new Error('All of dataDirectory, l1ChainId, and rollupVersion are required if proverNodeFailedEpochStore is set.');
308
752
  }
309
753
  }
310
754
  }
311
- _ts_decorate([
312
- trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
313
- [Attributes.EPOCH_NUMBER]: Number(epochNumber)
314
- }))
315
- ], ProverNode.prototype, "createProvingJob", null);
316
- _ts_decorate([
317
- memoize
318
- ], ProverNode.prototype, "getL1Constants", null);
319
- _ts_decorate([
320
- trackSpan('ProverNode.gatherEpochData', (epochNumber)=>({
321
- [Attributes.EPOCH_NUMBER]: Number(epochNumber)
322
- }))
323
- ], ProverNode.prototype, "gatherEpochData", null);
324
755
  class EmptyEpochError extends Error {
325
756
  constructor(epochNumber){
326
757
  super(`No blocks found for epoch ${epochNumber}`);