@aztec/prover-node 0.0.0-test.1 → 0.0.1-commit.1142ef1

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 (82) hide show
  1. package/dest/actions/download-epoch-proving-job.d.ts +18 -0
  2. package/dest/actions/download-epoch-proving-job.d.ts.map +1 -0
  3. package/dest/actions/download-epoch-proving-job.js +37 -0
  4. package/dest/actions/index.d.ts +3 -0
  5. package/dest/actions/index.d.ts.map +1 -0
  6. package/dest/actions/index.js +2 -0
  7. package/dest/actions/rerun-epoch-proving-job.d.ts +11 -0
  8. package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -0
  9. package/dest/actions/rerun-epoch-proving-job.js +40 -0
  10. package/dest/actions/upload-epoch-proof-failure.d.ts +15 -0
  11. package/dest/actions/upload-epoch-proof-failure.d.ts.map +1 -0
  12. package/dest/actions/upload-epoch-proof-failure.js +78 -0
  13. package/dest/bin/run-failed-epoch.d.ts +2 -0
  14. package/dest/bin/run-failed-epoch.d.ts.map +1 -0
  15. package/dest/bin/run-failed-epoch.js +67 -0
  16. package/dest/config.d.ts +15 -11
  17. package/dest/config.d.ts.map +1 -1
  18. package/dest/config.js +83 -15
  19. package/dest/factory.d.ts +14 -12
  20. package/dest/factory.d.ts.map +1 -1
  21. package/dest/factory.js +105 -32
  22. package/dest/index.d.ts +3 -2
  23. package/dest/index.d.ts.map +1 -1
  24. package/dest/index.js +2 -1
  25. package/dest/job/epoch-proving-job-data.d.ts +18 -0
  26. package/dest/job/epoch-proving-job-data.d.ts.map +1 -0
  27. package/dest/job/epoch-proving-job-data.js +59 -0
  28. package/dest/job/epoch-proving-job.d.ts +26 -18
  29. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  30. package/dest/job/epoch-proving-job.js +579 -96
  31. package/dest/metrics.d.ts +30 -5
  32. package/dest/metrics.d.ts.map +1 -1
  33. package/dest/metrics.js +103 -73
  34. package/dest/monitors/epoch-monitor.d.ts +5 -2
  35. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  36. package/dest/monitors/epoch-monitor.js +18 -13
  37. package/dest/monitors/index.d.ts +1 -1
  38. package/dest/prover-node-publisher.d.ts +14 -15
  39. package/dest/prover-node-publisher.d.ts.map +1 -1
  40. package/dest/prover-node-publisher.js +86 -81
  41. package/dest/prover-node.d.ts +49 -44
  42. package/dest/prover-node.d.ts.map +1 -1
  43. package/dest/prover-node.js +581 -129
  44. package/dest/prover-publisher-factory.d.ts +23 -0
  45. package/dest/prover-publisher-factory.d.ts.map +1 -0
  46. package/dest/prover-publisher-factory.js +26 -0
  47. package/dest/test/index.d.ts +5 -3
  48. package/dest/test/index.d.ts.map +1 -1
  49. package/dest/test/index.js +1 -3
  50. package/package.json +39 -33
  51. package/src/actions/download-epoch-proving-job.ts +44 -0
  52. package/src/actions/index.ts +2 -0
  53. package/src/actions/rerun-epoch-proving-job.ts +61 -0
  54. package/src/actions/upload-epoch-proof-failure.ts +88 -0
  55. package/src/bin/run-failed-epoch.ts +77 -0
  56. package/src/config.ts +111 -25
  57. package/src/factory.ts +176 -44
  58. package/src/index.ts +2 -1
  59. package/src/job/epoch-proving-job-data.ts +82 -0
  60. package/src/job/epoch-proving-job.ts +255 -83
  61. package/src/metrics.ts +116 -73
  62. package/src/monitors/epoch-monitor.ts +20 -15
  63. package/src/prover-node-publisher.ts +133 -115
  64. package/src/prover-node.ts +223 -142
  65. package/src/prover-publisher-factory.ts +39 -0
  66. package/src/test/index.ts +7 -4
  67. package/dest/http.d.ts +0 -8
  68. package/dest/http.d.ts.map +0 -1
  69. package/dest/http.js +0 -9
  70. package/dest/prover-coordination/config.d.ts +0 -7
  71. package/dest/prover-coordination/config.d.ts.map +0 -1
  72. package/dest/prover-coordination/config.js +0 -11
  73. package/dest/prover-coordination/factory.d.ts +0 -22
  74. package/dest/prover-coordination/factory.d.ts.map +0 -1
  75. package/dest/prover-coordination/factory.js +0 -42
  76. package/dest/prover-coordination/index.d.ts +0 -3
  77. package/dest/prover-coordination/index.d.ts.map +0 -1
  78. package/dest/prover-coordination/index.js +0 -2
  79. package/src/http.ts +0 -13
  80. package/src/prover-coordination/config.ts +0 -17
  81. package/src/prover-coordination/factory.ts +0 -72
  82. package/src/prover-coordination/index.ts +0 -2
@@ -1,137 +1,575 @@
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
  }
7
- import { compact } from '@aztec/foundation/collection';
373
+ var _dec, _dec1, _initProto;
374
+ import { BlockNumber } from '@aztec/foundation/branded-types';
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
- import { RunningPromise } from '@aztec/foundation/running-promise';
11
378
  import { DateProvider } from '@aztec/foundation/timer';
12
379
  import { PublicProcessorFactory } from '@aztec/simulator/server';
13
- import { getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
380
+ import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
14
381
  import { EpochProvingJobTerminalState, tryStop } from '@aztec/stdlib/interfaces/server';
15
382
  import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
383
+ import { uploadEpochProofFailure } from './actions/upload-epoch-proof-failure.js';
16
384
  import { EpochProvingJob } from './job/epoch-proving-job.js';
17
- import { ProverNodeMetrics } from './metrics.js';
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
- * An Aztec Prover Node is a standalone process that monitors the unfinalised chain on L1 for unproven blocks,
20
- * submits bids for proving them, and monitors if they are accepted. If so, the prover node fetches the txs
21
- * from a tx source in the p2p network or an external node, re-executes their public functions, creates a rollup
392
+ * An Aztec Prover Node is a standalone process that monitors the unfinalized chain on L1 for unproven epochs,
393
+ * fetches their txs from the p2p network or external nodes, re-executes their public functions, creates a rollup
22
394
  * proof for the epoch, and submits it to L1.
23
395
  */ export class ProverNode {
24
396
  prover;
25
- publisher;
397
+ publisherFactory;
26
398
  l2BlockSource;
27
399
  l1ToL2MessageSource;
28
400
  contractDataSource;
29
401
  worldState;
30
- coordination;
402
+ p2pClient;
31
403
  epochsMonitor;
404
+ rollupContract;
405
+ l1Metrics;
32
406
  telemetryClient;
407
+ static{
408
+ ({ e: [_initProto] } = _apply_decs_2203_r(this, [
409
+ [
410
+ _dec,
411
+ 2,
412
+ "createProvingJob"
413
+ ],
414
+ [
415
+ memoize,
416
+ 2,
417
+ "getL1Constants"
418
+ ],
419
+ [
420
+ _dec1,
421
+ 2,
422
+ "gatherEpochData"
423
+ ]
424
+ ], []));
425
+ }
33
426
  log;
34
427
  dateProvider;
35
- latestEpochWeAreProving;
36
428
  jobs;
37
- cachedEpochData;
38
- options;
39
- metrics;
40
- txFetcher;
41
- lastBlockNumber;
429
+ config;
430
+ jobMetrics;
431
+ rewardsMetrics;
42
432
  tracer;
43
- constructor(prover, publisher, l2BlockSource, l1ToL2MessageSource, contractDataSource, worldState, coordination, epochsMonitor, options = {}, telemetryClient = getTelemetryClient()){
433
+ publisher;
434
+ constructor(prover, publisherFactory, l2BlockSource, l1ToL2MessageSource, contractDataSource, worldState, p2pClient, epochsMonitor, rollupContract, l1Metrics, config = {}, telemetryClient = getTelemetryClient()){
44
435
  this.prover = prover;
45
- this.publisher = publisher;
436
+ this.publisherFactory = publisherFactory;
46
437
  this.l2BlockSource = l2BlockSource;
47
438
  this.l1ToL2MessageSource = l1ToL2MessageSource;
48
439
  this.contractDataSource = contractDataSource;
49
440
  this.worldState = worldState;
50
- this.coordination = coordination;
441
+ this.p2pClient = p2pClient;
51
442
  this.epochsMonitor = epochsMonitor;
443
+ this.rollupContract = rollupContract;
444
+ this.l1Metrics = l1Metrics;
52
445
  this.telemetryClient = telemetryClient;
53
- this.log = createLogger('prover-node');
446
+ this.log = (_initProto(this), createLogger('prover-node'));
54
447
  this.dateProvider = new DateProvider();
55
448
  this.jobs = new Map();
56
- this.cachedEpochData = undefined;
57
- this.options = {
58
- pollingIntervalMs: 1_000,
59
- maxPendingJobs: 100,
60
- maxParallelBlocksPerEpoch: 32,
61
- txGatheringTimeoutMs: 60_000,
449
+ this.config = {
450
+ proverNodePollingIntervalMs: 1_000,
451
+ proverNodeMaxPendingJobs: 100,
452
+ proverNodeMaxParallelBlocksPerEpoch: 32,
62
453
  txGatheringIntervalMs: 1_000,
63
- txGatheringMaxParallelRequests: 100,
64
- ...compact(options)
454
+ txGatheringBatchSize: 10,
455
+ txGatheringMaxParallelRequestsPerNode: 100,
456
+ txGatheringTimeoutMs: 120_000,
457
+ proverNodeFailedEpochStore: undefined,
458
+ proverNodeEpochProvingDelayMs: undefined,
459
+ ...compact(config)
65
460
  };
66
- this.metrics = new ProverNodeMetrics(telemetryClient, 'ProverNode');
461
+ this.validateConfig();
462
+ const meter = telemetryClient.getMeter('ProverNode');
67
463
  this.tracer = telemetryClient.getTracer('ProverNode');
68
- this.txFetcher = new RunningPromise(()=>this.checkForTxs(), this.log, this.options.txGatheringIntervalMs);
464
+ this.jobMetrics = new ProverNodeJobMetrics(meter, telemetryClient.getTracer('EpochProvingJob'));
465
+ this.rewardsMetrics = new ProverNodeRewardsMetrics(meter, this.prover.getProverId(), rollupContract);
69
466
  }
70
467
  getProverId() {
71
468
  return this.prover.getProverId();
72
469
  }
73
470
  getP2P() {
74
- const asP2PClient = this.coordination;
75
- if (typeof asP2PClient.isP2PClient === 'function' && asP2PClient.isP2PClient()) {
76
- return asP2PClient;
77
- }
78
- return undefined;
471
+ return this.p2pClient;
79
472
  }
80
473
  /**
81
474
  * Handles an epoch being completed by starting a proof for it if there are no active jobs for it.
82
475
  * @param epochNumber - The epoch number that was just completed.
476
+ * @returns false if there is an error, true otherwise
83
477
  */ async handleEpochReadyToProve(epochNumber) {
84
478
  try {
85
- this.log.debug('jobs', JSON.stringify(this.jobs, null, 2));
479
+ this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
480
+ jobs: Array.from(this.jobs.values()).map((job)=>`${job.getEpochNumber()}:${job.getId()}`)
481
+ });
86
482
  const activeJobs = await this.getActiveJobsForEpoch(epochNumber);
87
483
  if (activeJobs.length > 0) {
88
- this.log.info(`Not starting proof for ${epochNumber} since there are active jobs`);
89
- return;
484
+ this.log.warn(`Not starting proof for ${epochNumber} since there are active jobs for the epoch`, {
485
+ activeJobs: activeJobs.map((job)=>job.uuid)
486
+ });
487
+ return true;
90
488
  }
91
- // TODO: we probably want to skip starting a proof if we are too far into the current epoch
92
489
  await this.startProof(epochNumber);
490
+ return true;
93
491
  } catch (err) {
94
492
  if (err instanceof EmptyEpochError) {
95
493
  this.log.info(`Not starting proof for ${epochNumber} since no blocks were found`);
96
494
  } else {
97
495
  this.log.error(`Error handling epoch completed`, err);
98
496
  }
497
+ return false;
99
498
  }
100
499
  }
101
500
  /**
102
- * Starts the prover node so it periodically checks for unproven epochs in the unfinalised chain from L1 and
501
+ * Starts the prover node so it periodically checks for unproven epochs in the unfinalized chain from L1 and
103
502
  * starts proving jobs for them.
104
- */ start() {
105
- this.txFetcher.start();
503
+ */ async start() {
106
504
  this.epochsMonitor.start(this);
107
- this.log.info('Started ProverNode', this.options);
505
+ await this.publisherFactory.start();
506
+ this.publisher = await this.publisherFactory.create();
507
+ await this.rewardsMetrics.start();
508
+ this.l1Metrics.start();
509
+ this.log.info(`Started Prover Node with prover id ${this.prover.getProverId().toString()}`, this.config);
108
510
  }
109
511
  /**
110
512
  * Stops the prover node and all its dependencies.
111
513
  */ async stop() {
112
514
  this.log.info('Stopping ProverNode');
113
- await this.txFetcher.stop();
114
515
  await this.epochsMonitor.stop();
115
516
  await this.prover.stop();
517
+ await tryStop(this.p2pClient);
116
518
  await tryStop(this.l2BlockSource);
117
- this.publisher.interrupt();
519
+ await tryStop(this.publisherFactory);
520
+ this.publisher?.interrupt();
118
521
  await Promise.all(Array.from(this.jobs.values()).map((job)=>job.stop()));
119
522
  await this.worldState.stop();
120
- await tryStop(this.coordination);
523
+ this.rewardsMetrics.stop();
524
+ this.l1Metrics.stop();
121
525
  await this.telemetryClient.stop();
122
526
  this.log.info('Stopped ProverNode');
123
527
  }
124
- /**
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();
528
+ /** Returns world state status. */ async getWorldStateSyncStatus() {
529
+ const { syncSummary } = await this.worldState.status();
530
+ return syncSummary;
531
+ }
532
+ /** Returns archiver status. */ getL2Tips() {
533
+ return this.l2BlockSource.getL2Tips();
129
534
  }
130
535
  /**
131
536
  * Starts a proving process and returns immediately.
132
537
  */ async startProof(epochNumber) {
133
- const job = await this.createProvingJob(BigInt(epochNumber));
134
- void job.run().catch((err)=>this.log.error(`Error proving epoch ${epochNumber}`, err));
538
+ const job = await this.createProvingJob(epochNumber, {
539
+ skipEpochCheck: true
540
+ });
541
+ void this.runJob(job);
542
+ }
543
+ async runJob(job) {
544
+ const epochNumber = job.getEpochNumber();
545
+ const ctx = {
546
+ id: job.getId(),
547
+ epochNumber,
548
+ state: undefined
549
+ };
550
+ try {
551
+ await job.run();
552
+ const state = job.getState();
553
+ ctx.state = state;
554
+ if (state === 'reorg') {
555
+ this.log.warn(`Running new job for epoch ${epochNumber} due to reorg`, ctx);
556
+ await this.createProvingJob(epochNumber);
557
+ } else if (state === 'failed') {
558
+ this.log.error(`Job for ${epochNumber} exited with state ${state}`, ctx);
559
+ await this.tryUploadEpochFailure(job);
560
+ } else {
561
+ this.log.verbose(`Job for ${epochNumber} exited with state ${state}`, ctx);
562
+ }
563
+ } catch (err) {
564
+ this.log.error(`Error proving epoch ${epochNumber}`, err, ctx);
565
+ } finally{
566
+ this.jobs.delete(job.getId());
567
+ }
568
+ }
569
+ async tryUploadEpochFailure(job) {
570
+ if (this.config.proverNodeFailedEpochStore) {
571
+ return await uploadEpochProofFailure(this.config.proverNodeFailedEpochStore, job.getId(), job.getProvingData(), this.l2BlockSource, this.worldState, assertRequired(pick(this.config, 'l1ChainId', 'rollupVersion', 'dataDirectory')), this.log);
572
+ }
135
573
  }
136
574
  /**
137
575
  * Returns the prover instance.
@@ -144,112 +582,126 @@ import { ProverNodeMetrics } from './metrics.js';
144
582
  return Promise.resolve(Array.from(this.jobs.entries()).map(([uuid, job])=>({
145
583
  uuid,
146
584
  status: job.getState(),
147
- epochNumber: Number(job.getEpochNumber())
585
+ epochNumber: job.getEpochNumber()
148
586
  })));
149
587
  }
150
- async getActiveJobsForEpoch(epochBigInt) {
588
+ async getActiveJobsForEpoch(epochNumber) {
151
589
  const jobs = await this.getJobs();
152
- const epochNumber = Number(epochBigInt);
153
590
  return jobs.filter((job)=>job.epochNumber === epochNumber && !EpochProvingJobTerminalState.includes(job.status));
154
591
  }
155
592
  checkMaximumPendingJobs() {
156
- const { maxPendingJobs } = this.options;
157
- return maxPendingJobs === 0 || this.jobs.size < maxPendingJobs;
158
- }
159
- async createProvingJob(epochNumber) {
160
- if (!this.checkMaximumPendingJobs()) {
161
- throw new Error(`Maximum pending proving jobs ${this.options.maxPendingJobs} reached. Cannot create new job.`);
593
+ const { proverNodeMaxPendingJobs: maxPendingJobs } = this.config;
594
+ if (maxPendingJobs > 0 && this.jobs.size >= maxPendingJobs) {
595
+ throw new Error(`Maximum pending proving jobs ${maxPendingJobs} reached. Cannot create new job.`);
162
596
  }
163
- // Gather blocks for this epoch
164
- const cachedEpochData = this.cachedEpochData?.epochNumber === epochNumber ? this.cachedEpochData : undefined;
165
- const { blocks, txs } = cachedEpochData ?? await this.gatherEpochData(epochNumber);
166
- const fromBlock = blocks[0].number;
167
- const toBlock = blocks.at(-1).number;
597
+ }
598
+ async createProvingJob(epochNumber, opts = {}) {
599
+ this.checkMaximumPendingJobs();
600
+ this.publisher = await this.publisherFactory.create();
601
+ // Gather all data for this epoch
602
+ const epochData = await this.gatherEpochData(epochNumber);
603
+ const fromCheckpoint = epochData.checkpoints[0].number;
604
+ const toCheckpoint = epochData.checkpoints.at(-1).number;
605
+ const fromBlock = epochData.checkpoints[0].blocks[0].number;
606
+ const toBlock = epochData.checkpoints.at(-1).blocks.at(-1).number;
607
+ this.log.verbose(`Creating proving job for epoch ${epochNumber} for checkpoint range ${fromCheckpoint} to ${toCheckpoint} and block range ${fromBlock} to ${toBlock}`);
168
608
  // Fast forward world state to right before the target block and get a fork
169
- this.log.verbose(`Creating proving job for epoch ${epochNumber} for block range ${fromBlock} to ${toBlock}`);
170
609
  await this.worldState.syncImmediate(toBlock);
171
- // Create a processor using the forked world state
610
+ // Create a processor factory
172
611
  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
- const [_, endTimestamp] = getTimestampRangeForEpoch(epochNumber + 1n, await this.getL1Constants());
178
- const deadline = new Date(Number(endTimestamp) * 1000);
179
- const job = this.doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory, cleanUp);
612
+ // Set deadline for this job to run. It will abort if it takes too long.
613
+ const deadlineTs = getProofSubmissionDeadlineTimestamp(epochNumber, await this.getL1Constants());
614
+ const deadline = new Date(Number(deadlineTs) * 1000);
615
+ const job = this.doCreateEpochProvingJob(epochData, deadline, publicProcessorFactory, this.publisher, opts);
180
616
  this.jobs.set(job.getId(), job);
181
617
  return job;
182
618
  }
183
619
  getL1Constants() {
184
620
  return this.l2BlockSource.getL1Constants();
185
621
  }
186
- /** Monitors for new blocks and requests their txs from the p2p layer to ensure they are available for proving. */ async checkForTxs() {
187
- const blockNumber = await this.l2BlockSource.getBlockNumber();
188
- if (this.lastBlockNumber === undefined || blockNumber > this.lastBlockNumber) {
189
- const block = await this.l2BlockSource.getBlock(blockNumber);
190
- if (!block) {
191
- return;
192
- }
193
- const txHashes = block.body.txEffects.map((tx)=>tx.txHash);
194
- this.log.verbose(`Fetching ${txHashes.length} tx hashes for block number ${blockNumber} from coordination`);
195
- await this.coordination.getTxsByHash(txHashes); // This stores the txs in the tx pool, no need to persist them here
196
- this.lastBlockNumber = blockNumber;
197
- }
198
- }
199
622
  async gatherEpochData(epochNumber) {
200
- // Gather blocks for this epoch and their txs
201
- const blocks = await this.gatherBlocks(epochNumber);
202
- const txs = await this.gatherTxs(epochNumber, blocks);
623
+ const checkpoints = await this.gatherCheckpoints(epochNumber);
624
+ const txArray = await this.gatherTxs(epochNumber, checkpoints);
625
+ const txs = new Map(txArray.map((tx)=>[
626
+ tx.getTxHash().toString(),
627
+ tx
628
+ ]));
629
+ const l1ToL2Messages = await this.gatherMessages(epochNumber, checkpoints);
630
+ const [firstBlock] = checkpoints[0].blocks;
631
+ const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, firstBlock.number - 1);
632
+ const [lastPublishedCheckpoint] = await this.l2BlockSource.getPublishedCheckpoints(checkpoints.at(-1).number, 1);
633
+ const attestations = lastPublishedCheckpoint?.attestations ?? [];
203
634
  return {
204
- blocks,
205
- txs
635
+ checkpoints,
636
+ txs,
637
+ l1ToL2Messages,
638
+ epochNumber,
639
+ previousBlockHeader,
640
+ attestations
206
641
  };
207
642
  }
208
- async gatherBlocks(epochNumber) {
209
- const blocks = await this.l2BlockSource.getBlocksForEpoch(epochNumber);
210
- if (blocks.length === 0) {
643
+ async gatherCheckpoints(epochNumber) {
644
+ const checkpoints = await this.l2BlockSource.getCheckpointsForEpoch(epochNumber);
645
+ if (checkpoints.length === 0) {
211
646
  throw new EmptyEpochError(epochNumber);
212
647
  }
213
- return blocks;
648
+ return checkpoints;
214
649
  }
215
- async gatherTxs(epochNumber, blocks) {
216
- const txsToFind = blocks.flatMap((block)=>block.body.txEffects.map((tx)=>tx.txHash));
217
- const txs = await this.coordination.getTxsByHash(txsToFind);
218
- if (txs.length === txsToFind.length) {
650
+ async gatherTxs(epochNumber, checkpoints) {
651
+ const deadline = new Date(this.dateProvider.now() + this.config.txGatheringTimeoutMs);
652
+ const txProvider = this.p2pClient.getTxProvider();
653
+ const blocks = checkpoints.flatMap((checkpoint)=>checkpoint.blocks);
654
+ const txsByBlock = await Promise.all(blocks.map((block)=>txProvider.getTxsForBlock(block, {
655
+ deadline
656
+ })));
657
+ const txs = txsByBlock.map(({ txs })=>txs).flat();
658
+ const missingTxs = txsByBlock.map(({ missingTxs })=>missingTxs).flat();
659
+ if (missingTxs.length === 0) {
219
660
  this.log.verbose(`Gathered all ${txs.length} txs for epoch ${epochNumber}`, {
220
661
  epochNumber
221
662
  });
222
663
  return txs;
223
664
  }
224
- const txHashesFound = await Promise.all(txs.map((tx)=>tx.getTxHash()));
225
- const missingTxHashes = txsToFind.filter((txHashToFind)=>!txHashesFound.some((txHashFound)=>txHashToFind.equals(txHashFound))).join(', ');
226
- throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxHashes}`);
665
+ throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxs.map((hash)=>hash.toString()).join(', ')}`);
227
666
  }
228
- /** Extracted for testing purposes. */ doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory, cleanUp) {
229
- return new EpochProvingJob(this.worldState, epochNumber, blocks, txs, this.prover.createEpochProver(), publicProcessorFactory, this.publisher, this.l2BlockSource, this.l1ToL2MessageSource, this.metrics, deadline, {
230
- parallelBlockLimit: this.options.maxParallelBlocksPerEpoch
231
- }, cleanUp);
667
+ async gatherMessages(epochNumber, checkpoints) {
668
+ const messages = await Promise.all(checkpoints.map((c)=>this.l1ToL2MessageSource.getL1ToL2Messages(c.number)));
669
+ const messageCount = sum(messages.map((m)=>m.length));
670
+ this.log.verbose(`Gathered all ${messageCount} messages for epoch ${epochNumber}`, {
671
+ epochNumber
672
+ });
673
+ const messagesByCheckpoint = {};
674
+ for(let i = 0; i < checkpoints.length; i++){
675
+ messagesByCheckpoint[checkpoints[i].number] = messages[i];
676
+ }
677
+ return messagesByCheckpoint;
678
+ }
679
+ async gatherPreviousBlockHeader(epochNumber, previousBlockNumber) {
680
+ const header = await (previousBlockNumber === 0 ? this.worldState.getCommitted().getInitialHeader() : this.l2BlockSource.getBlockHeader(BlockNumber(previousBlockNumber)));
681
+ if (!header) {
682
+ throw new Error(`Previous block header ${previousBlockNumber} not found for proving epoch ${epochNumber}`);
683
+ }
684
+ this.log.verbose(`Gathered previous block header ${header.getBlockNumber()} for epoch ${epochNumber}`);
685
+ return header;
686
+ }
687
+ /** Extracted for testing purposes. */ doCreateEpochProvingJob(data, deadline, publicProcessorFactory, publisher, opts = {}) {
688
+ const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit, proverNodeDisableProofPublish } = this.config;
689
+ return new EpochProvingJob(data, this.worldState, this.prover.createEpochProver(), publicProcessorFactory, publisher, this.l2BlockSource, this.jobMetrics, deadline, {
690
+ parallelBlockLimit,
691
+ skipSubmitProof: proverNodeDisableProofPublish,
692
+ ...opts
693
+ });
232
694
  }
233
695
  /** Extracted for testing purposes. */ async triggerMonitors() {
234
696
  await this.epochsMonitor.work();
235
697
  }
698
+ validateConfig() {
699
+ if (this.config.proverNodeFailedEpochStore && (!this.config.dataDirectory || !this.config.l1ChainId || this.config.rollupVersion === undefined)) {
700
+ this.log.warn(`Invalid prover-node config (missing dataDirectory, l1ChainId, or rollupVersion)`, pick(this.config, 'proverNodeFailedEpochStore', 'dataDirectory', 'l1ChainId', 'rollupVersion'));
701
+ throw new Error('All of dataDirectory, l1ChainId, and rollupVersion are required if proverNodeFailedEpochStore is set.');
702
+ }
703
+ }
236
704
  }
237
- _ts_decorate([
238
- trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
239
- [Attributes.EPOCH_NUMBER]: Number(epochNumber)
240
- }))
241
- ], ProverNode.prototype, "createProvingJob", null);
242
- _ts_decorate([
243
- memoize
244
- ], ProverNode.prototype, "getL1Constants", null);
245
- _ts_decorate([
246
- trackSpan('ProverNode.checkForTxs')
247
- ], ProverNode.prototype, "checkForTxs", null);
248
- _ts_decorate([
249
- trackSpan('ProverNode.gatherEpochData', (epochNumber)=>({
250
- [Attributes.EPOCH_NUMBER]: Number(epochNumber)
251
- }))
252
- ], ProverNode.prototype, "gatherEpochData", null);
253
705
  class EmptyEpochError extends Error {
254
706
  constructor(epochNumber){
255
707
  super(`No blocks found for epoch ${epochNumber}`);