@aztec/prover-node 0.0.1-commit.2f68f620 → 0.0.1-commit.3100065

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 +511 -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 +106 -104
  5. package/dest/checkpoint-store.d.ts +88 -0
  6. package/dest/checkpoint-store.d.ts.map +1 -0
  7. package/dest/checkpoint-store.js +169 -0
  8. package/dest/config.d.ts +1 -3
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +1 -8
  11. package/dest/factory.d.ts +1 -1
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +1 -7
  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 +124 -0
  18. package/dest/job/checkpoint-prover.d.ts.map +1 -0
  19. package/dest/job/checkpoint-prover.js +330 -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 +7 -22
  33. package/dest/prover-node-publisher.d.ts.map +1 -1
  34. package/dest/prover-node-publisher.js +41 -101
  35. package/dest/prover-node.d.ts +105 -67
  36. package/dest/prover-node.d.ts.map +1 -1
  37. package/dest/prover-node.js +472 -261
  38. package/dest/prover-publisher-factory.d.ts +1 -3
  39. package/dest/prover-publisher-factory.d.ts.map +1 -1
  40. package/dest/prover-publisher-factory.js +0 -1
  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 +482 -0
  44. package/dest/test/index.d.ts +7 -6
  45. package/dest/test/index.d.ts.map +1 -1
  46. package/package.json +23 -23
  47. package/src/actions/rerun-epoch-proving-job.ts +102 -27
  48. package/src/checkpoint-store.ts +194 -0
  49. package/src/config.ts +2 -11
  50. package/src/factory.ts +0 -9
  51. package/src/index.ts +1 -0
  52. package/src/job/checkpoint-prover.ts +442 -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 +54 -127
  58. package/src/prover-node.ts +545 -282
  59. package/src/prover-publisher-factory.ts +0 -3
  60. package/src/session-manager.ts +583 -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
@@ -0,0 +1,335 @@
1
+ import { BlockNumber } from '@aztec/foundation/branded-types';
2
+ import { createLogger } from '@aztec/foundation/log';
3
+ import { promiseWithResolvers } from '@aztec/foundation/promise';
4
+ import { SerialQueue } from '@aztec/foundation/queue';
5
+ /**
6
+ * Backoff after a transient `publisherFactory.create()` failure. The candidate stays
7
+ * in the queue and the drain is re-scheduled after this delay; if the failure persists
8
+ * the candidate's own `deadline` timer caps the total wait.
9
+ */ const PUBLISHER_ACQUIRE_RETRY_DELAY_MS = 1_000;
10
+ /**
11
+ * Central owner of L1 proof submission. Sessions offer their proofs here as
12
+ * `PublishCandidate`s; the service serialises one publish at a time, picks the
13
+ * longest candidate per epoch as the winner, and resolves the rest as
14
+ * `'superseded'` without spending L1 gas.
15
+ *
16
+ * Construction-time invariants:
17
+ * - Every publish runs against a freshly-created `ProverNodePublisher` from the factory.
18
+ * - Only one publish is ever in flight (`SerialQueue` drain) — no defensive locks.
19
+ * - Once an L1 publish starts, it runs to completion. `withdraw` is a queue-only
20
+ * operation: it removes a candidate that has not yet started publishing. An in-flight
21
+ * candidate is left alone and its outcome (`'published'` / `'failed'`) is reported as
22
+ * usual — the originating session has already moved to a terminal state via `cancel()`
23
+ * and ignores the late outcome.
24
+ *
25
+ * Eligibility for publication is decided against the proven block number read inside
26
+ * the drain (so the value is consistent with the publish that runs on the same drain
27
+ * pass): a candidate is eligible when its predecessor block is proven and (for partial
28
+ * candidates) the candidate's range extends past the proven tip. `onChainProven` is a
29
+ * wake-up signal; it does not pass state into the drain.
30
+ */ export class ProofPublishingService {
31
+ deps;
32
+ log;
33
+ epochs;
34
+ /**
35
+ * One drain task at a time. Submits, withdrawals, chain-proven advances, and prunes
36
+ * all schedule a `drain` here, so the eligibility re-check and the L1 publish never
37
+ * interleave.
38
+ *
39
+ * Protected so unit tests can `await drainQueue.syncPoint()` to wait for pending
40
+ * drain work to settle deterministically (no sleeps).
41
+ */ drainQueue;
42
+ /** Tracks the candidate currently being published. Set while drain is awaiting the L1 publish. */ inFlight;
43
+ stopped;
44
+ constructor(deps){
45
+ this.deps = deps;
46
+ this.epochs = new Map();
47
+ this.drainQueue = new SerialQueue();
48
+ this.stopped = false;
49
+ this.log = createLogger('prover-node:proof-publishing-service', deps.bindings);
50
+ this.drainQueue.start();
51
+ }
52
+ /**
53
+ * Offers a proof candidate to the service. The returned promise resolves once the
54
+ * service settles the candidate's fate: `'published'` if it wins and L1 accepts it,
55
+ * `'superseded'` if a longer candidate for the same epoch wins, `'failed'` if the
56
+ * L1 submission errored, `'withdrawn'` if the originating session cancelled,
57
+ * `'expired'` if the candidate's `deadline` elapsed before publishing started.
58
+ */ submit(candidate) {
59
+ if (this.stopped) {
60
+ return Promise.resolve('withdrawn');
61
+ }
62
+ const { promise, resolve } = promiseWithResolvers();
63
+ let bucket = this.epochs.get(candidate.epoch);
64
+ if (!bucket) {
65
+ bucket = {
66
+ candidates: new Map(),
67
+ resolvers: new Map(),
68
+ expiryTimers: new Map()
69
+ };
70
+ this.epochs.set(candidate.epoch, bucket);
71
+ }
72
+ bucket.candidates.set(candidate.id, candidate);
73
+ bucket.resolvers.set(candidate.id, resolve);
74
+ this.scheduleExpiry(bucket, candidate);
75
+ this.log.info(`Candidate proof ${candidate.id} submitted for publishing`, {
76
+ candidateId: candidate.id,
77
+ epoch: candidate.epoch,
78
+ startBlock: candidate.startBlock,
79
+ endBlock: candidate.endBlock,
80
+ deadline: candidate.deadline?.toISOString()
81
+ });
82
+ this.scheduleDrain();
83
+ return promise;
84
+ }
85
+ /**
86
+ * Pulls a queued candidate from the bucket and resolves its promise as `'withdrawn'`.
87
+ * If the candidate is already being published, the publish runs to completion and the
88
+ * outcome reports whatever L1 returned — callers that cancelled mid-publish must rely
89
+ * on their own terminal-state check to ignore the late outcome. No-op if the candidate
90
+ * is unknown.
91
+ */ withdraw(candidateId) {
92
+ if (this.inFlight?.id === candidateId) {
93
+ this.log.debug(`Withdraw for in-flight candidate ${candidateId} ignored; publish will run to completion`, {
94
+ candidateId
95
+ });
96
+ return;
97
+ }
98
+ for (const bucket of this.epochs.values()){
99
+ if (bucket.candidates.has(candidateId)) {
100
+ this.log.info(`Candidate ${candidateId} withdrawn`, {
101
+ candidateId
102
+ });
103
+ this.resolveCandidate(bucket, candidateId, 'withdrawn');
104
+ this.scheduleDrain();
105
+ return;
106
+ }
107
+ }
108
+ }
109
+ /**
110
+ * Signals that the L1 proven tip has advanced and the queue should be re-evaluated.
111
+ * The drain reads the proven block number from `l2BlockSource` itself rather than
112
+ * relying on the value passed here — that way the eligibility check uses a value read
113
+ * inside the serial drain, not one captured by a concurrent caller of `onChainProven`.
114
+ */ onChainProven(_provenBlock) {
115
+ this.scheduleDrain();
116
+ }
117
+ /**
118
+ * Stops accepting new submissions, waits for any in-flight publish to settle, and
119
+ * resolves remaining queued candidates as `'withdrawn'`.
120
+ */ async stop() {
121
+ this.stopped = true;
122
+ await this.drainQueue.end();
123
+ // Anything still parked in a bucket never ran through drain — resolve it as withdrawn so
124
+ // callers awaiting `submit()` aren't left hanging.
125
+ for (const bucket of Array.from(this.epochs.values())){
126
+ for (const id of Array.from(bucket.candidates.keys())){
127
+ this.resolveCandidate(bucket, id, 'withdrawn');
128
+ }
129
+ }
130
+ this.epochs.clear();
131
+ }
132
+ // ---------------- drain ----------------
133
+ scheduleDrain() {
134
+ if (this.stopped) {
135
+ return;
136
+ }
137
+ void this.drainQueue.put(()=>this.drain()).catch((err)=>{
138
+ this.log.error(`Drain task threw`, err);
139
+ });
140
+ }
141
+ async drain() {
142
+ if (this.stopped) {
143
+ return;
144
+ }
145
+ // Read the proven block number afresh inside the serial drain so the eligibility
146
+ // check is consistent with the publish that follows it on the same drain pass.
147
+ const proven = await this.readProvenBlockNumber();
148
+ // Process epochs in ascending order: the proven tip advances monotonically, so the lower
149
+ // epoch is the natural next eligible candidate.
150
+ const orderedEpochs = Array.from(this.epochs.keys()).sort((a, b)=>Number(a) - Number(b));
151
+ for (const epoch of orderedEpochs){
152
+ const bucket = this.epochs.get(epoch);
153
+ const eligible = this.pickEpochWinner(bucket, proven);
154
+ if (!eligible) {
155
+ continue;
156
+ }
157
+ await this.publishWinner(epoch, eligible.winner, bucket);
158
+ }
159
+ // Drop empty buckets
160
+ for (const [key, bucket] of Array.from(this.epochs.entries())){
161
+ if (bucket.candidates.size === 0) {
162
+ this.epochs.delete(key);
163
+ }
164
+ }
165
+ }
166
+ /**
167
+ * Picks the winning candidate for a given epoch. Partial candidates whose `endBlock` is
168
+ * already proven on-chain resolve `'superseded'`.
169
+ * Full candidates are never auto-superseded by the proven tip — multiple prover-nodes
170
+ * legitimately submit redundant full epoch proofs (one per prover-id) and L1 records each.
171
+ * Among the remaining candidates with their predecessor proven, the one with the highest
172
+ * `endBlock` wins; the others resolve `'superseded'`.
173
+ */ pickEpochWinner(bucket, proven) {
174
+ const now = this.deps.dateProvider.now();
175
+ // Resolve any candidate whose deadline has already passed.
176
+ for (const candidate of Array.from(bucket.candidates.values())){
177
+ if (candidate.deadline && candidate.deadline.getTime() <= now) {
178
+ this.resolveCandidate(bucket, candidate.id, 'expired');
179
+ }
180
+ }
181
+ // Drop partial candidates the proven chain has already caught up to.
182
+ for (const candidate of Array.from(bucket.candidates.values())){
183
+ if (candidate.kind === 'partial' && candidate.endBlock <= proven) {
184
+ this.resolveCandidate(bucket, candidate.id, 'superseded');
185
+ }
186
+ }
187
+ const remaining = Array.from(bucket.candidates.values()).filter((c)=>c.startBlock - 1 <= proven);
188
+ if (remaining.length === 0) {
189
+ return undefined;
190
+ }
191
+ const winner = remaining.reduce((best, c)=>c.endBlock > best.endBlock ? c : best);
192
+ // Every other same-epoch candidate is superseded by the winner.
193
+ for (const candidate of remaining){
194
+ if (candidate.id !== winner.id) {
195
+ this.resolveCandidate(bucket, candidate.id, 'superseded');
196
+ }
197
+ }
198
+ return {
199
+ winner
200
+ };
201
+ }
202
+ async publishWinner(epoch, winner, bucket) {
203
+ let publisher;
204
+ try {
205
+ publisher = await this.deps.publisherFactory.create();
206
+ } catch (err) {
207
+ // Treat this as transient: the publisher pool may be temporarily exhausted
208
+ // (every signer busy, funding tx in flight, etc.). Leave the candidate queued and
209
+ // schedule another drain after a short backoff. If the failure persists past the
210
+ // candidate's deadline the expiry timer will resolve it as `'expired'`.
211
+ this.log.warn(`Failed to acquire publisher for candidate ${winner.id}; retrying`, {
212
+ candidateId: winner.id,
213
+ epoch: winner.epoch,
214
+ retryDelayMs: PUBLISHER_ACQUIRE_RETRY_DELAY_MS,
215
+ err
216
+ });
217
+ setTimeout(()=>this.scheduleDrain(), PUBLISHER_ACQUIRE_RETRY_DELAY_MS);
218
+ return;
219
+ }
220
+ this.inFlight = {
221
+ id: winner.id
222
+ };
223
+ this.log.info(`Publishing candidate ${winner.id}`, {
224
+ candidateId: winner.id,
225
+ epoch: winner.epoch,
226
+ startBlock: winner.startBlock,
227
+ endBlock: winner.endBlock,
228
+ fromCheckpoint: winner.fromCheckpoint,
229
+ toCheckpoint: winner.toCheckpoint
230
+ });
231
+ const outcome = await this.runPublish(winner, publisher);
232
+ this.inFlight = undefined;
233
+ this.resolveCandidate(bucket, winner.id, outcome);
234
+ if (bucket.candidates.size === 0) {
235
+ this.epochs.delete(epoch);
236
+ }
237
+ }
238
+ async runPublish(candidate, publisher) {
239
+ const submitArgs = {
240
+ epochNumber: candidate.epoch,
241
+ fromCheckpoint: candidate.fromCheckpoint,
242
+ toCheckpoint: candidate.toCheckpoint,
243
+ publicInputs: candidate.publicInputs,
244
+ proof: candidate.proof,
245
+ batchedBlobInputs: candidate.batchedBlobInputs,
246
+ attestations: candidate.attestations,
247
+ headers: candidate.headers,
248
+ // Stop the L1 tx retrying past the candidate's submission-window deadline.
249
+ deadline: candidate.deadline
250
+ };
251
+ if (this.deps.config.skipSubmitProof) {
252
+ try {
253
+ await publisher.analyzeEpochProofSubmission(submitArgs);
254
+ return 'published';
255
+ } catch (err) {
256
+ this.log.warn(`Failed to analyze estimated L1 fees for candidate ${candidate.id}`, {
257
+ err,
258
+ candidateId: candidate.id,
259
+ epoch: candidate.epoch
260
+ });
261
+ // Analyze-mode failures are recorded but the session shouldn't enter `failed` —
262
+ // the operator opted out of submission. Match the previous EpochSession behaviour.
263
+ return 'published';
264
+ }
265
+ }
266
+ try {
267
+ const success = await publisher.submitEpochProof(submitArgs);
268
+ return success ? 'published' : 'failed';
269
+ } catch (err) {
270
+ this.log.error(`Error publishing candidate ${candidate.id}`, err, {
271
+ candidateId: candidate.id,
272
+ epoch: candidate.epoch
273
+ });
274
+ return 'failed';
275
+ }
276
+ }
277
+ resolveCandidate(bucket, id, outcome) {
278
+ const resolve = bucket.resolvers.get(id);
279
+ const timer = bucket.expiryTimers.get(id);
280
+ if (timer) {
281
+ clearTimeout(timer);
282
+ bucket.expiryTimers.delete(id);
283
+ }
284
+ bucket.candidates.delete(id);
285
+ bucket.resolvers.delete(id);
286
+ if (resolve) {
287
+ this.log.info(`Candidate ${id} resolved as ${outcome}`, {
288
+ candidateId: id,
289
+ outcome
290
+ });
291
+ resolve(outcome);
292
+ }
293
+ }
294
+ /**
295
+ * Arms a per-candidate expiry timer if the candidate carries a deadline. When the timer
296
+ * fires, the candidate resolves as `'expired'` — unless it is already in flight, in
297
+ * which case the publish runs to completion (the timer becomes a no-op). The timer is
298
+ * cleared by `resolveCandidate` whenever the candidate settles for any other reason.
299
+ */ scheduleExpiry(bucket, candidate) {
300
+ if (!candidate.deadline) {
301
+ return;
302
+ }
303
+ const delay = Math.max(candidate.deadline.getTime() - this.deps.dateProvider.now(), 0);
304
+ const timer = setTimeout(()=>this.handleExpiry(candidate.id), delay);
305
+ bucket.expiryTimers.set(candidate.id, timer);
306
+ }
307
+ /**
308
+ * Protected so unit tests can drive the deadline path without waiting on the real
309
+ * `setTimeout` to fire. Production code calls this only via the per-candidate timer
310
+ * armed in `scheduleExpiry`.
311
+ */ handleExpiry(candidateId) {
312
+ if (this.inFlight?.id === candidateId) {
313
+ this.log.debug(`Expiry for in-flight candidate ${candidateId} ignored; publish will run to completion`, {
314
+ candidateId
315
+ });
316
+ return;
317
+ }
318
+ for (const bucket of this.epochs.values()){
319
+ if (bucket.candidates.has(candidateId)) {
320
+ this.log.info(`Candidate ${candidateId} expired before publishing`, {
321
+ candidateId
322
+ });
323
+ this.resolveCandidate(bucket, candidateId, 'expired');
324
+ this.scheduleDrain();
325
+ return;
326
+ }
327
+ }
328
+ }
329
+ async readProvenBlockNumber() {
330
+ const proven = await this.deps.l2BlockSource.getBlockNumber({
331
+ tag: 'proven'
332
+ });
333
+ return BlockNumber(proven ?? 0);
334
+ }
335
+ }
@@ -1,17 +1,14 @@
1
1
  import { BatchedBlob } from '@aztec/blob-lib';
2
- import { MAX_CHECKPOINTS_PER_EPOCH } from '@aztec/constants';
3
2
  import type { RollupContract, ViemCommitteeAttestation } from '@aztec/ethereum/contracts';
4
3
  import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
5
4
  import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
6
5
  import { Fr } from '@aztec/foundation/curves/bn254';
7
6
  import { EthAddress } from '@aztec/foundation/eth-address';
8
7
  import { type Logger, type LoggerBindings } from '@aztec/foundation/log';
9
- import type { Tuple } from '@aztec/foundation/serialize';
10
8
  import type { PublisherConfig, TxSenderConfig } from '@aztec/sequencer-client';
11
9
  import type { Proof } from '@aztec/stdlib/proofs';
12
- import type { FeeRecipient, RootRollupPublicInputs } from '@aztec/stdlib/rollup';
10
+ import type { CheckpointHeader, RootRollupPublicInputs } from '@aztec/stdlib/rollup';
13
11
  import { type TelemetryClient } from '@aztec/telemetry-client';
14
- import { type Hex } from 'viem';
15
12
  /** Arguments to the submitEpochProof method of the rollup contract */
16
13
  export type L1SubmitEpochProofArgs = {
17
14
  epochSize: number;
@@ -20,32 +17,20 @@ export type L1SubmitEpochProofArgs = {
20
17
  endTimestamp: Fr;
21
18
  outHash: Fr;
22
19
  proverId: Fr;
23
- fees: Tuple<FeeRecipient, typeof MAX_CHECKPOINTS_PER_EPOCH>;
20
+ headers: CheckpointHeader[];
24
21
  proof: Proof;
25
22
  };
26
23
  export declare class ProverNodePublisher {
27
- private interrupted;
28
24
  private metrics;
29
25
  protected log: Logger;
30
26
  protected rollupContract: RollupContract;
31
- protected proofSubmissionTarget: Hex;
32
27
  readonly l1TxUtils: L1TxUtils;
33
28
  constructor(config: TxSenderConfig & PublisherConfig, deps: {
34
29
  rollupContract: RollupContract;
35
30
  l1TxUtils: L1TxUtils;
36
- proofSubmissionTarget?: EthAddress;
37
31
  telemetry?: TelemetryClient;
38
32
  }, bindings?: LoggerBindings);
39
33
  getRollupContract(): RollupContract;
40
- /**
41
- * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
42
- * Be warned, the call may return false even if the tx subsequently gets successfully mined.
43
- * In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
44
- * A call to `restart` is required before you can continue publishing.
45
- */
46
- interrupt(): void;
47
- /** Restarts the publisher after calling `interrupt`. */
48
- restart(): void;
49
34
  getSenderAddress(): EthAddress;
50
35
  submitEpochProof(args: {
51
36
  epochNumber: EpochNumber;
@@ -55,11 +40,10 @@ export declare class ProverNodePublisher {
55
40
  proof: Proof;
56
41
  batchedBlobInputs: BatchedBlob;
57
42
  attestations: ViemCommitteeAttestation[];
43
+ headers: CheckpointHeader[];
44
+ /** Wall-clock deadline (proof-submission window end) past which the L1 tx should stop retrying. */
45
+ deadline?: Date;
58
46
  }): Promise<boolean>;
59
- private waitUntilStartBuildsOnProven;
60
- private getProvenCheckpoint;
61
- private isStartBuildingOnProven;
62
- private getSecondsUntilProofSubmissionWindowEnd;
63
47
  private validateEpochProofSubmission;
64
48
  /**
65
49
  * Estimates what submitting the epoch proof would have cost on L1 without actually sending it.
@@ -74,10 +58,11 @@ export declare class ProverNodePublisher {
74
58
  proof: Proof;
75
59
  batchedBlobInputs: BatchedBlob;
76
60
  attestations: ViemCommitteeAttestation[];
61
+ headers: CheckpointHeader[];
77
62
  }): Promise<void>;
78
63
  private encodeSubmitEpochProofCalldata;
79
64
  private sendSubmitEpochProofTx;
80
65
  private getEpochProofPublicInputsArgs;
81
66
  private getSubmitEpochProofArgs;
82
67
  }
83
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmVyLW5vZGUtcHVibGlzaGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJvdmVyLW5vZGUtcHVibGlzaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQThCLE1BQU0saUJBQWlCLENBQUM7QUFDMUUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDN0QsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDMUYsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFN0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWhGLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLEtBQUssTUFBTSxFQUFFLEtBQUssY0FBYyxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBRXZGLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBR3pELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUcvRSxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVqRixPQUFPLEVBQUUsS0FBSyxlQUFlLEVBQXNCLE1BQU0seUJBQXlCLENBQUM7QUFHbkYsT0FBTyxFQUFFLEtBQUssR0FBRyxFQUF3RSxNQUFNLE1BQU0sQ0FBQztBQUl0RyxzRUFBc0U7QUFDdEUsTUFBTSxNQUFNLHNCQUFzQixHQUFHO0lBQ25DLFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIsZUFBZSxFQUFFLEVBQUUsQ0FBQztJQUNwQixVQUFVLEVBQUUsRUFBRSxDQUFDO0lBQ2YsWUFBWSxFQUFFLEVBQUUsQ0FBQztJQUNqQixPQUFPLEVBQUUsRUFBRSxDQUFDO0lBQ1osUUFBUSxFQUFFLEVBQUUsQ0FBQztJQUNiLElBQUksRUFBRSxLQUFLLENBQUMsWUFBWSxFQUFFLE9BQU8seUJBQXlCLENBQUMsQ0FBQztJQUM1RCxLQUFLLEVBQUUsS0FBSyxDQUFDO0NBQ2QsQ0FBQztBQUVGLHFCQUFhLG1CQUFtQjtJQUM5QixPQUFPLENBQUMsV0FBVyxDQUFTO0lBQzVCLE9BQU8sQ0FBQyxPQUFPLENBQTZCO0lBRTVDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDO0lBRXRCLFNBQVMsQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDO0lBRXpDLFNBQVMsQ0FBQyxxQkFBcUIsRUFBRSxHQUFHLENBQUM7SUFFckMsU0FBZ0IsU0FBUyxFQUFFLFNBQVMsQ0FBQztJQUVyQyxZQUNFLE1BQU0sRUFBRSxjQUFjLEdBQUcsZUFBZSxFQUN4QyxJQUFJLEVBQUU7UUFDSixjQUFjLEVBQUUsY0FBYyxDQUFDO1FBQy9CLFNBQVMsRUFBRSxTQUFTLENBQUM7UUFDckIscUJBQXFCLENBQUMsRUFBRSxVQUFVLENBQUM7UUFDbkMsU0FBUyxDQUFDLEVBQUUsZUFBZSxDQUFDO0tBQzdCLEVBQ0QsUUFBUSxDQUFDLEVBQUUsY0FBYyxFQVUxQjtJQUVNLGlCQUFpQixtQkFFdkI7SUFFRDs7Ozs7T0FLRztJQUNJLFNBQVMsU0FHZjtJQUVELHdEQUF3RDtJQUNqRCxPQUFPLFNBR2I7SUFFTSxnQkFBZ0IsZUFFdEI7SUFFWSxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUU7UUFDbEMsV0FBVyxFQUFFLFdBQVcsQ0FBQztRQUN6QixjQUFjLEVBQUUsZ0JBQWdCLENBQUM7UUFDakMsWUFBWSxFQUFFLGdCQUFnQixDQUFDO1FBQy9CLFlBQVksRUFBRSxzQkFBc0IsQ0FBQztRQUNyQyxLQUFLLEVBQUUsS0FBSyxDQUFDO1FBQ2IsaUJBQWlCLEVBQUUsV0FBVyxDQUFDO1FBQy9CLFlBQVksRUFBRSx3QkFBd0IsRUFBRSxDQUFDO0tBQzFDLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQXNEbkI7WUFFYSw0QkFBNEI7WUFpQzVCLG1CQUFtQjtJQUlqQyxPQUFPLENBQUMsdUJBQXVCO1lBSWpCLHVDQUF1QztZQU12Qyw0QkFBNEI7SUFtRTFDOzs7O09BSUc7SUFDVSwyQkFBMkIsQ0FBQyxJQUFJLEVBQUU7UUFDN0MsV0FBVyxFQUFFLFdBQVcsQ0FBQztRQUN6QixjQUFjLEVBQUUsZ0JBQWdCLENBQUM7UUFDakMsWUFBWSxFQUFFLGdCQUFnQixDQUFDO1FBQy9CLFlBQVksRUFBRSxzQkFBc0IsQ0FBQztRQUNyQyxLQUFLLEVBQUUsS0FBSyxDQUFDO1FBQ2IsaUJBQWlCLEVBQUUsV0FBVyxDQUFDO1FBQy9CLFlBQVksRUFBRSx3QkFBd0IsRUFBRSxDQUFDO0tBQzFDLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQXNDaEI7SUFFRCxPQUFPLENBQUMsOEJBQThCO1lBZXhCLHNCQUFzQjtJQTRDcEMsT0FBTyxDQUFDLDZCQUE2QjtJQTBCckMsT0FBTyxDQUFDLHVCQUF1QjtDQXVCaEMifQ==
68
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmVyLW5vZGUtcHVibGlzaGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJvdmVyLW5vZGUtcHVibGlzaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQThCLE1BQU0saUJBQWlCLENBQUM7QUFFMUUsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDMUYsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWhGLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLEtBQUssTUFBTSxFQUFFLEtBQUssY0FBYyxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBR3ZGLE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUUvRSxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRXJGLE9BQU8sRUFBRSxLQUFLLGVBQWUsRUFBc0IsTUFBTSx5QkFBeUIsQ0FBQztBQU9uRixzRUFBc0U7QUFDdEUsTUFBTSxNQUFNLHNCQUFzQixHQUFHO0lBQ25DLFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIsZUFBZSxFQUFFLEVBQUUsQ0FBQztJQUNwQixVQUFVLEVBQUUsRUFBRSxDQUFDO0lBQ2YsWUFBWSxFQUFFLEVBQUUsQ0FBQztJQUNqQixPQUFPLEVBQUUsRUFBRSxDQUFDO0lBQ1osUUFBUSxFQUFFLEVBQUUsQ0FBQztJQUNiLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxDQUFDO0lBQzVCLEtBQUssRUFBRSxLQUFLLENBQUM7Q0FDZCxDQUFDO0FBRUYscUJBQWEsbUJBQW1CO0lBQzlCLE9BQU8sQ0FBQyxPQUFPLENBQTZCO0lBRTVDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDO0lBRXRCLFNBQVMsQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDO0lBRXpDLFNBQWdCLFNBQVMsRUFBRSxTQUFTLENBQUM7SUFFckMsWUFDRSxNQUFNLEVBQUUsY0FBYyxHQUFHLGVBQWUsRUFDeEMsSUFBSSxFQUFFO1FBQ0osY0FBYyxFQUFFLGNBQWMsQ0FBQztRQUMvQixTQUFTLEVBQUUsU0FBUyxDQUFDO1FBQ3JCLFNBQVMsQ0FBQyxFQUFFLGVBQWUsQ0FBQztLQUM3QixFQUNELFFBQVEsQ0FBQyxFQUFFLGNBQWMsRUFTMUI7SUFFTSxpQkFBaUIsbUJBRXZCO0lBRU0sZ0JBQWdCLGVBRXRCO0lBRVksZ0JBQWdCLENBQUMsSUFBSSxFQUFFO1FBQ2xDLFdBQVcsRUFBRSxXQUFXLENBQUM7UUFDekIsY0FBYyxFQUFFLGdCQUFnQixDQUFDO1FBQ2pDLFlBQVksRUFBRSxnQkFBZ0IsQ0FBQztRQUMvQixZQUFZLEVBQUUsc0JBQXNCLENBQUM7UUFDckMsS0FBSyxFQUFFLEtBQUssQ0FBQztRQUNiLGlCQUFpQixFQUFFLFdBQVcsQ0FBQztRQUMvQixZQUFZLEVBQUUsd0JBQXdCLEVBQUUsQ0FBQztRQUN6QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQztRQUM1QixtR0FBbUc7UUFDbkcsUUFBUSxDQUFDLEVBQUUsSUFBSSxDQUFDO0tBQ2pCLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQTZDbkI7WUFFYSw0QkFBNEI7SUFvRTFDOzs7O09BSUc7SUFDVSwyQkFBMkIsQ0FBQyxJQUFJLEVBQUU7UUFDN0MsV0FBVyxFQUFFLFdBQVcsQ0FBQztRQUN6QixjQUFjLEVBQUUsZ0JBQWdCLENBQUM7UUFDakMsWUFBWSxFQUFFLGdCQUFnQixDQUFDO1FBQy9CLFlBQVksRUFBRSxzQkFBc0IsQ0FBQztRQUNyQyxLQUFLLEVBQUUsS0FBSyxDQUFDO1FBQ2IsaUJBQWlCLEVBQUUsV0FBVyxDQUFDO1FBQy9CLFlBQVksRUFBRSx3QkFBd0IsRUFBRSxDQUFDO1FBQ3pDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxDQUFDO0tBQzdCLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQXNDaEI7SUFFRCxPQUFPLENBQUMsOEJBQThCO1lBZ0J4QixzQkFBc0I7SUFpRHBDLE9BQU8sQ0FBQyw2QkFBNkI7SUF1QnJDLE9BQU8sQ0FBQyx1QkFBdUI7Q0F3QmhDIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"prover-node-publisher.d.ts","sourceRoot":"","sources":["../src/prover-node-publisher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prover-node-publisher.d.ts","sourceRoot":"","sources":["../src/prover-node-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA8B,MAAM,iBAAiB,CAAC;AAE1E,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAgB,MAAM,uBAAuB,CAAC;AAGvF,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE/E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAErF,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAOnF,sEAAsE;AACtE,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,EAAE,CAAC;IACpB,UAAU,EAAE,EAAE,CAAC;IACf,YAAY,EAAE,EAAE,CAAC;IACjB,OAAO,EAAE,EAAE,CAAC;IACZ,QAAQ,EAAE,EAAE,CAAC;IACb,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAA6B;IAE5C,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC;IAEtB,SAAS,CAAC,cAAc,EAAE,cAAc,CAAC;IAEzC,SAAgB,SAAS,EAAE,SAAS,CAAC;IAErC,YACE,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,EACD,QAAQ,CAAC,EAAE,cAAc,EAS1B;IAEM,iBAAiB,mBAEvB;IAEM,gBAAgB,eAEtB;IAEY,gBAAgB,CAAC,IAAI,EAAE;QAClC,WAAW,EAAE,WAAW,CAAC;QACzB,cAAc,EAAE,gBAAgB,CAAC;QACjC,YAAY,EAAE,gBAAgB,CAAC;QAC/B,YAAY,EAAE,sBAAsB,CAAC;QACrC,KAAK,EAAE,KAAK,CAAC;QACb,iBAAiB,EAAE,WAAW,CAAC;QAC/B,YAAY,EAAE,wBAAwB,EAAE,CAAC;QACzC,OAAO,EAAE,gBAAgB,EAAE,CAAC;QAC5B,mGAAmG;QACnG,QAAQ,CAAC,EAAE,IAAI,CAAC;KACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CA6CnB;YAEa,4BAA4B;IAoE1C;;;;OAIG;IACU,2BAA2B,CAAC,IAAI,EAAE;QAC7C,WAAW,EAAE,WAAW,CAAC;QACzB,cAAc,EAAE,gBAAgB,CAAC;QACjC,YAAY,EAAE,gBAAgB,CAAC;QAC/B,YAAY,EAAE,sBAAsB,CAAC;QACrC,KAAK,EAAE,KAAK,CAAC;QACb,iBAAiB,EAAE,WAAW,CAAC;QAC/B,YAAY,EAAE,wBAAwB,EAAE,CAAC;QACzC,OAAO,EAAE,gBAAgB,EAAE,CAAC;KAC7B,GAAG,OAAO,CAAC,IAAI,CAAC,CAsChB;IAED,OAAO,CAAC,8BAA8B;YAgBxB,sBAAsB;IAiDpC,OAAO,CAAC,6BAA6B;IAuBrC,OAAO,CAAC,uBAAuB;CAwBhC"}
@@ -1,51 +1,32 @@
1
1
  import { getEthBlobEvaluationInputs } from '@aztec/blob-lib';
2
2
  import { MAX_CHECKPOINTS_PER_EPOCH } from '@aztec/constants';
3
- import { makeTuple } from '@aztec/foundation/array';
4
3
  import { CheckpointNumber } from '@aztec/foundation/branded-types';
5
4
  import { areArraysEqual } from '@aztec/foundation/collection';
6
5
  import { Fr } from '@aztec/foundation/curves/bn254';
7
6
  import { EthAddress } from '@aztec/foundation/eth-address';
8
7
  import { createLogger } from '@aztec/foundation/log';
9
- import { retryUntil } from '@aztec/foundation/retry';
10
8
  import { Timer } from '@aztec/foundation/timer';
11
9
  import { RollupAbi } from '@aztec/l1-artifacts';
12
10
  import { CommitteeAttestation, CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
13
- import { getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
14
11
  import { getTelemetryClient } from '@aztec/telemetry-client';
15
12
  import { inspect } from 'util';
16
13
  import { encodeFunctionData, formatEther, formatGwei } from 'viem';
17
14
  import { ProverNodePublisherMetrics } from './metrics.js';
18
15
  export class ProverNodePublisher {
19
- interrupted = false;
20
16
  metrics;
21
17
  log;
22
18
  rollupContract;
23
- proofSubmissionTarget;
24
19
  l1TxUtils;
25
20
  constructor(config, deps, bindings){
26
21
  const telemetry = deps.telemetry ?? getTelemetryClient();
27
22
  this.metrics = new ProverNodePublisherMetrics(telemetry, 'ProverNode');
28
23
  this.log = createLogger('prover-node:l1-tx-publisher', bindings);
29
24
  this.rollupContract = deps.rollupContract;
30
- this.proofSubmissionTarget = deps.proofSubmissionTarget?.toString() ?? deps.rollupContract.address;
31
25
  this.l1TxUtils = deps.l1TxUtils;
32
26
  }
33
27
  getRollupContract() {
34
28
  return this.rollupContract;
35
29
  }
36
- /**
37
- * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
38
- * Be warned, the call may return false even if the tx subsequently gets successfully mined.
39
- * In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
40
- * A call to `restart` is required before you can continue publishing.
41
- */ interrupt() {
42
- this.interrupted = true;
43
- this.l1TxUtils.interrupt();
44
- }
45
- /** Restarts the publisher after calling `interrupt`. */ restart() {
46
- this.interrupted = false;
47
- this.l1TxUtils.restart();
48
- }
49
30
  getSenderAddress() {
50
31
  return this.l1TxUtils.getSenderAddress();
51
32
  }
@@ -56,86 +37,43 @@ export class ProverNodePublisher {
56
37
  fromCheckpoint,
57
38
  toCheckpoint
58
39
  };
59
- if (!this.interrupted) {
60
- if (!await this.waitUntilStartBuildsOnProven(args)) {
61
- this.log.verbose('Checkpoint data syncing interrupted', ctx);
62
- return false;
63
- }
64
- const timer = new Timer();
65
- // Validate epoch proof range and hashes are correct before submitting
66
- await this.validateEpochProofSubmission(args);
67
- const txReceipt = await this.sendSubmitEpochProofTx(args);
68
- if (!txReceipt) {
69
- this.log.error(`Failed to mine submitEpochProof tx`, undefined, ctx);
70
- return false;
71
- }
72
- try {
73
- this.metrics.recordSenderBalance(await this.l1TxUtils.getSenderBalance(), this.l1TxUtils.getSenderAddress().toString());
74
- } catch (err) {
75
- this.log.warn(`Failed to record the ETH balance of the prover node: ${err}`);
76
- }
77
- // Tx was mined successfully
78
- if (txReceipt.status === 'success') {
79
- const tx = await this.l1TxUtils.getTransactionStats(txReceipt.transactionHash);
80
- const stats = {
81
- gasPrice: txReceipt.effectiveGasPrice,
82
- gasUsed: txReceipt.gasUsed,
83
- transactionHash: txReceipt.transactionHash,
84
- calldataGas: tx.calldataGas,
85
- calldataSize: tx.calldataSize,
86
- sender: tx.sender,
87
- blobDataGas: 0n,
88
- blobGasUsed: 0n,
89
- eventName: 'proof-published-to-l1'
90
- };
91
- this.log.info(`Published epoch proof to L1 rollup contract`, {
92
- ...stats,
93
- ...ctx
94
- });
95
- this.metrics.recordSubmitProof(timer.ms(), stats);
96
- return true;
97
- }
98
- this.metrics.recordFailedTx();
99
- this.log.error(`Rollup submitEpochProof tx reverted ${txReceipt.transactionHash}`, undefined, ctx);
40
+ const timer = new Timer();
41
+ // Validate epoch proof range and hashes are correct before submitting
42
+ await this.validateEpochProofSubmission(args);
43
+ const txReceipt = await this.sendSubmitEpochProofTx(args);
44
+ if (!txReceipt) {
45
+ this.log.error(`Failed to mine submitEpochProof tx`, undefined, ctx);
46
+ return false;
100
47
  }
101
- this.log.verbose('Checkpoint data syncing interrupted', ctx);
102
- return false;
103
- }
104
- async waitUntilStartBuildsOnProven(args) {
105
- const { epochNumber, fromCheckpoint } = args;
106
- const provenCheckpoint = await this.getProvenCheckpoint();
107
- if (this.isStartBuildingOnProven(fromCheckpoint, provenCheckpoint)) {
108
- return true;
48
+ try {
49
+ this.metrics.recordSenderBalance(await this.l1TxUtils.getSenderBalance(), this.l1TxUtils.getSenderAddress().toString());
50
+ } catch (err) {
51
+ this.log.warn(`Failed to record the ETH balance of the prover node: ${err}`);
109
52
  }
110
- const timeout = await this.getSecondsUntilProofSubmissionWindowEnd(epochNumber);
111
- this.log.info(`Waiting for proven checkpoint to reach proof start`, {
112
- epochNumber,
113
- fromCheckpoint,
114
- provenCheckpoint,
115
- timeout
116
- });
117
- await retryUntil(async ()=>{
118
- if (this.interrupted) {
119
- return true;
120
- }
121
- const proven = await this.getProvenCheckpoint();
122
- this.log.verbose(`Proven checkpoint is at ${proven} (waiting for ${fromCheckpoint - 1})`, {
123
- epochNumber
53
+ // Tx was mined successfully
54
+ if (txReceipt.status === 'success') {
55
+ const tx = await this.l1TxUtils.getTransactionStats(txReceipt.transactionHash);
56
+ const stats = {
57
+ gasPrice: txReceipt.effectiveGasPrice,
58
+ gasUsed: txReceipt.gasUsed,
59
+ transactionHash: txReceipt.transactionHash,
60
+ calldataGas: tx.calldataGas,
61
+ calldataSize: tx.calldataSize,
62
+ sender: tx.sender,
63
+ blobDataGas: 0n,
64
+ blobGasUsed: 0n,
65
+ eventName: 'proof-published-to-l1'
66
+ };
67
+ this.log.info(`Published epoch proof to L1 rollup contract`, {
68
+ ...stats,
69
+ ...ctx
124
70
  });
125
- return this.isStartBuildingOnProven(fromCheckpoint, proven) ? true : undefined;
126
- }, `proven checkpoint to reach ${fromCheckpoint - 1}`, timeout, 4);
127
- return !this.interrupted;
128
- }
129
- async getProvenCheckpoint() {
130
- return (await this.rollupContract.getTips()).proven;
131
- }
132
- isStartBuildingOnProven(fromCheckpoint, provenCheckpoint) {
133
- return fromCheckpoint - 1 <= provenCheckpoint;
134
- }
135
- async getSecondsUntilProofSubmissionWindowEnd(epochNumber) {
136
- const deadline = getProofSubmissionDeadlineTimestamp(epochNumber, await this.rollupContract.getRollupConstants());
137
- const now = BigInt(Math.floor(Date.now() / 1000));
138
- return Math.max(Number(deadline - now), 0.001);
71
+ this.metrics.recordSubmitProof(timer.ms(), stats);
72
+ return true;
73
+ }
74
+ this.metrics.recordFailedTx();
75
+ this.log.error(`Rollup submitEpochProof tx reverted ${txReceipt.transactionHash}`, undefined, ctx);
76
+ return false;
139
77
  }
140
78
  async validateEpochProofSubmission(args) {
141
79
  const { fromCheckpoint, toCheckpoint, publicInputs, batchedBlobInputs } = args;
@@ -191,7 +129,7 @@ export class ProverNodePublisher {
191
129
  const senderAddress = this.l1TxUtils.getSenderAddress();
192
130
  const [gasLimit, gasPrice, latestBlock] = await Promise.all([
193
131
  this.l1TxUtils.estimateGas(senderAddress.toString(), {
194
- to: this.proofSubmissionTarget,
132
+ to: this.rollupContract.address,
195
133
  data
196
134
  }),
197
135
  this.l1TxUtils.getGasPrice(),
@@ -245,8 +183,10 @@ export class ProverNodePublisher {
245
183
  });
246
184
  try {
247
185
  const { receipt } = await this.l1TxUtils.sendAndMonitorTransaction({
248
- to: this.proofSubmissionTarget,
186
+ to: this.rollupContract.address,
249
187
  data
188
+ }, {
189
+ txTimeoutAt: args.deadline
250
190
  });
251
191
  if (receipt.status !== 'success') {
252
192
  const errorMsg = await this.l1TxUtils.tryGetErrorFromRevertedTx(data, {
@@ -255,7 +195,7 @@ export class ProverNodePublisher {
255
195
  ],
256
196
  functionName: 'submitEpochRootProof',
257
197
  abi: RollupAbi,
258
- address: this.proofSubmissionTarget
198
+ address: this.rollupContract.address
259
199
  }, /*blobInputs*/ undefined, /*stateOverride*/ []);
260
200
  this.log.error(`Rollup submit epoch proof tx reverted with ${errorMsg ?? 'unknown error'}`);
261
201
  return undefined;
@@ -277,7 +217,7 @@ export class ProverNodePublisher {
277
217
  outHash: args.publicInputs.outHash.toString(),
278
218
  proverId: EthAddress.fromField(args.publicInputs.constants.proverId).toString()
279
219
  } /*_args*/ ,
280
- makeTuple(MAX_CHECKPOINTS_PER_EPOCH * 2, (i)=>i % 2 === 0 ? args.publicInputs.fees[i / 2].recipient.toField().toString() : args.publicInputs.fees[(i - 1) / 2].value.toString()),
220
+ args.headers.map((header)=>header.toViem()),
281
221
  getEthBlobEvaluationInputs(args.batchedBlobInputs)
282
222
  ];
283
223
  }
@@ -289,7 +229,7 @@ export class ProverNodePublisher {
289
229
  start: argsArray[0],
290
230
  end: argsArray[1],
291
231
  args: argsArray[2],
292
- fees: argsArray[3],
232
+ headers: argsArray[3],
293
233
  attestations: CommitteeAttestationsAndSigners.packAttestations(args.attestations.map((a)=>CommitteeAttestation.fromViem(a))),
294
234
  blobInputs: argsArray[4],
295
235
  proof: proofHex