@aztec/prover-node 0.67.1 → 0.68.1

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 (40) hide show
  1. package/dest/config.d.ts +7 -7
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +7 -7
  4. package/dest/factory.d.ts.map +1 -1
  5. package/dest/factory.js +7 -8
  6. package/dest/job/epoch-proving-job.d.ts +3 -1
  7. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  8. package/dest/job/epoch-proving-job.js +146 -121
  9. package/dest/metrics.d.ts +4 -1
  10. package/dest/metrics.d.ts.map +1 -1
  11. package/dest/metrics.js +13 -2
  12. package/dest/monitors/claims-monitor.d.ts +4 -2
  13. package/dest/monitors/claims-monitor.d.ts.map +1 -1
  14. package/dest/monitors/claims-monitor.js +51 -34
  15. package/dest/monitors/epoch-monitor.d.ts +4 -2
  16. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  17. package/dest/monitors/epoch-monitor.js +47 -31
  18. package/dest/prover-coordination/factory.d.ts +2 -0
  19. package/dest/prover-coordination/factory.d.ts.map +1 -1
  20. package/dest/prover-coordination/factory.js +4 -4
  21. package/dest/prover-node.d.ts +8 -8
  22. package/dest/prover-node.d.ts.map +1 -1
  23. package/dest/prover-node.js +225 -212
  24. package/package.json +22 -20
  25. package/src/config.ts +7 -7
  26. package/src/factory.ts +6 -8
  27. package/src/job/epoch-proving-job.ts +34 -24
  28. package/src/metrics.ts +14 -2
  29. package/src/monitors/claims-monitor.ts +13 -3
  30. package/src/monitors/epoch-monitor.ts +11 -3
  31. package/src/prover-coordination/factory.ts +11 -2
  32. package/src/prover-node.ts +26 -22
  33. package/dest/prover-cache/cache_manager.d.ts +0 -15
  34. package/dest/prover-cache/cache_manager.d.ts.map +0 -1
  35. package/dest/prover-cache/cache_manager.js +0 -57
  36. package/dest/prover-cache/kv_cache.d.ts +0 -11
  37. package/dest/prover-cache/kv_cache.d.ts.map +0 -1
  38. package/dest/prover-cache/kv_cache.js +0 -20
  39. package/src/prover-cache/cache_manager.ts +0 -69
  40. package/src/prover-cache/kv_cache.ts +0 -27
package/src/factory.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type Archiver, createArchiver } from '@aztec/archiver';
2
2
  import { type ProverCoordination, type ProvingJobBroker } from '@aztec/circuit-types';
3
+ import { EpochCache } from '@aztec/epoch-cache';
3
4
  import { createEthereumChain } from '@aztec/ethereum';
4
5
  import { Buffer32 } from '@aztec/foundation/buffer';
5
6
  import { type Logger, createLogger } from '@aztec/foundation/log';
@@ -12,14 +13,12 @@ import { type TelemetryClient } from '@aztec/telemetry-client';
12
13
  import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
13
14
  import { createWorldStateSynchronizer } from '@aztec/world-state';
14
15
 
15
- import { join } from 'path';
16
16
  import { createPublicClient, getAddress, getContract, http } from 'viem';
17
17
 
18
18
  import { createBondManager } from './bond/factory.js';
19
19
  import { type ProverNodeConfig, type QuoteProviderConfig } from './config.js';
20
20
  import { ClaimsMonitor } from './monitors/claims-monitor.js';
21
21
  import { EpochMonitor } from './monitors/epoch-monitor.js';
22
- import { ProverCacheManager } from './prover-cache/cache_manager.js';
23
22
  import { createProverCoordination } from './prover-coordination/factory.js';
24
23
  import { ProverNode, type ProverNodeOptions } from './prover-node.js';
25
24
  import { HttpQuoteProvider } from './quote-provider/http.js';
@@ -53,12 +52,15 @@ export async function createProverNode(
53
52
  // REFACTOR: Move publisher out of sequencer package and into an L1-related package
54
53
  const publisher = deps.publisher ?? new L1Publisher(config, telemetry);
55
54
 
55
+ const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config);
56
+
56
57
  // If config.p2pEnabled is true, createProverCoordination will create a p2p client where quotes will be shared and tx's requested
57
58
  // If config.p2pEnabled is false, createProverCoordination request information from the AztecNode
58
59
  const proverCoordination = await createProverCoordination(config, {
59
60
  aztecNodeTxProvider: deps.aztecNodeTxProvider,
60
61
  worldStateSynchronizer,
61
62
  archiver,
63
+ epochCache,
62
64
  telemetry,
63
65
  });
64
66
 
@@ -71,16 +73,13 @@ export async function createProverNode(
71
73
  maxParallelBlocksPerEpoch: config.proverNodeMaxParallelBlocksPerEpoch,
72
74
  };
73
75
 
74
- const claimsMonitor = new ClaimsMonitor(publisher, proverNodeConfig);
75
- const epochMonitor = new EpochMonitor(archiver, proverNodeConfig);
76
+ const claimsMonitor = new ClaimsMonitor(publisher, telemetry, proverNodeConfig);
77
+ const epochMonitor = new EpochMonitor(archiver, telemetry, proverNodeConfig);
76
78
 
77
79
  const rollupContract = publisher.getRollupContract();
78
80
  const walletClient = publisher.getClient();
79
81
  const bondManager = await createBondManager(rollupContract, walletClient, config);
80
82
 
81
- const cacheDir = config.cacheDir ? join(config.cacheDir, `prover_${config.proverId}`) : undefined;
82
- const cacheManager = new ProverCacheManager(cacheDir);
83
-
84
83
  return new ProverNode(
85
84
  prover,
86
85
  publisher,
@@ -95,7 +94,6 @@ export async function createProverNode(
95
94
  epochMonitor,
96
95
  bondManager,
97
96
  telemetry,
98
- cacheManager,
99
97
  proverNodeConfig,
100
98
  );
101
99
  }
@@ -17,6 +17,7 @@ import { promiseWithResolvers } from '@aztec/foundation/promise';
17
17
  import { Timer } from '@aztec/foundation/timer';
18
18
  import { type L1Publisher } from '@aztec/sequencer-client';
19
19
  import { type PublicProcessor, type PublicProcessorFactory } from '@aztec/simulator';
20
+ import { Attributes, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
20
21
 
21
22
  import * as crypto from 'node:crypto';
22
23
 
@@ -27,13 +28,15 @@ import { type ProverNodeMetrics } from '../metrics.js';
27
28
  * re-executes their public calls, generates a rollup proof, and submits it to L1. This job will update the
28
29
  * world state as part of public call execution via the public processor.
29
30
  */
30
- export class EpochProvingJob {
31
+ export class EpochProvingJob implements Traceable {
31
32
  private state: EpochProvingJobState = 'initialized';
32
33
  private log = createLogger('prover-node:epoch-proving-job');
33
34
  private uuid: string;
34
35
 
35
36
  private runPromise: Promise<void> | undefined;
36
37
 
38
+ public readonly tracer: Tracer;
39
+
37
40
  constructor(
38
41
  private dbProvider: ForkMerkleTreeOperations,
39
42
  private epochNumber: bigint,
@@ -49,6 +52,7 @@ export class EpochProvingJob {
49
52
  private cleanUp: (job: EpochProvingJob) => Promise<void> = () => Promise.resolve(),
50
53
  ) {
51
54
  this.uuid = crypto.randomUUID();
55
+ this.tracer = metrics.client.getTracer('EpochProvingJob');
52
56
  }
53
57
 
54
58
  public getId(): string {
@@ -62,11 +66,21 @@ export class EpochProvingJob {
62
66
  /**
63
67
  * Proves the given epoch and submits the proof to L1.
64
68
  */
69
+ @trackSpan('EpochProvingJob.run', function () {
70
+ return { [Attributes.EPOCH_NUMBER]: Number(this.epochNumber) };
71
+ })
65
72
  public async run() {
66
73
  const epochNumber = Number(this.epochNumber);
67
- const epochSize = this.blocks.length;
68
- const firstBlockNumber = this.blocks[0].number;
69
- this.log.info(`Starting epoch proving job`, { firstBlockNumber, epochSize, epochNumber, uuid: this.uuid });
74
+ const epochSizeBlocks = this.blocks.length;
75
+ const epochSizeTxs = this.blocks.reduce((total, current) => total + current.body.numberOfTxsIncludingPadded, 0);
76
+ const [fromBlock, toBlock] = [this.blocks[0].number, this.blocks.at(-1)!.number];
77
+ this.log.info(`Starting epoch ${epochNumber} proving job with blocks ${fromBlock} to ${toBlock}`, {
78
+ fromBlock,
79
+ toBlock,
80
+ epochSizeBlocks,
81
+ epochNumber,
82
+ uuid: this.uuid,
83
+ });
70
84
  this.state = 'processing';
71
85
  const timer = new Timer();
72
86
 
@@ -74,17 +88,17 @@ export class EpochProvingJob {
74
88
  this.runPromise = promise;
75
89
 
76
90
  try {
77
- this.prover.startNewEpoch(epochNumber, firstBlockNumber, epochSize);
91
+ this.prover.startNewEpoch(epochNumber, fromBlock, epochSizeBlocks);
78
92
 
79
93
  await asyncPool(this.config.parallelBlockLimit, this.blocks, async block => {
80
94
  const globalVariables = block.header.globalVariables;
81
95
  const txHashes = block.body.txEffects.map(tx => tx.txHash);
82
96
  const txCount = block.body.numberOfTxsIncludingPadded;
83
97
  const l1ToL2Messages = await this.getL1ToL2Messages(block);
84
- const txs = await this.getTxs(txHashes);
98
+ const txs = await this.getTxs(txHashes, block.number);
85
99
  const previousHeader = await this.getBlockHeader(block.number - 1);
86
100
 
87
- this.log.verbose(`Starting block processing`, {
101
+ this.log.verbose(`Starting processing block ${block.number}`, {
88
102
  number: block.number,
89
103
  blockHash: block.hash().toString(),
90
104
  lastArchive: block.header.lastArchive.root,
@@ -95,16 +109,16 @@ export class EpochProvingJob {
95
109
  uuid: this.uuid,
96
110
  ...globalVariables,
97
111
  });
98
-
99
112
  // Start block proving
100
- await this.prover.startNewBlock(txCount, globalVariables, l1ToL2Messages);
113
+ await this.prover.startNewBlock(globalVariables, l1ToL2Messages);
101
114
 
102
115
  // Process public fns
103
116
  const db = await this.dbProvider.fork(block.number - 1);
104
- const publicProcessor = this.publicProcessorFactory.create(db, previousHeader, globalVariables);
105
- await this.processTxs(publicProcessor, txs, txCount);
117
+ const publicProcessor = this.publicProcessorFactory.create(db, previousHeader, globalVariables, true);
118
+ const processed = await this.processTxs(publicProcessor, txs, txCount);
119
+ await this.prover.addTxs(processed);
106
120
  await db.close();
107
- this.log.verbose(`Processed all txs for block`, {
121
+ this.log.verbose(`Processed all ${txs.length} txs for block ${block.number}`, {
108
122
  blockNumber: block.number,
109
123
  blockHash: block.hash().toString(),
110
124
  uuid: this.uuid,
@@ -116,17 +130,16 @@ export class EpochProvingJob {
116
130
 
117
131
  this.state = 'awaiting-prover';
118
132
  const { publicInputs, proof } = await this.prover.finaliseEpoch();
119
- this.log.info(`Finalised proof for epoch`, { epochNumber, uuid: this.uuid, duration: timer.ms() });
133
+ this.log.info(`Finalised proof for epoch ${epochNumber}`, { epochNumber, uuid: this.uuid, duration: timer.ms() });
120
134
 
121
135
  this.state = 'publishing-proof';
122
- const [fromBlock, toBlock] = [this.blocks[0].number, this.blocks.at(-1)!.number];
123
136
  await this.publisher.submitEpochProof({ fromBlock, toBlock, epochNumber, publicInputs, proof });
124
137
  this.log.info(`Submitted proof for epoch`, { epochNumber, uuid: this.uuid });
125
138
 
126
139
  this.state = 'completed';
127
- this.metrics.recordProvingJob(timer);
140
+ this.metrics.recordProvingJob(timer, epochSizeBlocks, epochSizeTxs);
128
141
  } catch (err) {
129
- this.log.error(`Error running epoch prover job`, err, { uuid: this.uuid });
142
+ this.log.error(`Error running epoch ${epochNumber} prover job`, err, { uuid: this.uuid, epochNumber });
130
143
  this.state = 'failed';
131
144
  } finally {
132
145
  await this.cleanUp(this);
@@ -149,13 +162,15 @@ export class EpochProvingJob {
149
162
  return this.l2BlockSource.getBlockHeader(blockNumber);
150
163
  }
151
164
 
152
- private async getTxs(txHashes: TxHash[]): Promise<Tx[]> {
165
+ private async getTxs(txHashes: TxHash[], blockNumber: number): Promise<Tx[]> {
153
166
  const txs = await Promise.all(
154
167
  txHashes.map(txHash => this.coordination.getTxByHash(txHash).then(tx => [txHash, tx] as const)),
155
168
  );
156
169
  const notFound = txs.filter(([_, tx]) => !tx);
157
170
  if (notFound.length) {
158
- throw new Error(`Txs not found: ${notFound.map(([txHash]) => txHash.toString()).join(', ')}`);
171
+ throw new Error(
172
+ `Txs not found for block ${blockNumber}: ${notFound.map(([txHash]) => txHash.toString()).join(', ')}`,
173
+ );
159
174
  }
160
175
  return txs.map(([_, tx]) => tx!);
161
176
  }
@@ -169,12 +184,7 @@ export class EpochProvingJob {
169
184
  txs: Tx[],
170
185
  totalNumberOfTxs: number,
171
186
  ): Promise<ProcessedTx[]> {
172
- const [processedTxs, failedTxs] = await publicProcessor.process(
173
- txs,
174
- totalNumberOfTxs,
175
- this.prover,
176
- new EmptyTxValidator(),
177
- );
187
+ const [processedTxs, failedTxs] = await publicProcessor.process(txs, totalNumberOfTxs, new EmptyTxValidator());
178
188
 
179
189
  if (failedTxs.length) {
180
190
  throw new Error(
package/src/metrics.ts CHANGED
@@ -3,18 +3,30 @@ import { type Histogram, Metrics, type TelemetryClient, ValueType } from '@aztec
3
3
 
4
4
  export class ProverNodeMetrics {
5
5
  provingJobDuration: Histogram;
6
+ provingJobBlocks: Histogram;
7
+ provingJobTransactions: Histogram;
6
8
 
7
- constructor(client: TelemetryClient, name = 'ProverNode') {
9
+ constructor(public readonly client: TelemetryClient, name = 'ProverNode') {
8
10
  const meter = client.getMeter(name);
9
11
  this.provingJobDuration = meter.createHistogram(Metrics.PROVER_NODE_JOB_DURATION, {
10
12
  description: 'Duration of proving job',
11
13
  unit: 'ms',
12
14
  valueType: ValueType.INT,
13
15
  });
16
+ this.provingJobBlocks = meter.createHistogram(Metrics.PROVER_NODE_JOB_BLOCKS, {
17
+ description: 'Number of blocks in a proven epoch',
18
+ valueType: ValueType.INT,
19
+ });
20
+ this.provingJobTransactions = meter.createHistogram(Metrics.PROVER_NODE_JOB_TRANSACTIONS, {
21
+ description: 'Number of transactions in a proven epoch',
22
+ valueType: ValueType.INT,
23
+ });
14
24
  }
15
25
 
16
- public recordProvingJob(timerOrMs: Timer | number) {
26
+ public recordProvingJob(timerOrMs: Timer | number, numBlocks: number, numTxs: number) {
17
27
  const ms = Math.ceil(typeof timerOrMs === 'number' ? timerOrMs : timerOrMs.ms());
18
28
  this.provingJobDuration.record(ms);
29
+ this.provingJobBlocks.record(Math.floor(numBlocks));
30
+ this.provingJobTransactions.record(Math.floor(numTxs));
19
31
  }
20
32
  }
@@ -3,20 +3,28 @@ import { type EthAddress } from '@aztec/circuits.js';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { RunningPromise } from '@aztec/foundation/running-promise';
5
5
  import { type L1Publisher } from '@aztec/sequencer-client';
6
+ import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
6
7
 
7
8
  export interface ClaimsMonitorHandler {
8
9
  handleClaim(proofClaim: EpochProofClaim): Promise<void>;
9
10
  }
10
11
 
11
- export class ClaimsMonitor {
12
+ export class ClaimsMonitor implements Traceable {
12
13
  private runningPromise: RunningPromise;
13
14
  private log = createLogger('prover-node:claims-monitor');
14
15
 
15
16
  private handler: ClaimsMonitorHandler | undefined;
16
17
  private lastClaimEpochNumber: bigint | undefined;
17
18
 
18
- constructor(private readonly l1Publisher: L1Publisher, private options: { pollingIntervalMs: number }) {
19
- this.runningPromise = new RunningPromise(this.work.bind(this), this.options.pollingIntervalMs);
19
+ public readonly tracer: Tracer;
20
+
21
+ constructor(
22
+ private readonly l1Publisher: L1Publisher,
23
+ telemetry: TelemetryClient,
24
+ private options: { pollingIntervalMs: number },
25
+ ) {
26
+ this.tracer = telemetry.getTracer('ClaimsMonitor');
27
+ this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.options.pollingIntervalMs);
20
28
  }
21
29
 
22
30
  public start(handler: ClaimsMonitorHandler) {
@@ -31,9 +39,11 @@ export class ClaimsMonitor {
31
39
  this.log.info('Stopped ClaimsMonitor');
32
40
  }
33
41
 
42
+ @trackSpan('ClaimsMonitor.work')
34
43
  public async work() {
35
44
  const proofClaim = await this.l1Publisher.getProofClaim();
36
45
  if (!proofClaim) {
46
+ this.log.trace(`Found no proof claim`);
37
47
  return;
38
48
  }
39
49
 
@@ -1,22 +1,29 @@
1
1
  import { type L2BlockSource } from '@aztec/circuit-types';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
3
  import { RunningPromise } from '@aztec/foundation/running-promise';
4
+ import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
4
5
 
5
6
  export interface EpochMonitorHandler {
6
7
  handleInitialEpochSync(epochNumber: bigint): Promise<void>;
7
8
  handleEpochCompleted(epochNumber: bigint): Promise<void>;
8
9
  }
9
10
 
10
- export class EpochMonitor {
11
+ export class EpochMonitor implements Traceable {
11
12
  private runningPromise: RunningPromise;
12
13
  private log = createLogger('prover-node:epoch-monitor');
14
+ public readonly tracer: Tracer;
13
15
 
14
16
  private handler: EpochMonitorHandler | undefined;
15
17
 
16
18
  private latestEpochNumber: bigint | undefined;
17
19
 
18
- constructor(private readonly l2BlockSource: L2BlockSource, private options: { pollingIntervalMs: number }) {
19
- this.runningPromise = new RunningPromise(this.work.bind(this), this.options.pollingIntervalMs);
20
+ constructor(
21
+ private readonly l2BlockSource: L2BlockSource,
22
+ telemetry: TelemetryClient,
23
+ private options: { pollingIntervalMs: number },
24
+ ) {
25
+ this.tracer = telemetry.getTracer('EpochMonitor');
26
+ this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.options.pollingIntervalMs);
20
27
  }
21
28
 
22
29
  public start(handler: EpochMonitorHandler) {
@@ -30,6 +37,7 @@ export class EpochMonitor {
30
37
  this.log.info('Stopped EpochMonitor');
31
38
  }
32
39
 
40
+ @trackSpan('EpochMonitor.work')
33
41
  public async work() {
34
42
  if (!this.latestEpochNumber) {
35
43
  const epochNumber = await this.l2BlockSource.getL2EpochNumber();
@@ -1,6 +1,12 @@
1
1
  import { type ArchiveSource, type Archiver } from '@aztec/archiver';
2
2
  import { BBCircuitVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
3
- import { type ProverCoordination, type WorldStateSynchronizer, createAztecNodeClient } from '@aztec/circuit-types';
3
+ import {
4
+ P2PClientType,
5
+ type ProverCoordination,
6
+ type WorldStateSynchronizer,
7
+ createAztecNodeClient,
8
+ } from '@aztec/circuit-types';
9
+ import { type EpochCache } from '@aztec/epoch-cache';
4
10
  import { createLogger } from '@aztec/foundation/log';
5
11
  import { type DataStoreConfig } from '@aztec/kv-store/config';
6
12
  import { createP2PClient } from '@aztec/p2p';
@@ -14,6 +20,7 @@ type ProverCoordinationDeps = {
14
20
  worldStateSynchronizer?: WorldStateSynchronizer;
15
21
  archiver?: Archiver | ArchiveSource;
16
22
  telemetry?: TelemetryClient;
23
+ epochCache?: EpochCache;
17
24
  };
18
25
 
19
26
  /**
@@ -36,16 +43,18 @@ export async function createProverCoordination(
36
43
  if (config.p2pEnabled) {
37
44
  log.info('Using prover coordination via p2p');
38
45
 
39
- if (!deps.archiver || !deps.worldStateSynchronizer || !deps.telemetry) {
46
+ if (!deps.archiver || !deps.worldStateSynchronizer || !deps.telemetry || !deps.epochCache) {
40
47
  throw new Error('Missing dependencies for p2p prover coordination');
41
48
  }
42
49
 
43
50
  const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
44
51
  const p2pClient = await createP2PClient(
52
+ P2PClientType.Prover,
45
53
  config,
46
54
  deps.archiver,
47
55
  proofVerifier,
48
56
  deps.worldStateSynchronizer,
57
+ deps.epochCache,
49
58
  deps.telemetry,
50
59
  );
51
60
  await p2pClient.start();
@@ -6,7 +6,7 @@ import {
6
6
  type L1ToL2MessageSource,
7
7
  type L2Block,
8
8
  type L2BlockSource,
9
- type ProverCache,
9
+ type P2PClientType,
10
10
  type ProverCoordination,
11
11
  type ProverNodeApi,
12
12
  type Service,
@@ -15,20 +15,19 @@ import {
15
15
  } from '@aztec/circuit-types';
16
16
  import { type ContractDataSource } from '@aztec/circuits.js';
17
17
  import { compact } from '@aztec/foundation/collection';
18
- import { sha256 } from '@aztec/foundation/crypto';
19
18
  import { createLogger } from '@aztec/foundation/log';
19
+ import { DateProvider } from '@aztec/foundation/timer';
20
20
  import { type Maybe } from '@aztec/foundation/types';
21
21
  import { type P2P } from '@aztec/p2p';
22
22
  import { type L1Publisher } from '@aztec/sequencer-client';
23
23
  import { PublicProcessorFactory } from '@aztec/simulator';
24
- import { type TelemetryClient } from '@aztec/telemetry-client';
24
+ import { Attributes, type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
25
25
 
26
26
  import { type BondManager } from './bond/bond-manager.js';
27
27
  import { EpochProvingJob, type EpochProvingJobState } from './job/epoch-proving-job.js';
28
28
  import { ProverNodeMetrics } from './metrics.js';
29
29
  import { type ClaimsMonitor, type ClaimsMonitorHandler } from './monitors/claims-monitor.js';
30
30
  import { type EpochMonitor, type EpochMonitorHandler } from './monitors/epoch-monitor.js';
31
- import { type ProverCacheManager } from './prover-cache/cache_manager.js';
32
31
  import { type QuoteProvider } from './quote-provider/index.js';
33
32
  import { type QuoteSigner } from './quote-signer.js';
34
33
 
@@ -44,14 +43,17 @@ export type ProverNodeOptions = {
44
43
  * from a tx source in the p2p network or an external node, re-executes their public functions, creates a rollup
45
44
  * proof for the epoch, and submits it to L1.
46
45
  */
47
- export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, ProverNodeApi {
46
+ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, ProverNodeApi, Traceable {
48
47
  private log = createLogger('prover-node');
48
+ private dateProvider = new DateProvider();
49
49
 
50
50
  private latestEpochWeAreProving: bigint | undefined;
51
51
  private jobs: Map<string, EpochProvingJob> = new Map();
52
52
  private options: ProverNodeOptions;
53
53
  private metrics: ProverNodeMetrics;
54
54
 
55
+ public readonly tracer: Tracer;
56
+
55
57
  constructor(
56
58
  private readonly prover: EpochProverManager,
57
59
  private readonly publisher: L1Publisher,
@@ -66,7 +68,6 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr
66
68
  private readonly epochsMonitor: EpochMonitor,
67
69
  private readonly bondManager: BondManager,
68
70
  private readonly telemetryClient: TelemetryClient,
69
- private readonly proverCacheManager: ProverCacheManager,
70
71
  options: Partial<ProverNodeOptions> = {},
71
72
  ) {
72
73
  this.options = {
@@ -77,10 +78,11 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr
77
78
  };
78
79
 
79
80
  this.metrics = new ProverNodeMetrics(telemetryClient, 'ProverNode');
81
+ this.tracer = telemetryClient.getTracer('ProverNode');
80
82
  }
81
83
 
82
84
  public getP2P() {
83
- const asP2PClient = this.coordination as P2P;
85
+ const asP2PClient = this.coordination as P2P<P2PClientType.Prover>;
84
86
  if (typeof asP2PClient.isP2PClient === 'function' && asP2PClient.isP2PClient()) {
85
87
  return asP2PClient;
86
88
  }
@@ -93,6 +95,12 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr
93
95
  return;
94
96
  }
95
97
 
98
+ const provenEpoch = await this.l2BlockSource.getProvenL2EpochNumber();
99
+ if (provenEpoch !== undefined && proofClaim.epochToProve <= provenEpoch) {
100
+ this.log.verbose(`Claim for epoch ${proofClaim.epochToProve} is already proven`);
101
+ return;
102
+ }
103
+
96
104
  try {
97
105
  await this.startProof(proofClaim.epochToProve);
98
106
  this.latestEpochWeAreProving = proofClaim.epochToProve;
@@ -117,12 +125,8 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr
117
125
  try {
118
126
  const claim = await this.publisher.getProofClaim();
119
127
  if (!claim || claim.epochToProve < epochNumber) {
128
+ this.log.verbose(`Handling epoch ${epochNumber} completed as initial sync`);
120
129
  await this.handleEpochCompleted(epochNumber);
121
- } else if (claim && claim.bondProvider.equals(this.publisher.getSenderAddress())) {
122
- const lastEpochProven = await this.l2BlockSource.getProvenL2EpochNumber();
123
- if (lastEpochProven === undefined || lastEpochProven < claim.epochToProve) {
124
- await this.handleClaim(claim);
125
- }
126
130
  }
127
131
  } catch (err) {
128
132
  this.log.error(`Error handling initial epoch sync`, err);
@@ -245,6 +249,7 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr
245
249
  return maxPendingJobs === 0 || this.jobs.size < maxPendingJobs;
246
250
  }
247
251
 
252
+ @trackSpan('ProverNode.createProvingJob', epochNumber => ({ [Attributes.EPOCH_NUMBER]: Number(epochNumber) }))
248
253
  private async createProvingJob(epochNumber: bigint) {
249
254
  if (!this.checkMaximumPendingJobs()) {
250
255
  throw new Error(`Maximum pending proving jobs ${this.options.maxPendingJobs} reached. Cannot create new job.`);
@@ -263,18 +268,18 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr
263
268
  await this.worldState.syncImmediate(fromBlock - 1);
264
269
 
265
270
  // Create a processor using the forked world state
266
- const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, this.telemetryClient);
267
-
268
- const epochHash = sha256(Buffer.concat(blocks.map(block => block.hash().toBuffer())));
269
- const proverCache = await this.proverCacheManager.openCache(epochNumber, epochHash);
271
+ const publicProcessorFactory = new PublicProcessorFactory(
272
+ this.contractDataSource,
273
+ this.dateProvider,
274
+ this.telemetryClient,
275
+ );
270
276
 
271
- const cleanUp = async () => {
272
- await proverCache.close();
273
- await this.proverCacheManager.removeStaleCaches(epochNumber);
277
+ const cleanUp = () => {
274
278
  this.jobs.delete(job.getId());
279
+ return Promise.resolve();
275
280
  };
276
281
 
277
- const job = this.doCreateEpochProvingJob(epochNumber, blocks, proverCache, publicProcessorFactory, cleanUp);
282
+ const job = this.doCreateEpochProvingJob(epochNumber, blocks, publicProcessorFactory, cleanUp);
278
283
  this.jobs.set(job.getId(), job);
279
284
  return job;
280
285
  }
@@ -283,7 +288,6 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr
283
288
  protected doCreateEpochProvingJob(
284
289
  epochNumber: bigint,
285
290
  blocks: L2Block[],
286
- proverCache: ProverCache,
287
291
  publicProcessorFactory: PublicProcessorFactory,
288
292
  cleanUp: () => Promise<void>,
289
293
  ) {
@@ -291,7 +295,7 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr
291
295
  this.worldState,
292
296
  epochNumber,
293
297
  blocks,
294
- this.prover.createEpochProver(proverCache),
298
+ this.prover.createEpochProver(),
295
299
  publicProcessorFactory,
296
300
  this.publisher,
297
301
  this.l2BlockSource,
@@ -1,15 +0,0 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
- import { type ProverCache } from '@aztec/circuit-types';
4
- export declare class ProverCacheManager {
5
- private cacheDir?;
6
- private log;
7
- constructor(cacheDir?: string | undefined, log?: import("@aztec/foundation/log").Logger);
8
- openCache(epochNumber: bigint, epochHash: Buffer): Promise<ProverCache>;
9
- /**
10
- * Removes all caches for epochs older than the given epoch (including)
11
- * @param upToAndIncludingEpoch - The epoch number up to which to remove caches
12
- */
13
- removeStaleCaches(upToAndIncludingEpoch: bigint): Promise<void>;
14
- }
15
- //# sourceMappingURL=cache_manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache_manager.d.ts","sourceRoot":"","sources":["../../src/prover-cache/cache_manager.ts"],"names":[],"mappings":";;AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAexD,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC;IAAU,OAAO,CAAC,GAAG;gBAA9B,QAAQ,CAAC,oBAAQ,EAAU,GAAG,yCAA4C;IAEjF,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAsBpF;;;OAGG;IACU,iBAAiB,CAAC,qBAAqB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAwB7E"}
@@ -1,57 +0,0 @@
1
- import { createLogger } from '@aztec/foundation/log';
2
- import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
3
- import { InMemoryProverCache } from '@aztec/prover-client';
4
- import { mkdir, readFile, readdir, rm, writeFile } from 'fs/promises';
5
- import { join } from 'path';
6
- import { KVProverCache } from './kv_cache.js';
7
- const EPOCH_DIR_PREFIX = 'epoch';
8
- const EPOCH_DIR_SEPARATOR = '_';
9
- const EPOCH_HASH_FILENAME = 'epoch_hash.txt';
10
- export class ProverCacheManager {
11
- constructor(cacheDir, log = createLogger('prover-node:cache-manager')) {
12
- this.cacheDir = cacheDir;
13
- this.log = log;
14
- }
15
- async openCache(epochNumber, epochHash) {
16
- if (!this.cacheDir) {
17
- return new InMemoryProverCache();
18
- }
19
- const epochDir = EPOCH_DIR_PREFIX + EPOCH_DIR_SEPARATOR + epochNumber;
20
- const dataDir = join(this.cacheDir, epochDir);
21
- const storedEpochHash = await readFile(join(dataDir, EPOCH_HASH_FILENAME), 'hex').catch(() => Buffer.alloc(0));
22
- if (storedEpochHash.toString() !== epochHash.toString()) {
23
- await rm(dataDir, { recursive: true, force: true });
24
- }
25
- await mkdir(dataDir, { recursive: true });
26
- await writeFile(join(dataDir, EPOCH_HASH_FILENAME), epochHash.toString('hex'));
27
- const store = AztecLmdbStore.open(dataDir);
28
- this.log.debug(`Created new database for epoch ${epochNumber} at ${dataDir}`);
29
- const cleanup = () => store.close();
30
- return new KVProverCache(store, cleanup);
31
- }
32
- /**
33
- * Removes all caches for epochs older than the given epoch (including)
34
- * @param upToAndIncludingEpoch - The epoch number up to which to remove caches
35
- */
36
- async removeStaleCaches(upToAndIncludingEpoch) {
37
- if (!this.cacheDir) {
38
- return;
39
- }
40
- const entries = await readdir(this.cacheDir, { withFileTypes: true }).catch(() => []);
41
- for (const item of entries) {
42
- if (!item.isDirectory()) {
43
- continue;
44
- }
45
- const [prefix, epochNumber] = item.name.split(EPOCH_DIR_SEPARATOR);
46
- if (prefix !== EPOCH_DIR_PREFIX) {
47
- continue;
48
- }
49
- const epochNumberInt = BigInt(epochNumber);
50
- if (epochNumberInt <= upToAndIncludingEpoch) {
51
- this.log.info(`Removing old epoch database for epoch ${epochNumberInt} at ${join(this.cacheDir, item.name)}`);
52
- await rm(join(this.cacheDir, item.name), { recursive: true });
53
- }
54
- }
55
- }
56
- }
57
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGVfbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm92ZXItY2FjaGUvY2FjaGVfbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDckQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRzNELE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFNUIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU5QyxNQUFNLGdCQUFnQixHQUFHLE9BQU8sQ0FBQztBQUNqQyxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLGdCQUFnQixDQUFDO0FBRTdDLE1BQU0sT0FBTyxrQkFBa0I7SUFDN0IsWUFBb0IsUUFBaUIsRUFBVSxNQUFNLFlBQVksQ0FBQywyQkFBMkIsQ0FBQztRQUExRSxhQUFRLEdBQVIsUUFBUSxDQUFTO1FBQVUsUUFBRyxHQUFILEdBQUcsQ0FBNEM7SUFBRyxDQUFDO0lBRTNGLEtBQUssQ0FBQyxTQUFTLENBQUMsV0FBbUIsRUFBRSxTQUFpQjtRQUMzRCxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ25CLE9BQU8sSUFBSSxtQkFBbUIsRUFBRSxDQUFDO1FBQ25DLENBQUM7UUFFRCxNQUFNLFFBQVEsR0FBRyxnQkFBZ0IsR0FBRyxtQkFBbUIsR0FBRyxXQUFXLENBQUM7UUFDdEUsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsUUFBUSxD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
@@ -1,11 +0,0 @@
1
- import type { ProverCache, ProvingJobStatus } from '@aztec/circuit-types';
2
- import type { AztecKVStore } from '@aztec/kv-store';
3
- export declare class KVProverCache implements ProverCache {
4
- private cleanup?;
5
- private proofs;
6
- constructor(store: AztecKVStore, cleanup?: (() => Promise<void>) | undefined);
7
- getProvingJobStatus(jobId: string): Promise<ProvingJobStatus>;
8
- setProvingJobStatus(jobId: string, status: ProvingJobStatus): Promise<void>;
9
- close(): Promise<void>;
10
- }
11
- //# sourceMappingURL=kv_cache.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"kv_cache.d.ts","sourceRoot":"","sources":["../../src/prover-cache/kv_cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,iBAAiB,CAAC;AAE9D,qBAAa,aAAc,YAAW,WAAW;IAGd,OAAO,CAAC,OAAO,CAAC;IAFjD,OAAO,CAAC,MAAM,CAA2B;gBAE7B,KAAK,EAAE,YAAY,EAAU,OAAO,CAAC,SAAQ,QAAQ,IAAI,CAAC,aAAA;IAItE,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAS7D,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -1,20 +0,0 @@
1
- export class KVProverCache {
2
- constructor(store, cleanup) {
3
- this.cleanup = cleanup;
4
- this.proofs = store.openMap('prover_node_proof_status');
5
- }
6
- getProvingJobStatus(jobId) {
7
- const item = this.proofs.get(jobId);
8
- if (!item) {
9
- return Promise.resolve({ status: 'not-found' });
10
- }
11
- return Promise.resolve(JSON.parse(item));
12
- }
13
- setProvingJobStatus(jobId, status) {
14
- return this.proofs.set(jobId, JSON.stringify(status));
15
- }
16
- async close() {
17
- await this.cleanup?.();
18
- }
19
- }
20
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia3ZfY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJvdmVyLWNhY2hlL2t2X2NhY2hlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLE1BQU0sT0FBTyxhQUFhO0lBR3hCLFlBQVksS0FBbUIsRUFBVSxPQUE2QjtRQUE3QixZQUFPLEdBQVAsT0FBTyxDQUFzQjtRQUNwRSxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsMEJBQTBCLENBQUMsQ0FBQztJQUMxRCxDQUFDO0lBRUQsbUJBQW1CLENBQUMsS0FBYTtRQUMvQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNwQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDVixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQztRQUNsRCxDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBRUQsbUJBQW1CLENBQUMsS0FBYSxFQUFFLE1BQXdCO1FBQ3pELE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUs7UUFDVCxNQUFNLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO0lBQ3pCLENBQUM7Q0FDRiJ9