@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.
- package/dest/actions/download-epoch-proving-job.d.ts +18 -0
- package/dest/actions/download-epoch-proving-job.d.ts.map +1 -0
- package/dest/actions/download-epoch-proving-job.js +37 -0
- package/dest/actions/index.d.ts +3 -0
- package/dest/actions/index.d.ts.map +1 -0
- package/dest/actions/index.js +2 -0
- package/dest/actions/rerun-epoch-proving-job.d.ts +11 -0
- package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -0
- package/dest/actions/rerun-epoch-proving-job.js +40 -0
- package/dest/actions/upload-epoch-proof-failure.d.ts +15 -0
- package/dest/actions/upload-epoch-proof-failure.d.ts.map +1 -0
- package/dest/actions/upload-epoch-proof-failure.js +78 -0
- package/dest/bin/run-failed-epoch.d.ts +2 -0
- package/dest/bin/run-failed-epoch.d.ts.map +1 -0
- package/dest/bin/run-failed-epoch.js +67 -0
- package/dest/config.d.ts +2 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +5 -0
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +5 -5
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/job/epoch-proving-job-data.d.ts +15 -0
- package/dest/job/epoch-proving-job-data.d.ts.map +1 -0
- package/dest/job/epoch-proving-job-data.js +45 -0
- package/dest/job/epoch-proving-job.d.ts +10 -9
- package/dest/job/epoch-proving-job.d.ts.map +1 -1
- package/dest/job/epoch-proving-job.js +41 -24
- package/dest/metrics.js +2 -2
- package/dest/prover-coordination/combined-prover-coordination.d.ts.map +1 -1
- package/dest/prover-coordination/combined-prover-coordination.js +7 -4
- package/dest/prover-coordination/config.d.ts.map +1 -1
- package/dest/prover-coordination/config.js +2 -1
- package/dest/prover-coordination/factory.d.ts.map +1 -1
- package/dest/prover-coordination/factory.js +8 -4
- package/dest/prover-node.d.ts +23 -18
- package/dest/prover-node.d.ts.map +1 -1
- package/dest/prover-node.js +88 -37
- package/dest/test/index.d.ts +4 -2
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -1
- package/package.json +25 -24
- package/src/actions/download-epoch-proving-job.ts +44 -0
- package/src/actions/index.ts +2 -0
- package/src/actions/rerun-epoch-proving-job.ts +61 -0
- package/src/actions/upload-epoch-proof-failure.ts +88 -0
- package/src/bin/run-failed-epoch.ts +77 -0
- package/src/config.ts +7 -1
- package/src/factory.ts +21 -7
- package/src/index.ts +1 -0
- package/src/job/epoch-proving-job-data.ts +68 -0
- package/src/job/epoch-proving-job.ts +55 -23
- package/src/metrics.ts +2 -2
- package/src/prover-coordination/combined-prover-coordination.ts +9 -6
- package/src/prover-coordination/config.ts +1 -0
- package/src/prover-coordination/factory.ts +7 -4
- package/src/prover-node.ts +120 -53
- 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(
|
|
39
|
-
|
|
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
|
-
|
|
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 =
|
|
101
|
-
const previousHeader =
|
|
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
|
|
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
|
|
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
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
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;
|
|
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 -
|
|
97
|
+
const numNotFound = toFindFromP2P - foundFromP2PLength;
|
|
95
98
|
if (numNotFound === 0) {
|
|
96
|
-
this.log.info(`Found all ${originalToFind} txs. ${numFoundFromNodes} from nodes, ${
|
|
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 ${
|
|
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,
|
|
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;
|
|
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)=>
|
|
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
|
}
|
package/dest/prover-node.d.ts
CHANGED
|
@@ -1,48 +1,46 @@
|
|
|
1
|
-
import type {
|
|
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 {
|
|
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
|
-
|
|
13
|
-
|
|
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
|
|
20
|
-
*
|
|
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 &
|
|
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
|
|
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 &
|
|
45
|
-
getProverId():
|
|
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(
|
|
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":"
|
|
1
|
+
{"version":3,"file":"prover-node.d.ts","sourceRoot":"","sources":["../src/prover-node.ts"],"names":[],"mappings":"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"}
|
package/dest/prover-node.js
CHANGED
|
@@ -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
|
|
21
|
-
*
|
|
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
|
-
|
|
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,
|
|
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.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
this.config = {
|
|
61
|
+
proverNodePollingIntervalMs: 1_000,
|
|
62
|
+
proverNodeMaxPendingJobs: 100,
|
|
63
|
+
proverNodeMaxParallelBlocksPerEpoch: 32,
|
|
64
64
|
txGatheringIntervalMs: 1_000,
|
|
65
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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 ${
|
|
156
|
-
await this.createProvingJob(
|
|
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 ${
|
|
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 ${
|
|
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.
|
|
187
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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)=>({
|
package/dest/test/index.d.ts
CHANGED
|
@@ -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
|
|
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 =
|
|
10
|
+
export type TestProverNode = TestProverNodeClass;
|
|
9
11
|
export {};
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dest/test/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|