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