@aztec/prover-node 0.0.1-commit.b33fc05d0 → 0.0.1-commit.b3d3157a

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 (37) hide show
  1. package/dest/actions/download-epoch-proving-job.js +1 -1
  2. package/dest/actions/rerun-epoch-proving-job.d.ts +3 -2
  3. package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
  4. package/dest/actions/rerun-epoch-proving-job.js +105 -25
  5. package/dest/bin/run-failed-epoch.js +1 -3
  6. package/dest/factory.d.ts +1 -1
  7. package/dest/factory.d.ts.map +1 -1
  8. package/dest/factory.js +26 -6
  9. package/dest/job/epoch-proving-job.d.ts +6 -2
  10. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  11. package/dest/job/epoch-proving-job.js +186 -36
  12. package/dest/metrics.d.ts +11 -1
  13. package/dest/metrics.d.ts.map +1 -1
  14. package/dest/metrics.js +22 -0
  15. package/dest/monitors/epoch-monitor.d.ts +1 -1
  16. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  17. package/dest/monitors/epoch-monitor.js +11 -9
  18. package/dest/prover-node-publisher.d.ts +20 -1
  19. package/dest/prover-node-publisher.d.ts.map +1 -1
  20. package/dest/prover-node-publisher.js +200 -5
  21. package/dest/prover-node.d.ts +6 -6
  22. package/dest/prover-node.d.ts.map +1 -1
  23. package/dest/prover-node.js +81 -34
  24. package/dest/prover-publisher-factory.d.ts +2 -2
  25. package/dest/prover-publisher-factory.d.ts.map +1 -1
  26. package/dest/prover-publisher-factory.js +3 -3
  27. package/package.json +23 -23
  28. package/src/actions/download-epoch-proving-job.ts +1 -1
  29. package/src/actions/rerun-epoch-proving-job.ts +16 -5
  30. package/src/bin/run-failed-epoch.ts +1 -2
  31. package/src/factory.ts +21 -4
  32. package/src/job/epoch-proving-job.ts +102 -36
  33. package/src/metrics.ts +37 -0
  34. package/src/monitors/epoch-monitor.ts +5 -6
  35. package/src/prover-node-publisher.ts +232 -9
  36. package/src/prover-node.ts +85 -46
  37. package/src/prover-publisher-factory.ts +3 -3
@@ -30,7 +30,7 @@ export async function downloadEpochProvingJob(
30
30
 
31
31
  const dataUrls = makeSnapshotPaths(location);
32
32
  log.info(`Downloading state snapshot from ${location} to local data directory`, { metadata, dataUrls });
33
- await snapshotSync({ dataUrls }, log, { ...config, ...metadata, snapshotsUrl: location });
33
+ await snapshotSync({ dataUrls }, log, { ...config, ...metadata, fileStore });
34
34
 
35
35
  const dataPath = urlJoin(location, 'data.bin');
36
36
  const localPath = config.jobDataDownloadPath;
@@ -1,10 +1,11 @@
1
- import { createArchiverStore } from '@aztec/archiver';
1
+ import { createArchiverStore, createContractDataSource } from '@aztec/archiver';
2
2
  import type { L1ContractsConfig } from '@aztec/ethereum/config';
3
3
  import type { Logger } from '@aztec/foundation/log';
4
4
  import { type ProverClientConfig, createProverClient } from '@aztec/prover-client';
5
5
  import { ProverBrokerConfig, createAndStartProvingBroker } from '@aztec/prover-client/broker';
6
6
  import { PublicProcessorFactory } from '@aztec/simulator/server';
7
7
  import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
8
+ import type { GenesisData } from '@aztec/stdlib/world-state';
8
9
  import { getTelemetryClient } from '@aztec/telemetry-client';
9
10
  import { createWorldState } from '@aztec/world-state';
10
11
 
@@ -23,17 +24,27 @@ export async function rerunEpochProvingJob(
23
24
  localPath: string,
24
25
  log: Logger,
25
26
  config: DataStoreConfig & ProverBrokerConfig & ProverClientConfig & Pick<L1ContractsConfig, 'aztecEpochDuration'>,
27
+ genesis?: GenesisData,
26
28
  ) {
27
29
  const jobData = deserializeEpochProvingJobData(readFileSync(localPath));
28
30
  log.info(`Loaded proving job data for epoch ${jobData.epochNumber}`);
29
31
 
30
32
  const telemetry = getTelemetryClient();
31
33
  const metrics = new ProverNodeJobMetrics(telemetry.getMeter('prover-job'), telemetry.getTracer('prover-job'));
32
- const worldState = await createWorldState(config);
33
- const archiver = await createArchiverStore(config);
34
- const publicProcessorFactory = new PublicProcessorFactory(archiver, undefined, undefined, log.getBindings());
34
+ await using worldState = await createWorldState(config, genesis);
35
+ const initialBlockHash = await worldState.getInitialHeader().hash();
36
+ const archiver = await createArchiverStore(config, initialBlockHash);
37
+ const publicProcessorFactory = new PublicProcessorFactory(
38
+ createContractDataSource(archiver),
39
+ undefined,
40
+ undefined,
41
+ log.getBindings(),
42
+ );
35
43
 
36
- const publisher = { submitEpochProof: () => Promise.resolve(true) };
44
+ const publisher = {
45
+ submitEpochProof: () => Promise.resolve(true),
46
+ analyzeEpochProofSubmission: () => Promise.resolve(),
47
+ };
37
48
  const l2BlockSourceForReorgDetection = undefined;
38
49
  const deadline = undefined;
39
50
 
@@ -1,6 +1,5 @@
1
1
  /* eslint-disable no-console */
2
2
  import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
3
- import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
4
3
  import { EthAddress } from '@aztec/foundation/eth-address';
5
4
  import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
6
5
  import { createLogger } from '@aztec/foundation/log';
@@ -50,7 +49,7 @@ async function rerunFailedEpoch(provingJobUrl: string, baseLocalDir: string) {
50
49
  logger.info(`Rerunning proving job from ${jobPath} with state from ${dataDir}`, metadata);
51
50
  const result = await rerunEpochProvingJob(jobPath, logger, {
52
51
  ...config,
53
- l1Contracts: { rollupAddress: metadata.rollupAddress } as L1ContractAddresses,
52
+ rollupAddress: metadata.rollupAddress,
54
53
  rollupVersion: metadata.rollupVersion,
55
54
  });
56
55
 
package/src/factory.ts CHANGED
@@ -3,6 +3,7 @@ import type { BlobClientInterface } from '@aztec/blob-client/client';
3
3
  import { Blob } from '@aztec/blob-lib';
4
4
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
5
5
  import { createEthereumChain } from '@aztec/ethereum/chain';
6
+ import { makeL1HttpTransport } from '@aztec/ethereum/client';
6
7
  import { RollupContract } from '@aztec/ethereum/contracts';
7
8
  import { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
8
9
  import { PublisherManager } from '@aztec/ethereum/publisher-manager';
@@ -27,7 +28,7 @@ import type {
27
28
  } from '@aztec/stdlib/interfaces/server';
28
29
  import { L1Metrics, type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
29
30
 
30
- import { createPublicClient, fallback, http } from 'viem';
31
+ import { createPublicClient } from 'viem';
31
32
 
32
33
  import type { SpecificProverNodeConfig } from './config.js';
33
34
  import { EpochMonitor } from './monitors/epoch-monitor.js';
@@ -95,11 +96,11 @@ export async function createProverNode(
95
96
 
96
97
  const publicClient = createPublicClient({
97
98
  chain: chain.chainInfo,
98
- transport: fallback(config.l1RpcUrls.map((url: string) => http(url, { batch: false }))),
99
+ transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
99
100
  pollingInterval: config.viemPollingIntervalMS,
100
101
  });
101
102
 
102
- const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
103
+ const rollupContract = new RollupContract(publicClient, config.rollupAddress.toString());
103
104
 
104
105
  const l1TxUtils = deps.l1TxUtils
105
106
  ? [deps.l1TxUtils]
@@ -118,11 +119,27 @@ export async function createProverNode(
118
119
  { telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
119
120
  );
120
121
 
122
+ // Create a funder L1TxUtils from the keystore funding account (if configured)
123
+ const fundingSigner = keyStoreManager?.createFundingSigner();
124
+ let funderL1TxUtils: L1TxUtils | undefined;
125
+ if (fundingSigner) {
126
+ const [funder] = await createL1TxUtilsFromSigners(
127
+ publicClient,
128
+ [fundingSigner],
129
+ { ...config, scope: 'prover' },
130
+ { telemetry, logger: log.createChild('l1-tx-utils:funder'), dateProvider },
131
+ );
132
+ funderL1TxUtils = funder;
133
+ }
134
+
121
135
  const publisherFactory =
122
136
  deps.publisherFactory ??
123
137
  new ProverPublisherFactory(config, {
124
138
  rollupContract,
125
- publisherManager: new PublisherManager(l1TxUtils, getPublisherConfigFromProverConfig(config), log.getBindings()),
139
+ publisherManager: new PublisherManager(l1TxUtils, getPublisherConfigFromProverConfig(config), {
140
+ bindings: log.getBindings(),
141
+ funder: funderL1TxUtils,
142
+ }),
126
143
  telemetry,
127
144
  });
128
145
 
@@ -1,7 +1,5 @@
1
- import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
1
  import { asyncPool } from '@aztec/foundation/async-pool';
3
2
  import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
4
- import { padArrayEnd } from '@aztec/foundation/collection';
5
3
  import { Fr } from '@aztec/foundation/curves/bn254';
6
4
  import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
7
5
  import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
@@ -20,8 +18,8 @@ import {
20
18
  EpochProvingJobTerminalState,
21
19
  type ForkMerkleTreeOperations,
22
20
  } from '@aztec/stdlib/interfaces/server';
21
+ import { appendL1ToL2MessagesToTree } from '@aztec/stdlib/messaging';
23
22
  import { CheckpointConstantData } from '@aztec/stdlib/rollup';
24
- import { MerkleTreeId } from '@aztec/stdlib/trees';
25
23
  import type { ProcessedTx, Tx } from '@aztec/stdlib/tx';
26
24
  import { Attributes, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
27
25
 
@@ -48,6 +46,7 @@ export class EpochProvingJob implements Traceable {
48
46
  private uuid: string;
49
47
 
50
48
  private runPromise: Promise<void> | undefined;
49
+ private abortController = new AbortController();
51
50
  private epochCheckPromise: RunningPromise | undefined;
52
51
  private deadlineTimeoutHandler: NodeJS.Timeout | undefined;
53
52
 
@@ -58,7 +57,7 @@ export class EpochProvingJob implements Traceable {
58
57
  private dbProvider: Pick<ForkMerkleTreeOperations, 'fork'>,
59
58
  private prover: EpochProver,
60
59
  private publicProcessorFactory: PublicProcessorFactory,
61
- private publisher: Pick<ProverNodePublisher, 'submitEpochProof'>,
60
+ private publisher: Pick<ProverNodePublisher, 'submitEpochProof' | 'analyzeEpochProofSubmission'>,
62
61
  private l2BlockSource: L2BlockSource | undefined,
63
62
  private metrics: ProverNodeJobMetrics,
64
63
  private deadline: Date | undefined,
@@ -172,7 +171,7 @@ export class EpochProvingJob implements Traceable {
172
171
  ? AVM_MAX_CONCURRENT_SIMULATIONS
173
172
  : this.checkpoints.length;
174
173
 
175
- await asyncPool(parallelism, this.checkpoints, async checkpoint => {
174
+ await this.processCheckpoints(parallelism, async checkpoint => {
176
175
  this.checkState();
177
176
  const checkpointTimer = new Timer();
178
177
 
@@ -191,11 +190,12 @@ export class EpochProvingJob implements Traceable {
191
190
  const previousHeader = previousBlockHeaders[checkpointIndex];
192
191
  const l1ToL2Messages = this.getL1ToL2Messages(checkpoint);
193
192
 
194
- this.log.verbose(`Starting processing checkpoint ${checkpoint.number}`, {
193
+ this.log.debug(`Starting processing checkpoint ${checkpoint.number}`, {
195
194
  number: checkpoint.number,
196
195
  checkpointHash: checkpoint.hash().toString(),
197
- lastArchive: checkpoint.header.lastArchiveRoot,
198
- previousHeader: previousHeader.hash(),
196
+ headerHash: checkpoint.header.hash().toString(),
197
+ numL1ToL2Messages: l1ToL2Messages.length,
198
+ previousBlockNumber: previousHeader.globalVariables.blockNumber,
199
199
  uuid: this.uuid,
200
200
  });
201
201
 
@@ -229,22 +229,26 @@ export class EpochProvingJob implements Traceable {
229
229
 
230
230
  // Process public fns. L1 to L2 messages are only inserted for the first block of a checkpoint,
231
231
  // as the fork for subsequent blocks already includes them from the previous block's synced state.
232
- const db = await this.createFork(
233
- BlockNumber(block.number - 1),
234
- blockIndex === 0 ? l1ToL2Messages : undefined,
235
- );
236
- const config = PublicSimulatorConfig.from({
237
- proverId: this.prover.getProverId().toField(),
238
- skipFeeEnforcement: false,
239
- collectDebugLogs: false,
240
- collectHints: true,
241
- collectPublicInputs: true,
242
- collectStatistics: false,
243
- });
244
- const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, config);
245
- const processed = await this.processTxs(publicProcessor, txs);
246
- await this.prover.addTxs(processed);
247
- await db.close();
232
+ {
233
+ await using db = await this.createFork(
234
+ BlockNumber(block.number - 1),
235
+ blockIndex === 0 ? l1ToL2Messages : undefined,
236
+ );
237
+ this.checkState();
238
+ const config = PublicSimulatorConfig.from({
239
+ proverId: this.prover.getProverId().toField(),
240
+ skipFeeEnforcement: false,
241
+ collectDebugLogs: false,
242
+ collectHints: true,
243
+ collectPublicInputs: true,
244
+ collectStatistics: false,
245
+ });
246
+ const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, config);
247
+ const processed = await this.processTxs(publicProcessor, txs);
248
+ this.checkState();
249
+ await this.prover.addTxs(processed);
250
+ }
251
+ this.checkState();
248
252
  this.log.verbose(`Processed all ${txs.length} txs for block ${block.number}`, {
249
253
  blockNumber: block.number,
250
254
  blockHash: (await block.hash()).toString(),
@@ -270,8 +274,21 @@ export class EpochProvingJob implements Traceable {
270
274
 
271
275
  if (this.config.skipSubmitProof) {
272
276
  this.log.info(
273
- `Proof publishing is disabled. Dropping valid proof for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`,
277
+ `Proof publishing is disabled. Analyzing estimated L1 fees for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`,
274
278
  );
279
+ try {
280
+ await this.publisher.analyzeEpochProofSubmission({
281
+ fromCheckpoint,
282
+ toCheckpoint,
283
+ epochNumber,
284
+ publicInputs,
285
+ proof,
286
+ batchedBlobInputs,
287
+ attestations,
288
+ });
289
+ } catch (err) {
290
+ this.log.warn(`Failed to analyze estimated L1 fees for epoch ${epochNumber}`, err);
291
+ }
275
292
  this.state = 'completed';
276
293
  this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeCheckpoints, epochSizeBlocks, epochSizeTxs);
277
294
  return;
@@ -325,25 +342,56 @@ export class EpochProvingJob implements Traceable {
325
342
  */
326
343
  private async createFork(blockNumber: BlockNumber, l1ToL2Messages: Fr[] | undefined) {
327
344
  this.log.verbose(`Creating fork at ${blockNumber}`, { blockNumber });
328
- const db = await this.dbProvider.fork(blockNumber);
345
+ // temporary stack to control fork lifetime
346
+ await using cleanup = new AsyncDisposableStack();
347
+ const db = cleanup.use(await this.dbProvider.fork(blockNumber));
329
348
 
330
349
  if (l1ToL2Messages !== undefined) {
331
350
  this.log.verbose(`Inserting ${l1ToL2Messages.length} L1 to L2 messages in fork`, {
332
351
  blockNumber,
333
352
  l1ToL2Messages: l1ToL2Messages.map(m => m.toString()),
334
353
  });
335
- const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
336
- l1ToL2Messages,
337
- Fr.ZERO,
338
- NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
339
- 'Too many L1 to L2 messages',
340
- );
341
- await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
354
+ await appendL1ToL2MessagesToTree(db, l1ToL2Messages);
342
355
  }
343
356
 
357
+ // everything run succesfully so we can release this stack and give control of the fork's lifetime to the caller
358
+ cleanup.move();
344
359
  return db;
345
360
  }
346
361
 
362
+ private async processCheckpoints(
363
+ parallelism: number,
364
+ processCheckpoint: (checkpoint: Checkpoint) => Promise<void>,
365
+ ): Promise<void> {
366
+ let hasError = false;
367
+ let firstError: unknown;
368
+
369
+ await asyncPool(Math.max(parallelism, 1), this.checkpoints, async checkpoint => {
370
+ if (hasError || this.abortController.signal.aborted) {
371
+ return;
372
+ }
373
+
374
+ try {
375
+ this.checkState();
376
+ await processCheckpoint(checkpoint);
377
+ } catch (err) {
378
+ if (!hasError) {
379
+ hasError = true;
380
+ firstError = err;
381
+ this.failProcessing();
382
+ }
383
+ }
384
+ });
385
+
386
+ if (hasError) {
387
+ throw firstError;
388
+ }
389
+
390
+ if (this.abortController.signal.aborted) {
391
+ this.checkState();
392
+ }
393
+ }
394
+
347
395
  private progressState(state: EpochProvingJobState) {
348
396
  this.checkState();
349
397
  this.state = state;
@@ -357,12 +405,24 @@ export class EpochProvingJob implements Traceable {
357
405
 
358
406
  public async stop(state: EpochProvingJobTerminalState = 'stopped') {
359
407
  this.state = state;
360
- this.prover.cancel();
408
+ this.interruptProcessing();
361
409
  if (this.runPromise) {
362
410
  await this.runPromise;
363
411
  }
364
412
  }
365
413
 
414
+ private failProcessing() {
415
+ if (!EpochProvingJobTerminalState.includes(this.state)) {
416
+ this.state = 'failed';
417
+ }
418
+ this.interruptProcessing();
419
+ }
420
+
421
+ private interruptProcessing() {
422
+ this.abortController.abort();
423
+ this.prover.cancel();
424
+ }
425
+
366
426
  private scheduleDeadlineStop() {
367
427
  const deadline = this.deadline;
368
428
  if (deadline) {
@@ -397,7 +457,9 @@ export class EpochProvingJob implements Traceable {
397
457
  const intervalMs = Math.ceil((await l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
398
458
  this.epochCheckPromise = new RunningPromise(
399
459
  async () => {
400
- const blockHeaders = await l2BlockSource.getCheckpointedBlockHeadersForEpoch(this.epochNumber);
460
+ const blockHeaders = (
461
+ await l2BlockSource.getBlocksData({ epoch: this.epochNumber, onlyCheckpointed: true })
462
+ ).map(d => d.header);
401
463
  const blockHashes = await Promise.all(blockHeaders.map(header => header.hash()));
402
464
  const thisBlocks = this.checkpoints.flatMap(checkpoint => checkpoint.blocks);
403
465
  const thisBlockHashes = await Promise.all(thisBlocks.map(block => block.hash()));
@@ -436,7 +498,11 @@ export class EpochProvingJob implements Traceable {
436
498
 
437
499
  private async processTxs(publicProcessor: PublicProcessor, txs: Tx[]): Promise<ProcessedTx[]> {
438
500
  const { deadline } = this;
439
- const [processedTxs, failedTxs] = await publicProcessor.process(txs, { deadline });
501
+ const [processedTxs, failedTxs] = await publicProcessor.process(txs, {
502
+ deadline,
503
+ signal: this.abortController.signal,
504
+ });
505
+ this.checkState();
440
506
 
441
507
  if (failedTxs.length) {
442
508
  const failedTxHashes = await Promise.all(failedTxs.map(({ tx }) => tx.getTxHash()));
package/src/metrics.ts CHANGED
@@ -140,6 +140,13 @@ export class ProverNodeRewardsMetrics {
140
140
  };
141
141
  }
142
142
 
143
+ export type EstimatedSubmitProofStats = {
144
+ gasLimit: bigint;
145
+ baseFeePerGas: bigint;
146
+ maxPriorityFeePerGas: bigint;
147
+ estimatedTotalFee: bigint;
148
+ };
149
+
143
150
  export class ProverNodePublisherMetrics {
144
151
  gasPrice: Histogram;
145
152
  txCount: UpDownCounter;
@@ -151,6 +158,10 @@ export class ProverNodePublisherMetrics {
151
158
  txBlobDataGasCost: Histogram;
152
159
  txTotalFee: Histogram;
153
160
 
161
+ private txGasEstimated: Histogram;
162
+ private gasPriceEstimated: Histogram;
163
+ private txTotalFeeEstimated: Histogram;
164
+
154
165
  private senderBalance: Gauge;
155
166
  private meter: Meter;
156
167
 
@@ -182,6 +193,12 @@ export class ProverNodePublisherMetrics {
182
193
 
183
194
  this.txTotalFee = this.meter.createHistogram(Metrics.L1_PUBLISHER_TX_TOTAL_FEE);
184
195
 
196
+ this.txGasEstimated = this.meter.createHistogram(Metrics.PROVER_NODE_ESTIMATED_SUBMISSION_GAS);
197
+
198
+ this.gasPriceEstimated = this.meter.createHistogram(Metrics.PROVER_NODE_ESTIMATED_SUBMISSION_GAS_PRICE);
199
+
200
+ this.txTotalFeeEstimated = this.meter.createHistogram(Metrics.PROVER_NODE_ESTIMATED_SUBMISSION_TOTAL_FEE);
201
+
185
202
  this.senderBalance = this.meter.createGauge(Metrics.L1_PUBLISHER_BALANCE);
186
203
  }
187
204
 
@@ -196,6 +213,26 @@ export class ProverNodePublisherMetrics {
196
213
  this.recordTx(durationMs, stats);
197
214
  }
198
215
 
216
+ public recordEstimatedSubmitProof(stats: EstimatedSubmitProofStats) {
217
+ const attributes = { [Attributes.L1_TX_TYPE]: 'submitProof' } as const;
218
+
219
+ this.txGasEstimated.record(Number(stats.gasLimit), attributes);
220
+
221
+ try {
222
+ this.gasPriceEstimated.record(
223
+ parseInt(formatEther(stats.baseFeePerGas + stats.maxPriorityFeePerGas, 'gwei'), 10),
224
+ );
225
+ } catch {
226
+ // ignore
227
+ }
228
+
229
+ try {
230
+ this.txTotalFeeEstimated.record(parseFloat(formatEther(stats.estimatedTotalFee)));
231
+ } catch {
232
+ // ignore
233
+ }
234
+ }
235
+
199
236
  public recordSenderBalance(wei: bigint, senderAddress: string) {
200
237
  const eth = parseFloat(formatEther(wei, 'wei'));
201
238
  this.senderBalance.record(eth, {
@@ -69,9 +69,8 @@ export class EpochMonitor implements Traceable {
69
69
 
70
70
  public async work() {
71
71
  const { epochToProve, blockNumber, slotNumber } = await this.getEpochNumberToProve();
72
- this.log.debug(`Epoch to prove: ${epochToProve}`, { blockNumber, slotNumber });
73
72
  if (epochToProve === undefined) {
74
- this.log.trace(`Next block to prove ${blockNumber} not yet mined`, { blockNumber });
73
+ this.log.trace(`Next block to prove ${blockNumber} not yet mined`, { epochToProve, blockNumber, slotNumber });
75
74
  return;
76
75
  }
77
76
  if (this.latestEpochNumber !== undefined && epochToProve <= this.latestEpochNumber) {
@@ -86,20 +85,20 @@ export class EpochMonitor implements Traceable {
86
85
  }
87
86
 
88
87
  if (this.options.provingDelayMs) {
89
- this.log.debug(`Waiting ${this.options.provingDelayMs}ms before proving epoch ${epochToProve}`);
88
+ this.log.warn(`Waiting ${this.options.provingDelayMs}ms before proving epoch ${epochToProve}`);
90
89
  await sleep(this.options.provingDelayMs);
91
90
  }
92
91
 
93
- this.log.debug(`Epoch ${epochToProve} is ready to be proven`);
92
+ this.log.verbose(`Epoch ${epochToProve} is ready to be proven`);
94
93
  if (await this.handler?.handleEpochReadyToProve(epochToProve)) {
95
94
  this.latestEpochNumber = epochToProve;
96
95
  }
97
96
  }
98
97
 
99
98
  private async getEpochNumberToProve() {
100
- const lastBlockProven = await this.l2BlockSource.getProvenBlockNumber();
99
+ const lastBlockProven = (await this.l2BlockSource.getBlockNumber({ tag: 'proven' })) ?? BlockNumber.ZERO;
101
100
  const firstBlockToProve = BlockNumber(lastBlockProven + 1);
102
- const firstBlockHeaderToProve = await this.l2BlockSource.getBlockHeader(firstBlockToProve);
101
+ const firstBlockHeaderToProve = (await this.l2BlockSource.getBlockData({ number: firstBlockToProve }))?.header;
103
102
  if (!firstBlockHeaderToProve) {
104
103
  return { epochToProve: undefined, blockNumber: firstBlockToProve };
105
104
  }