@aztec/prover-node 0.86.0 → 0.87.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.
Files changed (59) 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 +2 -2
  17. package/dest/config.d.ts.map +1 -1
  18. package/dest/config.js +5 -0
  19. package/dest/factory.d.ts.map +1 -1
  20. package/dest/factory.js +5 -5
  21. package/dest/index.d.ts +1 -0
  22. package/dest/index.d.ts.map +1 -1
  23. package/dest/index.js +1 -0
  24. package/dest/job/epoch-proving-job-data.d.ts +15 -0
  25. package/dest/job/epoch-proving-job-data.d.ts.map +1 -0
  26. package/dest/job/epoch-proving-job-data.js +45 -0
  27. package/dest/job/epoch-proving-job.d.ts +10 -9
  28. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  29. package/dest/job/epoch-proving-job.js +41 -24
  30. package/dest/metrics.js +2 -2
  31. package/dest/prover-coordination/combined-prover-coordination.d.ts.map +1 -1
  32. package/dest/prover-coordination/combined-prover-coordination.js +7 -4
  33. package/dest/prover-coordination/config.d.ts.map +1 -1
  34. package/dest/prover-coordination/config.js +2 -1
  35. package/dest/prover-coordination/factory.d.ts.map +1 -1
  36. package/dest/prover-coordination/factory.js +8 -4
  37. package/dest/prover-node.d.ts +23 -18
  38. package/dest/prover-node.d.ts.map +1 -1
  39. package/dest/prover-node.js +88 -37
  40. package/dest/test/index.d.ts +4 -2
  41. package/dest/test/index.d.ts.map +1 -1
  42. package/dest/test/index.js +1 -1
  43. package/package.json +25 -24
  44. package/src/actions/download-epoch-proving-job.ts +44 -0
  45. package/src/actions/index.ts +2 -0
  46. package/src/actions/rerun-epoch-proving-job.ts +61 -0
  47. package/src/actions/upload-epoch-proof-failure.ts +88 -0
  48. package/src/bin/run-failed-epoch.ts +77 -0
  49. package/src/config.ts +7 -1
  50. package/src/factory.ts +21 -7
  51. package/src/index.ts +1 -0
  52. package/src/job/epoch-proving-job-data.ts +68 -0
  53. package/src/job/epoch-proving-job.ts +55 -23
  54. package/src/metrics.ts +2 -2
  55. package/src/prover-coordination/combined-prover-coordination.ts +9 -6
  56. package/src/prover-coordination/config.ts +1 -0
  57. package/src/prover-coordination/factory.ts +7 -4
  58. package/src/prover-node.ts +120 -53
  59. package/src/test/index.ts +7 -4
@@ -11,20 +11,18 @@ import { Timer } from '@aztec/foundation/timer';
11
11
  import { EpochProvingJobTerminalState } from '@aztec/stdlib/interfaces/server';
12
12
  import { Attributes, trackSpan } from '@aztec/telemetry-client';
13
13
  import * as crypto from 'node:crypto';
14
+ import { validateEpochProvingJobData } from './epoch-proving-job-data.js';
14
15
  /**
15
16
  * Job that grabs a range of blocks from the unfinalised chain from L1, gets their txs given their hashes,
16
17
  * re-executes their public calls, generates a rollup proof, and submits it to L1. This job will update the
17
18
  * world state as part of public call execution via the public processor.
18
19
  */ export class EpochProvingJob {
20
+ data;
19
21
  dbProvider;
20
- epochNumber;
21
- blocks;
22
- txs;
23
22
  prover;
24
23
  publicProcessorFactory;
25
24
  publisher;
26
25
  l2BlockSource;
27
- l1ToL2MessageSource;
28
26
  metrics;
29
27
  deadline;
30
28
  config;
@@ -35,23 +33,19 @@ import * as crypto from 'node:crypto';
35
33
  epochCheckPromise;
36
34
  deadlineTimeoutHandler;
37
35
  tracer;
38
- constructor(dbProvider, epochNumber, blocks, txs, prover, publicProcessorFactory, publisher, l2BlockSource, l1ToL2MessageSource, metrics, deadline, config = {
39
- parallelBlockLimit: 32
40
- }){
36
+ constructor(data, dbProvider, prover, publicProcessorFactory, publisher, l2BlockSource, metrics, deadline, config){
37
+ this.data = data;
41
38
  this.dbProvider = dbProvider;
42
- this.epochNumber = epochNumber;
43
- this.blocks = blocks;
44
- this.txs = txs;
45
39
  this.prover = prover;
46
40
  this.publicProcessorFactory = publicProcessorFactory;
47
41
  this.publisher = publisher;
48
42
  this.l2BlockSource = l2BlockSource;
49
- this.l1ToL2MessageSource = l1ToL2MessageSource;
50
43
  this.metrics = metrics;
51
44
  this.deadline = deadline;
52
45
  this.config = config;
53
46
  this.state = 'initialized';
54
47
  this.log = createLogger('prover-node:epoch-proving-job');
48
+ validateEpochProvingJobData(data);
55
49
  this.uuid = crypto.randomUUID();
56
50
  this.tracer = metrics.tracer;
57
51
  }
@@ -62,16 +56,30 @@ import * as crypto from 'node:crypto';
62
56
  return this.state;
63
57
  }
64
58
  getEpochNumber() {
65
- return this.epochNumber;
59
+ return this.data.epochNumber;
66
60
  }
67
61
  getDeadline() {
68
62
  return this.deadline;
69
63
  }
64
+ getProvingData() {
65
+ return this.data;
66
+ }
67
+ get epochNumber() {
68
+ return this.data.epochNumber;
69
+ }
70
+ get blocks() {
71
+ return this.data.blocks;
72
+ }
73
+ get txs() {
74
+ return this.data.txs;
75
+ }
70
76
  /**
71
77
  * Proves the given epoch and submits the proof to L1.
72
78
  */ async run() {
73
79
  this.scheduleDeadlineStop();
74
- await this.scheduleEpochCheck();
80
+ if (!this.config.skipEpochCheck) {
81
+ await this.scheduleEpochCheck();
82
+ }
75
83
  const epochNumber = Number(this.epochNumber);
76
84
  const epochSizeBlocks = this.blocks.length;
77
85
  const epochSizeTxs = this.blocks.reduce((total, current)=>total + current.body.txEffects.length, 0);
@@ -93,12 +101,12 @@ import * as crypto from 'node:crypto';
93
101
  try {
94
102
  this.prover.startNewEpoch(epochNumber, fromBlock, epochSizeBlocks);
95
103
  await this.prover.startTubeCircuits(this.txs);
96
- await asyncPool(this.config.parallelBlockLimit, this.blocks, async (block)=>{
104
+ await asyncPool(this.config.parallelBlockLimit ?? 32, this.blocks, async (block)=>{
97
105
  this.checkState();
98
106
  const globalVariables = block.header.globalVariables;
99
107
  const txs = await this.getTxs(block);
100
- const l1ToL2Messages = await this.getL1ToL2Messages(block);
101
- const previousHeader = await this.getBlockHeader(block.number - 1);
108
+ const l1ToL2Messages = this.getL1ToL2Messages(block);
109
+ const previousHeader = this.getBlockHeader(block.number - 1);
102
110
  this.log.verbose(`Starting processing block ${block.number}`, {
103
111
  number: block.number,
104
112
  blockHash: (await block.hash()).toString(),
@@ -217,9 +225,14 @@ import * as crypto from 'node:crypto';
217
225
  * Kicks off a running promise that queries the archiver for the set of L2 blocks of the current epoch.
218
226
  * If those change, stops the proving job with a `rerun` state, so the node re-enqueues it.
219
227
  */ async scheduleEpochCheck() {
220
- const intervalMs = Math.ceil((await this.l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
228
+ const l2BlockSource = this.l2BlockSource;
229
+ if (!l2BlockSource) {
230
+ this.log.warn(`No L2 block source available, skipping epoch check`);
231
+ return;
232
+ }
233
+ const intervalMs = Math.ceil((await l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
221
234
  this.epochCheckPromise = new RunningPromise(async ()=>{
222
- const blocks = await this.l2BlockSource.getBlockHeadersForEpoch(this.epochNumber);
235
+ const blocks = await l2BlockSource.getBlockHeadersForEpoch(this.epochNumber);
223
236
  const blockHashes = await Promise.all(blocks.map((block)=>block.hash()));
224
237
  const thisBlockHashes = await Promise.all(this.blocks.map((block)=>block.hash()));
225
238
  if (blocks.length !== this.blocks.length || !blockHashes.every((block, i)=>block.equals(thisBlockHashes[i]))) {
@@ -234,11 +247,15 @@ import * as crypto from 'node:crypto';
234
247
  }, this.log, intervalMs).start();
235
248
  this.log.verbose(`Scheduled epoch check for epoch ${this.epochNumber} every ${intervalMs}ms`);
236
249
  }
237
- /* Returns the header for the given block number, or the genesis block for block zero. */ async getBlockHeader(blockNumber) {
238
- if (blockNumber === 0) {
239
- return (await this.dbProvider.fork()).getInitialHeader();
250
+ /* Returns the header for the given block number based on the epoch proving job data. */ getBlockHeader(blockNumber) {
251
+ const block = this.blocks.find((b)=>b.number === blockNumber);
252
+ if (block) {
253
+ return block.header;
254
+ }
255
+ if (blockNumber === Number(this.data.previousBlockHeader.getBlockNumber())) {
256
+ return this.data.previousBlockHeader;
240
257
  }
241
- return this.l2BlockSource.getBlockHeader(blockNumber);
258
+ throw new Error(`Block header not found for block number ${blockNumber} (got ${this.blocks.map((b)=>b.number).join(', ')} and previous header ${this.data.previousBlockHeader.getBlockNumber()})`);
242
259
  }
243
260
  async getTxs(block) {
244
261
  const txHashes = block.body.txEffects.map((tx)=>tx.txHash.toBigInt());
@@ -249,7 +266,7 @@ import * as crypto from 'node:crypto';
249
266
  return txsAndHashes.filter((txAndHash)=>txHashes.includes(txAndHash.hash.toBigInt())).map((txAndHash)=>txAndHash.tx);
250
267
  }
251
268
  getL1ToL2Messages(block) {
252
- return this.l1ToL2MessageSource.getL1ToL2Messages(BigInt(block.number));
269
+ return this.data.l1ToL2Messages[block.number];
253
270
  }
254
271
  async processTxs(publicProcessor, txs) {
255
272
  const { deadline } = this;
@@ -269,7 +286,7 @@ import * as crypto from 'node:crypto';
269
286
  _ts_decorate([
270
287
  trackSpan('EpochProvingJob.run', function() {
271
288
  return {
272
- [Attributes.EPOCH_NUMBER]: Number(this.epochNumber)
289
+ [Attributes.EPOCH_NUMBER]: Number(this.data.epochNumber)
273
290
  };
274
291
  })
275
292
  ], EpochProvingJob.prototype, "run", null);
package/dest/metrics.js CHANGED
@@ -217,7 +217,7 @@ export class ProverNodePublisherMetrics {
217
217
  this.txBlobDataGasUsed.record(Number(stats.blobGasUsed), attributes);
218
218
  try {
219
219
  this.gasPrice.record(parseInt(formatEther(stats.gasPrice, 'gwei'), 10));
220
- } catch (e) {
220
+ } catch {
221
221
  // ignore
222
222
  }
223
223
  const executionFee = stats.gasUsed * stats.gasPrice;
@@ -225,7 +225,7 @@ export class ProverNodePublisherMetrics {
225
225
  const totalFee = executionFee + blobFee;
226
226
  try {
227
227
  this.txTotalFee.record(parseFloat(formatEther(totalFee)));
228
- } catch (e) {
228
+ } catch {
229
229
  // ignore
230
230
  }
231
231
  }
@@ -1 +1 @@
1
- {"version":3,"file":"combined-prover-coordination.d.ts","sourceRoot":"","sources":["../../src/prover-coordination/combined-prover-coordination.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrF,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,MAAM,2BAA2B,GAAG;IAExC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qCAAqC,EAAE,MAAM,CAAC;CAC/C,CAAC;AASF,MAAM,WAAW,QAAQ;IACvB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;CAC/D;AAsCD,qBAAa,0BAA2B,YAAW,kBAAkB;;aAEjD,GAAG,EAAE,GAAG,GAAG,SAAS;aACpB,UAAU,EAAE,QAAQ,EAAE;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAIxB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBANJ,GAAG,EAAE,GAAG,GAAG,SAAS,EACpB,UAAU,EAAE,QAAQ,EAAE,EACrB,OAAO,GAAE,2BAGzB,EACgB,GAAG,yCAA2D;IAG1E,YAAY,IAAI,SAAS,GAAG,SAAS;IAI/B,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC;IAY/C,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAyE1D"}
1
+ {"version":3,"file":"combined-prover-coordination.d.ts","sourceRoot":"","sources":["../../src/prover-coordination/combined-prover-coordination.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrF,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,MAAM,2BAA2B,GAAG;IAExC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qCAAqC,EAAE,MAAM,CAAC;CAC/C,CAAC;AASF,MAAM,WAAW,QAAQ;IACvB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;CAC/D;AAsCD,qBAAa,0BAA2B,YAAW,kBAAkB;;aAEjD,GAAG,EAAE,GAAG,GAAG,SAAS;aACpB,UAAU,EAAE,QAAQ,EAAE;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAIxB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBANJ,GAAG,EAAE,GAAG,GAAG,SAAS,EACpB,UAAU,EAAE,QAAQ,EAAE,EACrB,OAAO,GAAE,2BAGzB,EACgB,GAAG,yCAA2D;IAG1E,YAAY,IAAI,SAAS,GAAG,SAAS;IAI/B,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC;IAY/C,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA4E1D"}
@@ -75,7 +75,7 @@ export class CombinedProverCoordination {
75
75
  const notFound = txHashes.filter((_, index)=>!availability[index]);
76
76
  const txsToFind = new Set(notFound.map((tx)=>tx.toString()));
77
77
  if (txsToFind.size === 0) {
78
- this.log.info(`Check for ${txHashes.length} txs found all in the pool}`);
78
+ this.log.info(`Check for ${txHashes.length} txs found all in the pool`);
79
79
  return;
80
80
  }
81
81
  this.log.info(`Check for ${txHashes.length} txs found ${txsToFind.size} missing. Will gather from nodes and p2p`);
@@ -90,13 +90,16 @@ export class CombinedProverCoordination {
90
90
  const foundFromP2P = await pool.getTxsByHash([
91
91
  ...txsToFind
92
92
  ].map((tx)=>TxHash.fromString(tx)));
93
+ // TODO(!!): test for this
94
+ // getTxsByHash returns undefined for transactions that are not found, so it must be filtered to find the true length
95
+ const foundFromP2PLength = foundFromP2P.filter((tx)=>!!tx).length;
93
96
  const numFoundFromNodes = originalToFind - toFindFromP2P;
94
- const numNotFound = toFindFromP2P - foundFromP2P.length;
97
+ const numNotFound = toFindFromP2P - foundFromP2PLength;
95
98
  if (numNotFound === 0) {
96
- this.log.info(`Found all ${originalToFind} txs. ${numFoundFromNodes} from nodes, ${foundFromP2P.length} from p2p`);
99
+ this.log.info(`Found all ${originalToFind} txs. ${numFoundFromNodes} from nodes, ${foundFromP2PLength} from p2p`);
97
100
  return;
98
101
  }
99
- this.log.warn(`Failed to find ${numNotFound} txs from any source. Found ${foundFromP2P.length} from p2p and ${numFoundFromNodes} from nodes`);
102
+ this.log.warn(`Failed to find ${numNotFound} txs from any source. Found ${foundFromP2PLength} from p2p and ${numFoundFromNodes} from nodes`);
100
103
  }
101
104
  async #gatherTxsFromAllNodes(txsToFind, pool) {
102
105
  if (txsToFind.size === 0 || this.aztecNodes.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/prover-coordination/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAyB,MAAM,0BAA0B,CAAC;AAE1F,MAAM,MAAM,wBAAwB,GAAG;IACrC,0BAA0B,EAAE,MAAM,EAAE,CAAC;CACtC,CAAC;AAEF,eAAO,MAAM,gCAAgC,EAAE,kBAAkB,CAAC,wBAAwB,CAMzF,CAAC;AAEF,wBAAgB,0BAA0B,IAAI,wBAAwB,CAErE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/prover-coordination/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAyB,MAAM,0BAA0B,CAAC;AAE1F,MAAM,MAAM,wBAAwB,GAAG;IACrC,0BAA0B,EAAE,MAAM,EAAE,CAAC;CACtC,CAAC;AAEF,eAAO,MAAM,gCAAgC,EAAE,kBAAkB,CAAC,wBAAwB,CAOzF,CAAC;AAEF,wBAAgB,0BAA0B,IAAI,wBAAwB,CAErE"}
@@ -3,7 +3,8 @@ export const proverCoordinationConfigMappings = {
3
3
  proverCoordinationNodeUrls: {
4
4
  env: 'PROVER_COORDINATION_NODE_URLS',
5
5
  description: 'The URLs of the tx provider nodes',
6
- parseEnv: (val)=>val.split(',').map((url)=>url.trim().replace(/\/$/, ''))
6
+ parseEnv: (val)=>val.split(',').map((url)=>url.trim().replace(/\/$/, '')),
7
+ defaultValue: []
7
8
  }
8
9
  };
9
10
  export function getTxProviderConfigFromEnv() {
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/prover-coordination/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAK9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAGlG,OAAO,EAAE,KAAK,eAAe,EAAmB,MAAM,yBAAyB,CAAC;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,mCAAmC,CAAC;AAG3C,KAAK,sBAAsB,GAAG;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC;IAC/B,sBAAsB,EAAE,sBAAsB,CAAC;IAC/C,QAAQ,EAAE,QAAQ,GAAG,aAAa,CAAC;IACnC,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,gBAAgB,GAAG,eAAe,EAC1C,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA2C7B"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/prover-coordination/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAK9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAIlG,OAAO,EAAE,KAAK,eAAe,EAAmB,MAAM,yBAAyB,CAAC;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,mCAAmC,CAAC;AAG3C,KAAK,sBAAsB,GAAG;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC;IAC/B,sBAAsB,EAAE,sBAAsB,CAAC;IAC/C,QAAQ,EAAE,QAAQ,GAAG,aAAa,CAAC;IACnC,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,gBAAgB,GAAG,eAAe,EAC1C,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA6C7B"}
@@ -5,6 +5,7 @@ import { createP2PClient } from '@aztec/p2p';
5
5
  import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
6
6
  import { createAztecNodeClient } from '@aztec/stdlib/interfaces/client';
7
7
  import { P2PClientType } from '@aztec/stdlib/p2p';
8
+ import { getPackageVersion } from '@aztec/stdlib/update-checker';
8
9
  import { getComponentsVersionsFromConfig } from '@aztec/stdlib/versioning';
9
10
  import { makeTracedFetch } from '@aztec/telemetry-client';
10
11
  import { CombinedProverCoordination } from './combined-prover-coordination.js';
@@ -32,17 +33,20 @@ import { CombinedProverCoordination } from './combined-prover-coordination.js';
32
33
  }
33
34
  }
34
35
  let nodes = [];
35
- if (config.proverCoordinationNodeUrls.length > 0) {
36
+ if (config.proverCoordinationNodeUrls && config.proverCoordinationNodeUrls.length > 0) {
36
37
  log.info('Using prover coordination via node urls');
37
38
  const versions = getComponentsVersionsFromConfig(config, protocolContractTreeRoot, getVKTreeRoot());
38
- nodes = config.proverCoordinationNodeUrls.map((url)=>createAztecNodeClient(url, versions, makeTracedFetch([
39
+ nodes = config.proverCoordinationNodeUrls.map((url)=>{
40
+ log.info(`Creating aztec node client for prover coordination with url: ${url}`);
41
+ return createAztecNodeClient(url, versions, makeTracedFetch([
39
42
  1,
40
43
  2,
41
44
  3
42
- ], false)));
45
+ ], false));
46
+ });
43
47
  }
44
48
  const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
45
- const p2pClient = await createP2PClient(P2PClientType.Prover, config, deps.archiver, proofVerifier, deps.worldStateSynchronizer, deps.epochCache, deps.telemetry);
49
+ const p2pClient = await createP2PClient(P2PClientType.Prover, config, deps.archiver, proofVerifier, deps.worldStateSynchronizer, deps.epochCache, getPackageVersion() ?? '', deps.telemetry);
46
50
  await p2pClient.start();
47
51
  return new CombinedProverCoordination(p2pClient, nodes, coordinationConfig);
48
52
  }
@@ -1,48 +1,46 @@
1
- import type { Maybe } from '@aztec/foundation/types';
1
+ import type { Fr } from '@aztec/foundation/fields';
2
+ import type { DataStoreConfig } from '@aztec/kv-store/config';
2
3
  import { PublicProcessorFactory } from '@aztec/simulator/server';
3
- import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
4
+ import type { L2BlockSource } from '@aztec/stdlib/block';
5
+ import type { ChainConfig } from '@aztec/stdlib/config';
4
6
  import type { ContractDataSource } from '@aztec/stdlib/contract';
5
7
  import { type EpochProverManager, type ProverCoordination, type ProverNodeApi, type Service, type WorldStateSyncStatus, type WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
6
8
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
7
- import type { Tx } from '@aztec/stdlib/tx';
8
9
  import { type TelemetryClient, type Traceable, type Tracer } from '@aztec/telemetry-client';
10
+ import type { SpecificProverNodeConfig } from './config.js';
11
+ import type { EpochProvingJobData } from './job/epoch-proving-job-data.js';
9
12
  import { EpochProvingJob, type EpochProvingJobState } from './job/epoch-proving-job.js';
10
13
  import type { EpochMonitor, EpochMonitorHandler } from './monitors/epoch-monitor.js';
11
14
  import type { ProverNodePublisher } from './prover-node-publisher.js';
12
- export type ProverNodeOptions = {
13
- pollingIntervalMs: number;
14
- maxPendingJobs: number;
15
- maxParallelBlocksPerEpoch: number;
16
- txGatheringIntervalMs: number;
17
- };
15
+ type ProverNodeOptions = SpecificProverNodeConfig & Partial<DataStoreOptions>;
16
+ type DataStoreOptions = Pick<DataStoreConfig, 'dataDirectory'> & Pick<ChainConfig, 'l1ChainId' | 'rollupVersion'>;
18
17
  /**
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
18
+ * An Aztec Prover Node is a standalone process that monitors the unfinalised chain on L1 for unproven epochs,
19
+ * fetches their txs from the p2p network or external nodes, re-executes their public functions, creates a rollup
22
20
  * proof for the epoch, and submits it to L1.
23
21
  */
24
22
  export declare class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable {
25
23
  protected readonly prover: EpochProverManager;
26
24
  protected readonly publisher: ProverNodePublisher;
27
- protected readonly l2BlockSource: L2BlockSource & Maybe<Service>;
25
+ protected readonly l2BlockSource: L2BlockSource & Partial<Service>;
28
26
  protected readonly l1ToL2MessageSource: L1ToL2MessageSource;
29
27
  protected readonly contractDataSource: ContractDataSource;
30
28
  protected readonly worldState: WorldStateSynchronizer;
31
- protected readonly coordination: ProverCoordination;
29
+ protected readonly coordination: ProverCoordination & Partial<Service>;
32
30
  protected readonly epochsMonitor: EpochMonitor;
33
31
  protected readonly telemetryClient: TelemetryClient;
34
32
  private log;
35
33
  private dateProvider;
36
34
  private jobs;
37
- private options;
35
+ private config;
38
36
  private jobMetrics;
39
37
  private rewardsMetrics;
40
38
  private l1Metrics;
41
39
  private txFetcher;
42
40
  private lastBlockNumber;
43
41
  readonly tracer: Tracer;
44
- constructor(prover: EpochProverManager, publisher: ProverNodePublisher, l2BlockSource: L2BlockSource & Maybe<Service>, l1ToL2MessageSource: L1ToL2MessageSource, contractDataSource: ContractDataSource, worldState: WorldStateSynchronizer, coordination: ProverCoordination, epochsMonitor: EpochMonitor, options?: Partial<ProverNodeOptions>, telemetryClient?: TelemetryClient);
45
- getProverId(): import("@aztec/foundation/schemas").Fr;
42
+ constructor(prover: EpochProverManager, publisher: ProverNodePublisher, l2BlockSource: L2BlockSource & Partial<Service>, l1ToL2MessageSource: L1ToL2MessageSource, contractDataSource: ContractDataSource, worldState: WorldStateSynchronizer, coordination: ProverCoordination & Partial<Service>, epochsMonitor: EpochMonitor, config?: Partial<ProverNodeOptions>, telemetryClient?: TelemetryClient);
43
+ getProverId(): Fr;
46
44
  getP2P(): import("@aztec/stdlib/interfaces/server").P2PClient | undefined;
47
45
  /**
48
46
  * Handles an epoch being completed by starting a proof for it if there are no active jobs for it.
@@ -68,6 +66,7 @@ export declare class ProverNode implements EpochMonitorHandler, ProverNodeApi, T
68
66
  */
69
67
  startProof(epochNumber: number | bigint): Promise<void>;
70
68
  private runJob;
69
+ protected tryUploadEpochFailure(job: EpochProvingJob): Promise<string | undefined>;
71
70
  /**
72
71
  * Returns the prover instance.
73
72
  */
@@ -92,9 +91,15 @@ export declare class ProverNode implements EpochMonitorHandler, ProverNodeApi, T
92
91
  private gatherEpochData;
93
92
  private gatherBlocks;
94
93
  private gatherTxs;
94
+ private gatherMessages;
95
+ private gatherPreviousBlockHeader;
95
96
  /** Extracted for testing purposes. */
96
- protected doCreateEpochProvingJob(epochNumber: bigint, deadline: Date | undefined, blocks: L2Block[], txs: Tx[], publicProcessorFactory: PublicProcessorFactory): EpochProvingJob;
97
+ protected doCreateEpochProvingJob(data: EpochProvingJobData, deadline: Date | undefined, publicProcessorFactory: PublicProcessorFactory, opts?: {
98
+ skipEpochCheck?: boolean;
99
+ }): EpochProvingJob;
97
100
  /** Extracted for testing purposes. */
98
101
  protected triggerMonitors(): Promise<void>;
102
+ private validateConfig;
99
103
  }
104
+ export {};
100
105
  //# sourceMappingURL=prover-node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prover-node.d.ts","sourceRoot":"","sources":["../src/prover-node.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EACL,KAAK,kBAAkB,EAEvB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAE5B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,EAAU,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,MAAM,EAGZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAExF,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,yBAAyB,EAAE,MAAM,CAAC;IAClC,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,mBAAmB,EAAE,aAAa,EAAE,SAAS;IAgB5E,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB;IAC7C,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,mBAAmB;IACjD,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC;IAChE,SAAS,CAAC,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB;IAC3D,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB;IACzD,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,sBAAsB;IACrD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,kBAAkB;IACnD,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,YAAY;IAE9C,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,eAAe;IAxBrD,OAAO,CAAC,GAAG,CAA+B;IAC1C,OAAO,CAAC,YAAY,CAAsB;IAE1C,OAAO,CAAC,IAAI,CAA2C;IACvD,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,cAAc,CAA2B;IACjD,OAAO,CAAC,SAAS,CAAY;IAE7B,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,eAAe,CAAqB;IAE5C,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAGV,MAAM,EAAE,kBAAkB,EAC1B,SAAS,EAAE,mBAAmB,EAC9B,aAAa,EAAE,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,EAC7C,mBAAmB,EAAE,mBAAmB,EACxC,kBAAkB,EAAE,kBAAkB,EACtC,UAAU,EAAE,sBAAsB,EAClC,YAAY,EAAE,kBAAkB,EAChC,aAAa,EAAE,YAAY,EAC9C,OAAO,GAAE,OAAO,CAAC,iBAAiB,CAAM,EACrB,eAAe,GAAE,eAAsC;IA8BrE,WAAW;IAIX,MAAM;IAIb;;;;OAIG;IACG,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAwBpE;;;OAGG;IACG,KAAK;IAQX;;OAEG;IACG,IAAI;IAgBV,kCAAkC;IACrB,uBAAuB,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAKrE,+BAA+B;IACxB,SAAS;IAIhB;;OAEG;IACU,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;YAKtC,MAAM;IAkBpB;;OAEG;IACI,SAAS;IAIhB;;OAEG;IACI,OAAO,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,oBAAoB,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;cAUhF,qBAAqB,CACnC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,oBAAoB,CAAA;KAAE,EAAE,CAAC;IAM5D,OAAO,CAAC,uBAAuB;YAMjB,gBAAgB;IA8B9B,OAAO,CAAC,cAAc;IAItB,kHAAkH;YAEpG,WAAW;YAeX,eAAe;YAQf,YAAY;YAQZ,SAAS;IAiBvB,sCAAsC;IACtC,SAAS,CAAC,uBAAuB,CAC/B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,IAAI,GAAG,SAAS,EAC1B,MAAM,EAAE,OAAO,EAAE,EACjB,GAAG,EAAE,EAAE,EAAE,EACT,sBAAsB,EAAE,sBAAsB;IAkBhD,sCAAsC;cACtB,eAAe;CAGhC"}
1
+ {"version":3,"file":"prover-node.d.ts","sourceRoot":"","sources":["../src/prover-node.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ function _ts_decorate(decorators, target, key, desc) {
4
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
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  }
7
- import { compact } from '@aztec/foundation/collection';
7
+ import { assertRequired, compact, pick, sum } from '@aztec/foundation/collection';
8
8
  import { memoize } from '@aztec/foundation/decorators';
9
9
  import { EthAddress } from '@aztec/foundation/eth-address';
10
10
  import { createLogger } from '@aztec/foundation/log';
@@ -14,12 +14,12 @@ import { PublicProcessorFactory } from '@aztec/simulator/server';
14
14
  import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
15
15
  import { EpochProvingJobTerminalState, tryStop } from '@aztec/stdlib/interfaces/server';
16
16
  import { Attributes, L1Metrics, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
17
+ import { uploadEpochProofFailure } from './actions/upload-epoch-proof-failure.js';
17
18
  import { EpochProvingJob } from './job/epoch-proving-job.js';
18
19
  import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
19
20
  /**
20
- * An Aztec Prover Node is a standalone process that monitors the unfinalised chain on L1 for unproven blocks,
21
- * submits bids for proving them, and monitors if they are accepted. If so, the prover node fetches the txs
22
- * from a tx source in the p2p network or an external node, re-executes their public functions, creates a rollup
21
+ * An Aztec Prover Node is a standalone process that monitors the unfinalised chain on L1 for unproven epochs,
22
+ * fetches their txs from the p2p network or external nodes, re-executes their public functions, creates a rollup
23
23
  * proof for the epoch, and submits it to L1.
24
24
  */ export class ProverNode {
25
25
  prover;
@@ -34,14 +34,14 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
34
34
  log;
35
35
  dateProvider;
36
36
  jobs;
37
- options;
37
+ config;
38
38
  jobMetrics;
39
39
  rewardsMetrics;
40
40
  l1Metrics;
41
41
  txFetcher;
42
42
  lastBlockNumber;
43
43
  tracer;
44
- constructor(prover, publisher, l2BlockSource, l1ToL2MessageSource, contractDataSource, worldState, coordination, epochsMonitor, options = {}, telemetryClient = getTelemetryClient()){
44
+ constructor(prover, publisher, l2BlockSource, l1ToL2MessageSource, contractDataSource, worldState, coordination, epochsMonitor, config = {}, telemetryClient = getTelemetryClient()){
45
45
  this.prover = prover;
46
46
  this.publisher = publisher;
47
47
  this.l2BlockSource = l2BlockSource;
@@ -57,18 +57,22 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
57
57
  this.l1Metrics = new L1Metrics(telemetryClient.getMeter('ProverNodeL1Metrics'), publisher.l1TxUtils.client, [
58
58
  publisher.getSenderAddress()
59
59
  ]);
60
- this.options = {
61
- pollingIntervalMs: 1_000,
62
- maxPendingJobs: 100,
63
- maxParallelBlocksPerEpoch: 32,
60
+ this.config = {
61
+ proverNodePollingIntervalMs: 1_000,
62
+ proverNodeMaxPendingJobs: 100,
63
+ proverNodeMaxParallelBlocksPerEpoch: 32,
64
64
  txGatheringIntervalMs: 1_000,
65
- ...compact(options)
65
+ txGatheringBatchSize: 10,
66
+ txGatheringMaxParallelRequestsPerNode: 100,
67
+ proverNodeFailedEpochStore: undefined,
68
+ ...compact(config)
66
69
  };
70
+ this.validateConfig();
67
71
  const meter = telemetryClient.getMeter('ProverNode');
68
72
  this.tracer = telemetryClient.getTracer('ProverNode');
69
73
  this.jobMetrics = new ProverNodeJobMetrics(meter, telemetryClient.getTracer('EpochProvingJob'));
70
74
  this.rewardsMetrics = new ProverNodeRewardsMetrics(meter, EthAddress.fromField(this.prover.getProverId()), this.publisher.getRollupContract());
71
- this.txFetcher = new RunningPromise(()=>this.checkForTxs(), this.log, this.options.txGatheringIntervalMs);
75
+ this.txFetcher = new RunningPromise(()=>this.checkForTxs(), this.log, this.config.txGatheringIntervalMs);
72
76
  }
73
77
  getProverId() {
74
78
  return this.prover.getProverId();
@@ -111,7 +115,7 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
111
115
  this.epochsMonitor.start(this);
112
116
  this.l1Metrics.start();
113
117
  await this.rewardsMetrics.start();
114
- this.log.info(`Started Prover Node with prover id ${this.prover.getProverId().toString()}`, this.options);
118
+ this.log.info(`Started Prover Node with prover id ${this.prover.getProverId().toString()}`, this.config);
115
119
  }
116
120
  /**
117
121
  * Stops the prover node and all its dependencies.
@@ -140,29 +144,42 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
140
144
  /**
141
145
  * Starts a proving process and returns immediately.
142
146
  */ async startProof(epochNumber) {
143
- const job = await this.createProvingJob(BigInt(epochNumber));
147
+ const job = await this.createProvingJob(BigInt(epochNumber), {
148
+ skipEpochCheck: true
149
+ });
144
150
  void this.runJob(job);
145
151
  }
146
152
  async runJob(job) {
153
+ const epochNumber = job.getEpochNumber();
147
154
  const ctx = {
148
155
  id: job.getId(),
149
- epochNumber: job.getEpochNumber()
156
+ epochNumber,
157
+ state: undefined
150
158
  };
151
159
  try {
152
160
  await job.run();
153
161
  const state = job.getState();
162
+ ctx.state = state;
154
163
  if (state === 'reorg') {
155
- this.log.warn(`Running new job for epoch ${job.getEpochNumber()} due to reorg`, ctx);
156
- await this.createProvingJob(job.getEpochNumber());
164
+ this.log.warn(`Running new job for epoch ${epochNumber} due to reorg`, ctx);
165
+ await this.createProvingJob(epochNumber);
166
+ } else if (state === 'failed') {
167
+ this.log.error(`Job for ${epochNumber} exited with state ${state}`, ctx);
168
+ await this.tryUploadEpochFailure(job);
157
169
  } else {
158
- this.log.verbose(`Job for ${job.getEpochNumber()} exited with state ${state}`, ctx);
170
+ this.log.verbose(`Job for ${epochNumber} exited with state ${state}`, ctx);
159
171
  }
160
172
  } catch (err) {
161
- this.log.error(`Error proving epoch ${job.getEpochNumber()}`, err, ctx);
173
+ this.log.error(`Error proving epoch ${epochNumber}`, err, ctx);
162
174
  } finally{
163
175
  this.jobs.delete(job.getId());
164
176
  }
165
177
  }
178
+ async tryUploadEpochFailure(job) {
179
+ if (this.config.proverNodeFailedEpochStore) {
180
+ return await uploadEpochProofFailure(this.config.proverNodeFailedEpochStore, job.getId(), job.getProvingData(), this.l2BlockSource, this.worldState, assertRequired(pick(this.config, 'l1ChainId', 'rollupVersion', 'dataDirectory')), this.log);
181
+ }
182
+ }
166
183
  /**
167
184
  * Returns the prover instance.
168
185
  */ getProver() {
@@ -183,25 +200,26 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
183
200
  return jobs.filter((job)=>job.epochNumber === epochNumber && !EpochProvingJobTerminalState.includes(job.status));
184
201
  }
185
202
  checkMaximumPendingJobs() {
186
- const { maxPendingJobs } = this.options;
187
- return maxPendingJobs === 0 || this.jobs.size < maxPendingJobs;
188
- }
189
- async createProvingJob(epochNumber) {
190
- if (!this.checkMaximumPendingJobs()) {
191
- throw new Error(`Maximum pending proving jobs ${this.options.maxPendingJobs} reached. Cannot create new job.`);
203
+ const { proverNodeMaxPendingJobs: maxPendingJobs } = this.config;
204
+ if (maxPendingJobs > 0 && this.jobs.size >= maxPendingJobs) {
205
+ throw new Error(`Maximum pending proving jobs ${maxPendingJobs} reached. Cannot create new job.`);
192
206
  }
193
- // Gather blocks for this epoch
194
- const { blocks, txs } = await this.gatherEpochData(epochNumber);
195
- const fromBlock = blocks[0].number;
196
- const toBlock = blocks.at(-1).number;
197
- // Fast forward world state to right before the target block and get a fork
207
+ }
208
+ async createProvingJob(epochNumber, opts = {}) {
209
+ this.checkMaximumPendingJobs();
210
+ // Gather all data for this epoch
211
+ const epochData = await this.gatherEpochData(epochNumber);
212
+ const fromBlock = epochData.blocks[0].number;
213
+ const toBlock = epochData.blocks.at(-1).number;
198
214
  this.log.verbose(`Creating proving job for epoch ${epochNumber} for block range ${fromBlock} to ${toBlock}`);
215
+ // Fast forward world state to right before the target block and get a fork
199
216
  await this.worldState.syncImmediate(toBlock);
200
- // Create a processor using the forked world state
217
+ // Create a processor factory
201
218
  const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, this.dateProvider, this.telemetryClient);
219
+ // Set deadline for this job to run. It will abort if it takes too long.
202
220
  const deadlineTs = getProofSubmissionDeadlineTimestamp(epochNumber, await this.getL1Constants());
203
221
  const deadline = new Date(Number(deadlineTs) * 1000);
204
- const job = this.doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory);
222
+ const job = this.doCreateEpochProvingJob(epochData, deadline, publicProcessorFactory, opts);
205
223
  this.jobs.set(job.getId(), job);
206
224
  return job;
207
225
  }
@@ -222,12 +240,16 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
222
240
  }
223
241
  }
224
242
  async gatherEpochData(epochNumber) {
225
- // Gather blocks for this epoch and their txs
226
243
  const blocks = await this.gatherBlocks(epochNumber);
227
244
  const txs = await this.gatherTxs(epochNumber, blocks);
245
+ const l1ToL2Messages = await this.gatherMessages(epochNumber, blocks);
246
+ const previousBlockHeader = await this.gatherPreviousBlockHeader(epochNumber, blocks[0]);
228
247
  return {
229
248
  blocks,
230
- txs
249
+ txs,
250
+ l1ToL2Messages,
251
+ epochNumber,
252
+ previousBlockHeader
231
253
  };
232
254
  }
233
255
  async gatherBlocks(epochNumber) {
@@ -250,14 +272,43 @@ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
250
272
  const missingTxHashes = txsToFind.filter((txHashToFind)=>!txHashesFound.some((txHashFound)=>txHashToFind.equals(txHashFound))).join(', ');
251
273
  throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxHashes}`);
252
274
  }
253
- /** Extracted for testing purposes. */ doCreateEpochProvingJob(epochNumber, deadline, blocks, txs, publicProcessorFactory) {
254
- return new EpochProvingJob(this.worldState, epochNumber, blocks, txs, this.prover.createEpochProver(), publicProcessorFactory, this.publisher, this.l2BlockSource, this.l1ToL2MessageSource, this.jobMetrics, deadline, {
255
- parallelBlockLimit: this.options.maxParallelBlocksPerEpoch
275
+ async gatherMessages(epochNumber, blocks) {
276
+ const messages = await Promise.all(blocks.map((b)=>this.l1ToL2MessageSource.getL1ToL2Messages(BigInt(b.number))));
277
+ const messageCount = sum(messages.map((m)=>m.length));
278
+ this.log.verbose(`Gathered all ${messageCount} messages for epoch ${epochNumber}`, {
279
+ epochNumber
280
+ });
281
+ const messagesByBlock = {};
282
+ for(let i = 0; i < blocks.length; i++){
283
+ messagesByBlock[blocks[i].number] = messages[i];
284
+ }
285
+ return messagesByBlock;
286
+ }
287
+ async gatherPreviousBlockHeader(epochNumber, initialBlock) {
288
+ const previousBlockNumber = initialBlock.number - 1;
289
+ const header = await (previousBlockNumber === 0 ? this.worldState.getCommitted().getInitialHeader() : this.l2BlockSource.getBlockHeader(previousBlockNumber));
290
+ if (!header) {
291
+ throw new Error(`Previous block header ${initialBlock.number} not found for proving epoch ${epochNumber}`);
292
+ }
293
+ this.log.verbose(`Gathered previous block header ${header.getBlockNumber()} for epoch ${epochNumber}`);
294
+ return header;
295
+ }
296
+ /** Extracted for testing purposes. */ doCreateEpochProvingJob(data, deadline, publicProcessorFactory, opts = {}) {
297
+ const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit } = this.config;
298
+ return new EpochProvingJob(data, this.worldState, this.prover.createEpochProver(), publicProcessorFactory, this.publisher, this.l2BlockSource, this.jobMetrics, deadline, {
299
+ parallelBlockLimit,
300
+ ...opts
256
301
  });
257
302
  }
258
303
  /** Extracted for testing purposes. */ async triggerMonitors() {
259
304
  await this.epochsMonitor.work();
260
305
  }
306
+ validateConfig() {
307
+ if (this.config.proverNodeFailedEpochStore && (!this.config.dataDirectory || !this.config.l1ChainId || !this.config.rollupVersion)) {
308
+ this.log.warn(`Invalid prover-node config (missing dataDirectory, l1ChainId, or rollupVersion)`, pick(this.config, 'proverNodeFailedEpochStore', 'dataDirectory', 'l1ChainId', 'rollupVersion'));
309
+ throw new Error('All of dataDirectory, l1ChainId, and rollupVersion are required if proverNodeFailedEpochStore is set.');
310
+ }
311
+ }
261
312
  }
262
313
  _ts_decorate([
263
314
  trackSpan('ProverNode.createProvingJob', (epochNumber)=>({
@@ -1,10 +1,12 @@
1
1
  import type { EpochProverManager } from '@aztec/stdlib/interfaces/server';
2
+ import type { EpochProvingJob } from '../job/epoch-proving-job.js';
2
3
  import type { ProverNodePublisher } from '../prover-node-publisher.js';
3
4
  import { ProverNode } from '../prover-node.js';
4
- declare class TestProverNode_ extends ProverNode {
5
+ declare abstract class TestProverNodeClass extends ProverNode {
5
6
  prover: EpochProverManager;
6
7
  publisher: ProverNodePublisher;
8
+ abstract tryUploadEpochFailure(job: EpochProvingJob): Promise<string | undefined>;
7
9
  }
8
- export type TestProverNode = TestProverNode_;
10
+ export type TestProverNode = TestProverNodeClass;
9
11
  export {};
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,cAAM,eAAgB,SAAQ,UAAU;IACvB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,SAAS,EAAE,mBAAmB,CAAC;CAC/C;AAED,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,uBAAe,mBAAoB,SAAQ,UAAU;IACpC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,SAAS,EAAE,mBAAmB,CAAC;aAErB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAClG;AAED,MAAM,MAAM,cAAc,GAAG,mBAAmB,CAAC"}