@aztec/prover-node 0.0.1-commit.b9865e97 → 0.0.1-commit.be03c316

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 (65) hide show
  1. package/README.md +518 -0
  2. package/dest/actions/rerun-epoch-proving-job.d.ts +3 -3
  3. package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
  4. package/dest/actions/rerun-epoch-proving-job.js +102 -19
  5. package/dest/checkpoint-store.d.ts +87 -0
  6. package/dest/checkpoint-store.d.ts.map +1 -0
  7. package/dest/checkpoint-store.js +186 -0
  8. package/dest/config.d.ts +3 -1
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +8 -1
  11. package/dest/factory.d.ts +4 -1
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +2 -6
  14. package/dest/index.d.ts +2 -1
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +1 -0
  17. package/dest/job/checkpoint-prover.d.ts +134 -0
  18. package/dest/job/checkpoint-prover.d.ts.map +1 -0
  19. package/dest/job/checkpoint-prover.js +353 -0
  20. package/dest/job/epoch-session.d.ts +146 -0
  21. package/dest/job/epoch-session.d.ts.map +1 -0
  22. package/dest/job/epoch-session.js +720 -0
  23. package/dest/job/top-tree-job.d.ts +82 -0
  24. package/dest/job/top-tree-job.d.ts.map +1 -0
  25. package/dest/job/top-tree-job.js +152 -0
  26. package/dest/metrics.d.ts +25 -8
  27. package/dest/metrics.d.ts.map +1 -1
  28. package/dest/metrics.js +64 -14
  29. package/dest/proof-publishing-service.d.ts +161 -0
  30. package/dest/proof-publishing-service.d.ts.map +1 -0
  31. package/dest/proof-publishing-service.js +335 -0
  32. package/dest/prover-node-publisher.d.ts +10 -19
  33. package/dest/prover-node-publisher.d.ts.map +1 -1
  34. package/dest/prover-node-publisher.js +43 -99
  35. package/dest/prover-node.d.ts +107 -67
  36. package/dest/prover-node.d.ts.map +1 -1
  37. package/dest/prover-node.js +476 -261
  38. package/dest/prover-publisher-factory.d.ts +3 -1
  39. package/dest/prover-publisher-factory.d.ts.map +1 -1
  40. package/dest/prover-publisher-factory.js +1 -0
  41. package/dest/session-manager.d.ts +158 -0
  42. package/dest/session-manager.d.ts.map +1 -0
  43. package/dest/session-manager.js +452 -0
  44. package/dest/test/index.d.ts +7 -6
  45. package/dest/test/index.d.ts.map +1 -1
  46. package/package.json +24 -23
  47. package/src/actions/rerun-epoch-proving-job.ts +104 -27
  48. package/src/checkpoint-store.ts +218 -0
  49. package/src/config.ts +12 -1
  50. package/src/factory.ts +5 -8
  51. package/src/index.ts +1 -0
  52. package/src/job/checkpoint-prover.ts +468 -0
  53. package/src/job/epoch-session.ts +436 -0
  54. package/src/job/top-tree-job.ts +227 -0
  55. package/src/metrics.ts +65 -23
  56. package/src/proof-publishing-service.ts +427 -0
  57. package/src/prover-node-publisher.ts +58 -123
  58. package/src/prover-node.ts +549 -283
  59. package/src/prover-publisher-factory.ts +3 -0
  60. package/src/session-manager.ts +552 -0
  61. package/src/test/index.ts +6 -6
  62. package/dest/job/epoch-proving-job.d.ts +0 -67
  63. package/dest/job/epoch-proving-job.d.ts.map +0 -1
  64. package/dest/job/epoch-proving-job.js +0 -912
  65. package/src/job/epoch-proving-job.ts +0 -531
@@ -2,21 +2,17 @@ import { BatchedBlob, getEthBlobEvaluationInputs } from '@aztec/blob-lib';
2
2
  import { MAX_CHECKPOINTS_PER_EPOCH } from '@aztec/constants';
3
3
  import type { RollupContract, ViemCommitteeAttestation } from '@aztec/ethereum/contracts';
4
4
  import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
5
- import { makeTuple } from '@aztec/foundation/array';
6
5
  import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
7
6
  import { areArraysEqual } from '@aztec/foundation/collection';
8
7
  import { Fr } from '@aztec/foundation/curves/bn254';
9
8
  import { EthAddress } from '@aztec/foundation/eth-address';
10
9
  import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
11
- import { retryUntil } from '@aztec/foundation/retry';
12
- import type { Tuple } from '@aztec/foundation/serialize';
13
10
  import { Timer } from '@aztec/foundation/timer';
14
11
  import { RollupAbi } from '@aztec/l1-artifacts';
15
12
  import type { PublisherConfig, TxSenderConfig } from '@aztec/sequencer-client';
16
13
  import { CommitteeAttestation, CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
17
- import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
18
14
  import type { Proof } from '@aztec/stdlib/proofs';
19
- import type { FeeRecipient, RootRollupPublicInputs } from '@aztec/stdlib/rollup';
15
+ import type { CheckpointHeader, RootRollupPublicInputs } from '@aztec/stdlib/rollup';
20
16
  import type { L1PublishProofStats } from '@aztec/stdlib/stats';
21
17
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
22
18
 
@@ -33,18 +29,19 @@ export type L1SubmitEpochProofArgs = {
33
29
  endTimestamp: Fr;
34
30
  outHash: Fr;
35
31
  proverId: Fr;
36
- fees: Tuple<FeeRecipient, typeof MAX_CHECKPOINTS_PER_EPOCH>;
32
+ headers: CheckpointHeader[];
37
33
  proof: Proof;
38
34
  };
39
35
 
40
36
  export class ProverNodePublisher {
41
- private interrupted = false;
42
37
  private metrics: ProverNodePublisherMetrics;
43
38
 
44
39
  protected log: Logger;
45
40
 
46
41
  protected rollupContract: RollupContract;
47
42
 
43
+ protected proofSubmissionTarget: Hex;
44
+
48
45
  public readonly l1TxUtils: L1TxUtils;
49
46
 
50
47
  constructor(
@@ -52,6 +49,7 @@ export class ProverNodePublisher {
52
49
  deps: {
53
50
  rollupContract: RollupContract;
54
51
  l1TxUtils: L1TxUtils;
52
+ proofSubmissionTarget?: EthAddress;
55
53
  telemetry?: TelemetryClient;
56
54
  },
57
55
  bindings?: LoggerBindings,
@@ -62,6 +60,7 @@ export class ProverNodePublisher {
62
60
  this.log = createLogger('prover-node:l1-tx-publisher', bindings);
63
61
 
64
62
  this.rollupContract = deps.rollupContract;
63
+ this.proofSubmissionTarget = deps.proofSubmissionTarget?.toString() ?? deps.rollupContract.address;
65
64
  this.l1TxUtils = deps.l1TxUtils;
66
65
  }
67
66
 
@@ -69,23 +68,6 @@ export class ProverNodePublisher {
69
68
  return this.rollupContract;
70
69
  }
71
70
 
72
- /**
73
- * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
74
- * Be warned, the call may return false even if the tx subsequently gets successfully mined.
75
- * In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
76
- * A call to `restart` is required before you can continue publishing.
77
- */
78
- public interrupt() {
79
- this.interrupted = true;
80
- this.l1TxUtils.interrupt();
81
- }
82
-
83
- /** Restarts the publisher after calling `interrupt`. */
84
- public restart() {
85
- this.interrupted = false;
86
- this.l1TxUtils.restart();
87
- }
88
-
89
71
  public getSenderAddress() {
90
72
  return this.l1TxUtils.getSenderAddress();
91
73
  }
@@ -98,107 +80,54 @@ export class ProverNodePublisher {
98
80
  proof: Proof;
99
81
  batchedBlobInputs: BatchedBlob;
100
82
  attestations: ViemCommitteeAttestation[];
83
+ headers: CheckpointHeader[];
84
+ /** Wall-clock deadline (proof-submission window end) past which the L1 tx should stop retrying. */
85
+ deadline?: Date;
101
86
  }): Promise<boolean> {
102
87
  const { epochNumber, fromCheckpoint, toCheckpoint } = args;
103
88
  const ctx = { epochNumber, fromCheckpoint, toCheckpoint };
104
89
 
105
- if (!this.interrupted) {
106
- if (!(await this.waitUntilStartBuildsOnProven(args))) {
107
- this.log.verbose('Checkpoint data syncing interrupted', ctx);
108
- return false;
109
- }
110
-
111
- const timer = new Timer();
112
- // Validate epoch proof range and hashes are correct before submitting
113
- await this.validateEpochProofSubmission(args);
114
-
115
- const txReceipt = await this.sendSubmitEpochProofTx(args);
116
- if (!txReceipt) {
117
- this.log.error(`Failed to mine submitEpochProof tx`, undefined, ctx);
118
- return false;
119
- }
120
-
121
- try {
122
- this.metrics.recordSenderBalance(
123
- await this.l1TxUtils.getSenderBalance(),
124
- this.l1TxUtils.getSenderAddress().toString(),
125
- );
126
- } catch (err) {
127
- this.log.warn(`Failed to record the ETH balance of the prover node: ${err}`);
128
- }
129
-
130
- // Tx was mined successfully
131
- if (txReceipt.status === 'success') {
132
- const tx = await this.l1TxUtils.getTransactionStats(txReceipt.transactionHash);
133
- const stats: L1PublishProofStats = {
134
- gasPrice: txReceipt.effectiveGasPrice,
135
- gasUsed: txReceipt.gasUsed,
136
- transactionHash: txReceipt.transactionHash,
137
- calldataGas: tx!.calldataGas,
138
- calldataSize: tx!.calldataSize,
139
- sender: tx!.sender,
140
- blobDataGas: 0n,
141
- blobGasUsed: 0n,
142
- eventName: 'proof-published-to-l1',
143
- };
144
- this.log.info(`Published epoch proof to L1 rollup contract`, { ...stats, ...ctx });
145
- this.metrics.recordSubmitProof(timer.ms(), stats);
146
- return true;
147
- }
90
+ const timer = new Timer();
91
+ // Validate epoch proof range and hashes are correct before submitting
92
+ await this.validateEpochProofSubmission(args);
148
93
 
149
- this.metrics.recordFailedTx();
150
- this.log.error(`Rollup submitEpochProof tx reverted ${txReceipt.transactionHash}`, undefined, ctx);
94
+ const txReceipt = await this.sendSubmitEpochProofTx(args);
95
+ if (!txReceipt) {
96
+ this.log.error(`Failed to mine submitEpochProof tx`, undefined, ctx);
97
+ return false;
151
98
  }
152
99
 
153
- this.log.verbose('Checkpoint data syncing interrupted', ctx);
154
- return false;
155
- }
100
+ try {
101
+ this.metrics.recordSenderBalance(
102
+ await this.l1TxUtils.getSenderBalance(),
103
+ this.l1TxUtils.getSenderAddress().toString(),
104
+ );
105
+ } catch (err) {
106
+ this.log.warn(`Failed to record the ETH balance of the prover node: ${err}`);
107
+ }
156
108
 
157
- private async waitUntilStartBuildsOnProven(args: { epochNumber: EpochNumber; fromCheckpoint: CheckpointNumber }) {
158
- const { epochNumber, fromCheckpoint } = args;
159
- const provenCheckpoint = await this.getProvenCheckpoint();
160
- if (this.isStartBuildingOnProven(fromCheckpoint, provenCheckpoint)) {
109
+ // Tx was mined successfully
110
+ if (txReceipt.status === 'success') {
111
+ const tx = await this.l1TxUtils.getTransactionStats(txReceipt.transactionHash);
112
+ const stats: L1PublishProofStats = {
113
+ gasPrice: txReceipt.effectiveGasPrice,
114
+ gasUsed: txReceipt.gasUsed,
115
+ transactionHash: txReceipt.transactionHash,
116
+ calldataGas: tx!.calldataGas,
117
+ calldataSize: tx!.calldataSize,
118
+ sender: tx!.sender,
119
+ blobDataGas: 0n,
120
+ blobGasUsed: 0n,
121
+ eventName: 'proof-published-to-l1',
122
+ };
123
+ this.log.info(`Published epoch proof to L1 rollup contract`, { ...stats, ...ctx });
124
+ this.metrics.recordSubmitProof(timer.ms(), stats);
161
125
  return true;
162
126
  }
163
127
 
164
- const timeout = await this.getSecondsUntilProofSubmissionWindowEnd(epochNumber);
165
- this.log.info(`Waiting for proven checkpoint to reach proof start`, {
166
- epochNumber,
167
- fromCheckpoint,
168
- provenCheckpoint,
169
- timeout,
170
- });
171
-
172
- await retryUntil(
173
- async () => {
174
- if (this.interrupted) {
175
- return true;
176
- }
177
-
178
- const proven = await this.getProvenCheckpoint();
179
- this.log.verbose(`Proven checkpoint is at ${proven} (waiting for ${fromCheckpoint - 1})`, { epochNumber });
180
- return this.isStartBuildingOnProven(fromCheckpoint, proven) ? true : undefined;
181
- },
182
- `proven checkpoint to reach ${fromCheckpoint - 1}`,
183
- timeout,
184
- 4,
185
- );
186
-
187
- return !this.interrupted;
188
- }
189
-
190
- private async getProvenCheckpoint() {
191
- return (await this.rollupContract.getTips()).proven;
192
- }
193
-
194
- private isStartBuildingOnProven(fromCheckpoint: CheckpointNumber, provenCheckpoint: CheckpointNumber) {
195
- return fromCheckpoint - 1 <= provenCheckpoint;
196
- }
197
-
198
- private async getSecondsUntilProofSubmissionWindowEnd(epochNumber: EpochNumber) {
199
- const deadline = getProofSubmissionDeadlineTimestamp(epochNumber, await this.rollupContract.getRollupConstants());
200
- const now = BigInt(Math.floor(Date.now() / 1000));
201
- return Math.max(Number(deadline - now), 0.001);
128
+ this.metrics.recordFailedTx();
129
+ this.log.error(`Rollup submitEpochProof tx reverted ${txReceipt.transactionHash}`, undefined, ctx);
130
+ return false;
202
131
  }
203
132
 
204
133
  private async validateEpochProofSubmission(args: {
@@ -208,6 +137,7 @@ export class ProverNodePublisher {
208
137
  proof: Proof;
209
138
  batchedBlobInputs: BatchedBlob;
210
139
  attestations: ViemCommitteeAttestation[];
140
+ headers: CheckpointHeader[];
211
141
  }) {
212
142
  const { fromCheckpoint, toCheckpoint, publicInputs, batchedBlobInputs } = args;
213
143
 
@@ -281,6 +211,7 @@ export class ProverNodePublisher {
281
211
  proof: Proof;
282
212
  batchedBlobInputs: BatchedBlob;
283
213
  attestations: ViemCommitteeAttestation[];
214
+ headers: CheckpointHeader[];
284
215
  }): Promise<void> {
285
216
  const { epochNumber, fromCheckpoint, toCheckpoint } = args;
286
217
 
@@ -290,7 +221,7 @@ export class ProverNodePublisher {
290
221
  const senderAddress = this.l1TxUtils.getSenderAddress();
291
222
 
292
223
  const [gasLimit, gasPrice, latestBlock] = await Promise.all([
293
- this.l1TxUtils.estimateGas(senderAddress.toString() as `0x${string}`, { to: this.rollupContract.address, data }),
224
+ this.l1TxUtils.estimateGas(senderAddress.toString() as `0x${string}`, { to: this.proofSubmissionTarget, data }),
294
225
  this.l1TxUtils.getGasPrice(),
295
226
  this.l1TxUtils.client.getBlock({ blockTag: 'latest' }),
296
227
  ]);
@@ -328,6 +259,7 @@ export class ProverNodePublisher {
328
259
  proof: Proof;
329
260
  batchedBlobInputs: BatchedBlob;
330
261
  attestations: ViemCommitteeAttestation[];
262
+ headers: CheckpointHeader[];
331
263
  }): Hex {
332
264
  return encodeFunctionData({
333
265
  abi: RollupAbi,
@@ -339,10 +271,12 @@ export class ProverNodePublisher {
339
271
  private async sendSubmitEpochProofTx(args: {
340
272
  fromCheckpoint: CheckpointNumber;
341
273
  toCheckpoint: CheckpointNumber;
274
+ deadline?: Date;
342
275
  publicInputs: RootRollupPublicInputs;
343
276
  proof: Proof;
344
277
  batchedBlobInputs: BatchedBlob;
345
278
  attestations: ViemCommitteeAttestation[];
279
+ headers: CheckpointHeader[];
346
280
  }): Promise<TransactionReceipt | undefined> {
347
281
  const txArgs = [this.getSubmitEpochProofArgs(args)] as const;
348
282
 
@@ -357,7 +291,10 @@ export class ProverNodePublisher {
357
291
  args: txArgs,
358
292
  });
359
293
  try {
360
- const { receipt } = await this.l1TxUtils.sendAndMonitorTransaction({ to: this.rollupContract.address, data });
294
+ const { receipt } = await this.l1TxUtils.sendAndMonitorTransaction(
295
+ { to: this.proofSubmissionTarget, data },
296
+ { txTimeoutAt: args.deadline },
297
+ );
361
298
  if (receipt.status !== 'success') {
362
299
  const errorMsg = await this.l1TxUtils.tryGetErrorFromRevertedTx(
363
300
  data,
@@ -365,7 +302,7 @@ export class ProverNodePublisher {
365
302
  args: [...txArgs],
366
303
  functionName: 'submitEpochRootProof',
367
304
  abi: RollupAbi,
368
- address: this.rollupContract.address,
305
+ address: this.proofSubmissionTarget,
369
306
  },
370
307
  /*blobInputs*/ undefined,
371
308
  /*stateOverride*/ [],
@@ -386,6 +323,7 @@ export class ProverNodePublisher {
386
323
  publicInputs: RootRollupPublicInputs;
387
324
  batchedBlobInputs: BatchedBlob;
388
325
  attestations: ViemCommitteeAttestation[];
326
+ headers: CheckpointHeader[];
389
327
  }) {
390
328
  // Returns arguments for EpochProofLib.sol -> getEpochProofPublicInputs()
391
329
  return [
@@ -397,11 +335,7 @@ export class ProverNodePublisher {
397
335
  outHash: args.publicInputs.outHash.toString(),
398
336
  proverId: EthAddress.fromField(args.publicInputs.constants.proverId).toString(),
399
337
  } /*_args*/,
400
- makeTuple(MAX_CHECKPOINTS_PER_EPOCH * 2, i =>
401
- i % 2 === 0
402
- ? args.publicInputs.fees[i / 2].recipient.toField().toString()
403
- : args.publicInputs.fees[(i - 1) / 2].value.toString(),
404
- ) /*_fees*/,
338
+ args.headers.map(header => header.toViem()) /*_headers*/,
405
339
  getEthBlobEvaluationInputs(args.batchedBlobInputs) /*_blobPublicInputs*/,
406
340
  ] as const;
407
341
  }
@@ -413,6 +347,7 @@ export class ProverNodePublisher {
413
347
  proof: Proof;
414
348
  batchedBlobInputs: BatchedBlob;
415
349
  attestations: ViemCommitteeAttestation[];
350
+ headers: CheckpointHeader[];
416
351
  }) {
417
352
  // Returns arguments for EpochProofLib.sol -> submitEpochRootProof()
418
353
  const proofHex: Hex = `0x${args.proof.withoutPublicInputs().toString('hex')}`;
@@ -421,7 +356,7 @@ export class ProverNodePublisher {
421
356
  start: argsArray[0],
422
357
  end: argsArray[1],
423
358
  args: argsArray[2],
424
- fees: argsArray[3],
359
+ headers: argsArray[3],
425
360
  attestations: CommitteeAttestationsAndSigners.packAttestations(
426
361
  args.attestations.map(a => CommitteeAttestation.fromViem(a)),
427
362
  ),