@aztec/prover-node 0.85.0 → 0.86.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dest/config.d.ts +2 -2
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +8 -8
  4. package/dest/factory.d.ts +3 -2
  5. package/dest/factory.d.ts.map +1 -1
  6. package/dest/factory.js +9 -9
  7. package/dest/job/epoch-proving-job.d.ts +2 -2
  8. package/dest/job/epoch-proving-job.d.ts.map +1 -1
  9. package/dest/job/epoch-proving-job.js +1 -1
  10. package/dest/metrics.d.ts +27 -4
  11. package/dest/metrics.d.ts.map +1 -1
  12. package/dest/metrics.js +104 -36
  13. package/dest/monitors/epoch-monitor.d.ts +1 -1
  14. package/dest/monitors/epoch-monitor.d.ts.map +1 -1
  15. package/dest/monitors/epoch-monitor.js +7 -2
  16. package/dest/prover-coordination/combined-prover-coordination.d.ts +22 -0
  17. package/dest/prover-coordination/combined-prover-coordination.d.ts.map +1 -0
  18. package/dest/prover-coordination/combined-prover-coordination.js +136 -0
  19. package/dest/prover-coordination/config.d.ts +1 -1
  20. package/dest/prover-coordination/config.d.ts.map +1 -1
  21. package/dest/prover-coordination/config.js +4 -4
  22. package/dest/prover-coordination/factory.d.ts +5 -4
  23. package/dest/prover-coordination/factory.d.ts.map +1 -1
  24. package/dest/prover-coordination/factory.js +20 -14
  25. package/dest/prover-node-publisher.d.ts +1 -2
  26. package/dest/prover-node-publisher.d.ts.map +1 -1
  27. package/dest/prover-node-publisher.js +7 -13
  28. package/dest/prover-node.d.ts +8 -10
  29. package/dest/prover-node.d.ts.map +1 -1
  30. package/dest/prover-node.js +21 -17
  31. package/package.json +20 -22
  32. package/src/config.ts +10 -10
  33. package/src/factory.ts +10 -10
  34. package/src/job/epoch-proving-job.ts +3 -3
  35. package/src/metrics.ts +111 -38
  36. package/src/monitors/epoch-monitor.ts +5 -3
  37. package/src/prover-coordination/combined-prover-coordination.ts +160 -0
  38. package/src/prover-coordination/config.ts +5 -5
  39. package/src/prover-coordination/factory.ts +36 -25
  40. package/src/prover-node-publisher.ts +9 -18
  41. package/src/prover-node.ts +35 -25
@@ -6,21 +6,26 @@ import type { DataStoreConfig } from '@aztec/kv-store/config';
6
6
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
7
7
  import { createP2PClient } from '@aztec/p2p';
8
8
  import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
9
- import { createAztecNodeClient } from '@aztec/stdlib/interfaces/client';
9
+ import { type AztecNode, createAztecNodeClient } from '@aztec/stdlib/interfaces/client';
10
10
  import type { ProverCoordination, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
11
11
  import { P2PClientType } from '@aztec/stdlib/p2p';
12
12
  import { getComponentsVersionsFromConfig } from '@aztec/stdlib/versioning';
13
13
  import { type TelemetryClient, makeTracedFetch } from '@aztec/telemetry-client';
14
14
 
15
15
  import type { ProverNodeConfig } from '../config.js';
16
+ import {
17
+ type CombinedCoordinationOptions,
18
+ CombinedProverCoordination,
19
+ type TxSource,
20
+ } from './combined-prover-coordination.js';
16
21
 
17
22
  // We return a reference to the P2P client so that the prover node can stop the service when it shuts down.
18
23
  type ProverCoordinationDeps = {
19
- aztecNodeTxProvider?: ProverCoordination;
20
- worldStateSynchronizer?: WorldStateSynchronizer;
21
- archiver?: Archiver | ArchiveSource;
24
+ aztecNodeTxProvider?: TxSource;
25
+ worldStateSynchronizer: WorldStateSynchronizer;
26
+ archiver: Archiver | ArchiveSource;
22
27
  telemetry?: TelemetryClient;
23
- epochCache?: EpochCache;
28
+ epochCache: EpochCache;
24
29
  };
25
30
 
26
31
  /**
@@ -35,9 +40,14 @@ export async function createProverCoordination(
35
40
  ): Promise<ProverCoordination> {
36
41
  const log = createLogger('prover-node:prover-coordination');
37
42
 
43
+ const coordinationConfig: CombinedCoordinationOptions = {
44
+ txGatheringBatchSize: config.txGatheringBatchSize ?? 10,
45
+ txGatheringMaxParallelRequestsPerNode: config.txGatheringMaxParallelRequestsPerNode ?? 10,
46
+ };
47
+
38
48
  if (deps.aztecNodeTxProvider) {
39
49
  log.info('Using prover coordination via aztec node');
40
- return deps.aztecNodeTxProvider;
50
+ return new CombinedProverCoordination(undefined, [deps.aztecNodeTxProvider!], coordinationConfig);
41
51
  }
42
52
 
43
53
  if (config.p2pEnabled) {
@@ -46,27 +56,28 @@ export async function createProverCoordination(
46
56
  if (!deps.archiver || !deps.worldStateSynchronizer || !deps.telemetry || !deps.epochCache) {
47
57
  throw new Error('Missing dependencies for p2p prover coordination');
48
58
  }
49
-
50
- const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
51
- const p2pClient = await createP2PClient(
52
- P2PClientType.Prover,
53
- config,
54
- deps.archiver,
55
- proofVerifier,
56
- deps.worldStateSynchronizer,
57
- deps.epochCache,
58
- deps.telemetry,
59
- );
60
- await p2pClient.start();
61
-
62
- return p2pClient;
63
59
  }
64
60
 
65
- if (config.proverCoordinationNodeUrl) {
66
- log.info('Using prover coordination via node url');
61
+ let nodes: AztecNode[] = [];
62
+ if (config.proverCoordinationNodeUrls.length > 0) {
63
+ log.info('Using prover coordination via node urls');
67
64
  const versions = getComponentsVersionsFromConfig(config, protocolContractTreeRoot, getVKTreeRoot());
68
- return createAztecNodeClient(config.proverCoordinationNodeUrl, versions, makeTracedFetch([1, 2, 3], false));
69
- } else {
70
- throw new Error(`Aztec Node URL for Tx Provider is not set.`);
65
+ nodes = config.proverCoordinationNodeUrls.map(url =>
66
+ createAztecNodeClient(url, versions, makeTracedFetch([1, 2, 3], false)),
67
+ );
71
68
  }
69
+
70
+ const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
71
+ const p2pClient = await createP2PClient(
72
+ P2PClientType.Prover,
73
+ config,
74
+ deps.archiver,
75
+ proofVerifier,
76
+ deps.worldStateSynchronizer,
77
+ deps.epochCache,
78
+ deps.telemetry,
79
+ );
80
+ await p2pClient.start();
81
+
82
+ return new CombinedProverCoordination(p2pClient, nodes, coordinationConfig);
72
83
  }
@@ -17,7 +17,7 @@ import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-clien
17
17
 
18
18
  import { type Hex, type TransactionReceipt, encodeFunctionData } from 'viem';
19
19
 
20
- import { ProverNodeMetrics } from './metrics.js';
20
+ import { ProverNodePublisherMetrics } from './metrics.js';
21
21
 
22
22
  /**
23
23
  * Stats for a sent transaction.
@@ -27,8 +27,6 @@ export type L1SubmitEpochProofArgs = {
27
27
  epochSize: number;
28
28
  previousArchive: Fr;
29
29
  endArchive: Fr;
30
- previousBlockHash: Fr;
31
- endBlockHash: Fr;
32
30
  endTimestamp: Fr;
33
31
  outHash: Fr;
34
32
  proverId: Fr;
@@ -40,7 +38,7 @@ export class ProverNodePublisher {
40
38
  private interruptibleSleep = new InterruptibleSleep();
41
39
  private sleepTimeMs: number;
42
40
  private interrupted = false;
43
- private metrics: ProverNodeMetrics;
41
+ private metrics: ProverNodePublisherMetrics;
44
42
 
45
43
  protected log = createLogger('prover-node:l1-tx-publisher');
46
44
 
@@ -60,12 +58,16 @@ export class ProverNodePublisher {
60
58
 
61
59
  const telemetry = deps.telemetry ?? getTelemetryClient();
62
60
 
63
- this.metrics = new ProverNodeMetrics(telemetry, 'ProverNode');
61
+ this.metrics = new ProverNodePublisherMetrics(telemetry, 'ProverNode');
64
62
 
65
63
  this.rollupContract = deps.rollupContract;
66
64
  this.l1TxUtils = deps.l1TxUtils;
67
65
  }
68
66
 
67
+ public getRollupContract() {
68
+ return this.rollupContract;
69
+ }
70
+
69
71
  /**
70
72
  * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
71
73
  * Be warned, the call may return false even if the tx subsequently gets successfully mined.
@@ -158,30 +160,21 @@ export class ProverNodePublisher {
158
160
  throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as pending block is ${pending}`);
159
161
  }
160
162
 
161
- // Check the block hash and archive for the immediate block before the epoch
163
+ // Check the archive for the immediate block before the epoch
162
164
  const blockLog = await this.rollupContract.getBlock(BigInt(fromBlock - 1));
163
165
  if (publicInputs.previousArchive.root.toString() !== blockLog.archive) {
164
166
  throw new Error(
165
167
  `Previous archive root mismatch: ${publicInputs.previousArchive.root.toString()} !== ${blockLog.archive}`,
166
168
  );
167
169
  }
168
- // TODO: Remove zero check once we inject the proper zero blockhash
169
- if (blockLog.blockHash !== Fr.ZERO.toString() && publicInputs.previousBlockHash.toString() !== blockLog.blockHash) {
170
- throw new Error(
171
- `Previous block hash mismatch: ${publicInputs.previousBlockHash.toString()} !== ${blockLog.blockHash}`,
172
- );
173
- }
174
170
 
175
- // Check the block hash and archive for the last block in the epoch
171
+ // Check the archive for the last block in the epoch
176
172
  const endBlockLog = await this.rollupContract.getBlock(BigInt(toBlock));
177
173
  if (publicInputs.endArchive.root.toString() !== endBlockLog.archive) {
178
174
  throw new Error(
179
175
  `End archive root mismatch: ${publicInputs.endArchive.root.toString()} !== ${endBlockLog.archive}`,
180
176
  );
181
177
  }
182
- if (publicInputs.endBlockHash.toString() !== endBlockLog.blockHash) {
183
- throw new Error(`End block hash mismatch: ${publicInputs.endBlockHash.toString()} !== ${endBlockLog.blockHash}`);
184
- }
185
178
 
186
179
  // Compare the public inputs computed by the contract with the ones injected
187
180
  const rollupPublicInputs = await this.rollupContract.getEpochProofPublicInputs(this.getSubmitEpochProofArgs(args));
@@ -258,8 +251,6 @@ export class ProverNodePublisher {
258
251
  {
259
252
  previousArchive: args.publicInputs.previousArchive.root.toString(),
260
253
  endArchive: args.publicInputs.endArchive.root.toString(),
261
- previousBlockHash: args.publicInputs.previousBlockHash.toString(),
262
- endBlockHash: args.publicInputs.endBlockHash.toString(),
263
254
  endTimestamp: args.publicInputs.endTimestamp.toBigInt(),
264
255
  outHash: args.publicInputs.outHash.toString(),
265
256
  proverId: EthAddress.fromField(args.publicInputs.proverId).toString(),
@@ -1,10 +1,11 @@
1
+ import type { ViemPublicClient } from '@aztec/ethereum';
1
2
  import { compact } from '@aztec/foundation/collection';
2
3
  import { memoize } from '@aztec/foundation/decorators';
4
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
5
  import { createLogger } from '@aztec/foundation/log';
4
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
5
7
  import { DateProvider } from '@aztec/foundation/timer';
6
8
  import type { Maybe } from '@aztec/foundation/types';
7
- import type { P2P } from '@aztec/p2p';
8
9
  import { PublicProcessorFactory } from '@aztec/simulator/server';
9
10
  import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
10
11
  import type { ContractDataSource } from '@aztec/stdlib/contract';
@@ -20,7 +21,6 @@ import {
20
21
  tryStop,
21
22
  } from '@aztec/stdlib/interfaces/server';
22
23
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
23
- import type { P2PClientType } from '@aztec/stdlib/p2p';
24
24
  import type { Tx, TxHash } from '@aztec/stdlib/tx';
25
25
  import {
26
26
  Attributes,
@@ -33,7 +33,7 @@ import {
33
33
  } from '@aztec/telemetry-client';
34
34
 
35
35
  import { EpochProvingJob, type EpochProvingJobState } from './job/epoch-proving-job.js';
36
- import { ProverNodeMetrics } from './metrics.js';
36
+ import { ProverNodeJobMetrics, ProverNodeRewardsMetrics } from './metrics.js';
37
37
  import type { EpochMonitor, EpochMonitorHandler } from './monitors/epoch-monitor.js';
38
38
  import type { ProverNodePublisher } from './prover-node-publisher.js';
39
39
 
@@ -41,9 +41,7 @@ export type ProverNodeOptions = {
41
41
  pollingIntervalMs: number;
42
42
  maxPendingJobs: number;
43
43
  maxParallelBlocksPerEpoch: number;
44
- txGatheringTimeoutMs: number;
45
44
  txGatheringIntervalMs: number;
46
- txGatheringMaxParallelRequests: number;
47
45
  };
48
46
 
49
47
  /**
@@ -58,7 +56,8 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
58
56
 
59
57
  private jobs: Map<string, EpochProvingJob> = new Map();
60
58
  private options: ProverNodeOptions;
61
- private metrics: ProverNodeMetrics;
59
+ private jobMetrics: ProverNodeJobMetrics;
60
+ private rewardsMetrics: ProverNodeRewardsMetrics;
62
61
  private l1Metrics: L1Metrics;
63
62
 
64
63
  private txFetcher: RunningPromise;
@@ -73,27 +72,36 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
73
72
  protected readonly l1ToL2MessageSource: L1ToL2MessageSource,
74
73
  protected readonly contractDataSource: ContractDataSource,
75
74
  protected readonly worldState: WorldStateSynchronizer,
76
- protected readonly coordination: ProverCoordination & Maybe<Service>,
75
+ protected readonly coordination: ProverCoordination,
77
76
  protected readonly epochsMonitor: EpochMonitor,
78
77
  options: Partial<ProverNodeOptions> = {},
79
78
  protected readonly telemetryClient: TelemetryClient = getTelemetryClient(),
80
79
  ) {
81
- this.l1Metrics = new L1Metrics(telemetryClient.getMeter('ProverNodeL1Metrics'), publisher.l1TxUtils.publicClient, [
82
- publisher.getSenderAddress(),
83
- ]);
80
+ this.l1Metrics = new L1Metrics(
81
+ telemetryClient.getMeter('ProverNodeL1Metrics'),
82
+ publisher.l1TxUtils.client as unknown as ViemPublicClient,
83
+ [publisher.getSenderAddress()],
84
+ );
84
85
 
85
86
  this.options = {
86
87
  pollingIntervalMs: 1_000,
87
88
  maxPendingJobs: 100,
88
89
  maxParallelBlocksPerEpoch: 32,
89
- txGatheringTimeoutMs: 60_000,
90
90
  txGatheringIntervalMs: 1_000,
91
- txGatheringMaxParallelRequests: 100,
92
91
  ...compact(options),
93
92
  };
94
93
 
95
- this.metrics = new ProverNodeMetrics(telemetryClient, 'ProverNode');
94
+ const meter = telemetryClient.getMeter('ProverNode');
96
95
  this.tracer = telemetryClient.getTracer('ProverNode');
96
+
97
+ this.jobMetrics = new ProverNodeJobMetrics(meter, telemetryClient.getTracer('EpochProvingJob'));
98
+
99
+ this.rewardsMetrics = new ProverNodeRewardsMetrics(
100
+ meter,
101
+ EthAddress.fromField(this.prover.getProverId()),
102
+ this.publisher.getRollupContract(),
103
+ );
104
+
97
105
  this.txFetcher = new RunningPromise(() => this.checkForTxs(), this.log, this.options.txGatheringIntervalMs);
98
106
  }
99
107
 
@@ -102,18 +110,15 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
102
110
  }
103
111
 
104
112
  public getP2P() {
105
- const asP2PClient = this.coordination as P2P<P2PClientType.Prover>;
106
- if (typeof asP2PClient.isP2PClient === 'function' && asP2PClient.isP2PClient()) {
107
- return asP2PClient;
108
- }
109
- return undefined;
113
+ return this.coordination.getP2PClient();
110
114
  }
111
115
 
112
116
  /**
113
117
  * Handles an epoch being completed by starting a proof for it if there are no active jobs for it.
114
118
  * @param epochNumber - The epoch number that was just completed.
119
+ * @returns false if there is an error, true otherwise
115
120
  */
116
- async handleEpochReadyToProve(epochNumber: bigint): Promise<void> {
121
+ async handleEpochReadyToProve(epochNumber: bigint): Promise<boolean> {
117
122
  try {
118
123
  this.log.debug(`Running jobs as ${epochNumber} is ready to prove`, {
119
124
  jobs: Array.from(this.jobs.values()).map(job => `${job.getEpochNumber()}:${job.getId()}`),
@@ -123,15 +128,17 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
123
128
  this.log.warn(`Not starting proof for ${epochNumber} since there are active jobs for the epoch`, {
124
129
  activeJobs: activeJobs.map(job => job.uuid),
125
130
  });
126
- return;
131
+ return true;
127
132
  }
128
133
  await this.startProof(epochNumber);
134
+ return true;
129
135
  } catch (err) {
130
136
  if (err instanceof EmptyEpochError) {
131
137
  this.log.info(`Not starting proof for ${epochNumber} since no blocks were found`);
132
138
  } else {
133
139
  this.log.error(`Error handling epoch completed`, err);
134
140
  }
141
+ return false;
135
142
  }
136
143
  }
137
144
 
@@ -139,10 +146,11 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
139
146
  * Starts the prover node so it periodically checks for unproven epochs in the unfinalised chain from L1 and
140
147
  * starts proving jobs for them.
141
148
  */
142
- start() {
149
+ async start() {
143
150
  this.txFetcher.start();
144
151
  this.epochsMonitor.start(this);
145
152
  this.l1Metrics.start();
153
+ await this.rewardsMetrics.start();
146
154
  this.log.info(`Started Prover Node with prover id ${this.prover.getProverId().toString()}`, this.options);
147
155
  }
148
156
 
@@ -160,13 +168,15 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
160
168
  await this.worldState.stop();
161
169
  await tryStop(this.coordination);
162
170
  this.l1Metrics.stop();
171
+ this.rewardsMetrics.stop();
163
172
  await this.telemetryClient.stop();
164
173
  this.log.info('Stopped ProverNode');
165
174
  }
166
175
 
167
176
  /** Returns world state status. */
168
- public getWorldStateSyncStatus(): Promise<WorldStateSyncStatus> {
169
- return this.worldState.status().then(s => s.syncSummary);
177
+ public async getWorldStateSyncStatus(): Promise<WorldStateSyncStatus> {
178
+ const { syncSummary } = await this.worldState.status();
179
+ return syncSummary;
170
180
  }
171
181
 
172
182
  /** Returns archiver status. */
@@ -279,7 +289,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
279
289
  }
280
290
  const txHashes = block.body.txEffects.map(tx => tx.txHash);
281
291
  this.log.verbose(`Fetching ${txHashes.length} tx hashes for block number ${blockNumber} from coordination`);
282
- await this.coordination.getTxsByHash(txHashes); // This stores the txs in the tx pool, no need to persist them here
292
+ await this.coordination.gatherTxs(txHashes); // This stores the txs in the tx pool, no need to persist them here
283
293
  this.lastBlockNumber = blockNumber;
284
294
  }
285
295
  }
@@ -336,7 +346,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
336
346
  this.publisher,
337
347
  this.l2BlockSource,
338
348
  this.l1ToL2MessageSource,
339
- this.metrics,
349
+ this.jobMetrics,
340
350
  deadline,
341
351
  { parallelBlockLimit: this.options.maxParallelBlocksPerEpoch },
342
352
  );