@aztec/prover-node 0.56.0 → 0.58.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 (102) hide show
  1. package/dest/bond/bond-manager.d.ts +22 -0
  2. package/dest/bond/bond-manager.d.ts.map +1 -0
  3. package/dest/bond/bond-manager.js +42 -0
  4. package/dest/bond/config.d.ts +8 -0
  5. package/dest/bond/config.d.ts.map +1 -0
  6. package/dest/bond/config.js +17 -0
  7. package/dest/bond/escrow-contract.d.ts +22 -0
  8. package/dest/bond/escrow-contract.d.ts.map +1 -0
  9. package/dest/bond/escrow-contract.js +32 -0
  10. package/dest/bond/factory.d.ts +9 -0
  11. package/dest/bond/factory.d.ts.map +1 -0
  12. package/dest/bond/factory.js +19 -0
  13. package/dest/bond/index.d.ts +3 -0
  14. package/dest/bond/index.d.ts.map +1 -0
  15. package/dest/bond/index.js +3 -0
  16. package/dest/bond/token-contract.d.ts +29 -0
  17. package/dest/bond/token-contract.d.ts.map +1 -0
  18. package/dest/bond/token-contract.js +58 -0
  19. package/dest/config.d.ts +10 -4
  20. package/dest/config.d.ts.map +1 -1
  21. package/dest/config.js +30 -9
  22. package/dest/factory.d.ts.map +1 -1
  23. package/dest/factory.js +39 -9
  24. package/dest/job/epoch-proving-job.d.ts +39 -0
  25. package/dest/job/epoch-proving-job.d.ts.map +1 -0
  26. package/dest/job/epoch-proving-job.js +127 -0
  27. package/dest/monitors/claims-monitor.d.ts +22 -0
  28. package/dest/monitors/claims-monitor.d.ts.map +1 -0
  29. package/dest/monitors/claims-monitor.js +37 -0
  30. package/dest/monitors/epoch-monitor.d.ts +20 -0
  31. package/dest/monitors/epoch-monitor.d.ts.map +1 -0
  32. package/dest/monitors/epoch-monitor.js +34 -0
  33. package/dest/monitors/index.d.ts +3 -0
  34. package/dest/monitors/index.d.ts.map +1 -0
  35. package/dest/monitors/index.js +3 -0
  36. package/dest/prover-coordination/config.d.ts +7 -0
  37. package/dest/prover-coordination/config.d.ts.map +1 -0
  38. package/dest/prover-coordination/config.js +12 -0
  39. package/dest/prover-coordination/factory.d.ts +4 -0
  40. package/dest/prover-coordination/factory.d.ts.map +1 -0
  41. package/dest/prover-coordination/factory.js +10 -0
  42. package/dest/prover-coordination/index.d.ts +3 -0
  43. package/dest/prover-coordination/index.d.ts.map +1 -0
  44. package/dest/prover-coordination/index.js +3 -0
  45. package/dest/prover-node.d.ts +57 -33
  46. package/dest/prover-node.d.ts.map +1 -1
  47. package/dest/prover-node.js +128 -76
  48. package/dest/quote-provider/http.d.ts +15 -0
  49. package/dest/quote-provider/http.d.ts.map +1 -0
  50. package/dest/quote-provider/http.js +32 -0
  51. package/dest/quote-provider/index.d.ts +6 -0
  52. package/dest/quote-provider/index.d.ts.map +1 -0
  53. package/dest/quote-provider/index.js +2 -0
  54. package/dest/quote-provider/simple.d.ts +9 -0
  55. package/dest/quote-provider/simple.d.ts.map +1 -0
  56. package/dest/quote-provider/simple.js +11 -0
  57. package/dest/quote-provider/utils.d.ts +4 -0
  58. package/dest/quote-provider/utils.d.ts.map +1 -0
  59. package/dest/quote-provider/utils.js +8 -0
  60. package/dest/quote-signer.d.ts +13 -0
  61. package/dest/quote-signer.d.ts.map +1 -0
  62. package/dest/quote-signer.js +18 -0
  63. package/package.json +19 -13
  64. package/src/bond/bond-manager.ts +48 -0
  65. package/src/bond/config.ts +25 -0
  66. package/src/bond/escrow-contract.ts +63 -0
  67. package/src/bond/factory.ts +48 -0
  68. package/src/bond/index.ts +2 -0
  69. package/src/bond/token-contract.ts +85 -0
  70. package/src/config.ts +47 -12
  71. package/src/factory.ts +51 -10
  72. package/src/job/{block-proving-job.ts → epoch-proving-job.ts} +59 -57
  73. package/src/monitors/claims-monitor.ts +52 -0
  74. package/src/monitors/epoch-monitor.ts +48 -0
  75. package/src/monitors/index.ts +2 -0
  76. package/src/prover-coordination/config.ts +17 -0
  77. package/src/prover-coordination/factory.ts +11 -0
  78. package/src/{tx-provider → prover-coordination}/index.ts +1 -2
  79. package/src/prover-node.ts +169 -99
  80. package/src/quote-provider/http.ts +47 -0
  81. package/src/quote-provider/index.ts +8 -0
  82. package/src/quote-provider/simple.ts +15 -0
  83. package/src/quote-provider/utils.ts +10 -0
  84. package/src/quote-signer.ts +24 -0
  85. package/dest/job/block-proving-job.d.ts +0 -33
  86. package/dest/job/block-proving-job.d.ts.map +0 -1
  87. package/dest/job/block-proving-job.js +0 -120
  88. package/dest/tx-provider/aztec-node-tx-provider.d.ts +0 -8
  89. package/dest/tx-provider/aztec-node-tx-provider.d.ts.map +0 -1
  90. package/dest/tx-provider/aztec-node-tx-provider.js +0 -10
  91. package/dest/tx-provider/config.d.ts +0 -7
  92. package/dest/tx-provider/config.d.ts.map +0 -1
  93. package/dest/tx-provider/config.js +0 -12
  94. package/dest/tx-provider/factory.d.ts +0 -4
  95. package/dest/tx-provider/factory.d.ts.map +0 -1
  96. package/dest/tx-provider/factory.js +0 -12
  97. package/dest/tx-provider/index.d.ts +0 -4
  98. package/dest/tx-provider/index.d.ts.map +0 -1
  99. package/dest/tx-provider/index.js +0 -4
  100. package/src/tx-provider/aztec-node-tx-provider.ts +0 -10
  101. package/src/tx-provider/config.ts +0 -17
  102. package/src/tx-provider/factory.ts +0 -13
@@ -0,0 +1,48 @@
1
+ import { type L2BlockSource } from '@aztec/circuit-types';
2
+ import { createDebugLogger } from '@aztec/foundation/log';
3
+ import { RunningPromise } from '@aztec/foundation/running-promise';
4
+
5
+ export interface EpochMonitorHandler {
6
+ handleInitialEpochSync(epochNumber: bigint): Promise<void>;
7
+ handleEpochCompleted(epochNumber: bigint): Promise<void>;
8
+ }
9
+
10
+ export class EpochMonitor {
11
+ private runningPromise: RunningPromise;
12
+ private log = createDebugLogger('aztec:prover-node:epoch-monitor');
13
+
14
+ private handler: EpochMonitorHandler | undefined;
15
+
16
+ private latestEpochNumber: bigint | undefined;
17
+
18
+ constructor(private readonly l2BlockSource: L2BlockSource, private options: { pollingIntervalMs: number }) {
19
+ this.runningPromise = new RunningPromise(this.work.bind(this), this.options.pollingIntervalMs);
20
+ }
21
+
22
+ public start(handler: EpochMonitorHandler) {
23
+ this.handler = handler;
24
+ this.runningPromise.start();
25
+ this.log.info('Started EpochMonitor', this.options);
26
+ }
27
+
28
+ public async stop() {
29
+ await this.runningPromise.stop();
30
+ this.log.info('Stopped EpochMonitor');
31
+ }
32
+
33
+ public async work() {
34
+ if (!this.latestEpochNumber) {
35
+ const epochNumber = await this.l2BlockSource.getL2EpochNumber();
36
+ if (epochNumber > 0n) {
37
+ await this.handler?.handleInitialEpochSync(epochNumber - 1n);
38
+ }
39
+ this.latestEpochNumber = epochNumber;
40
+ return;
41
+ }
42
+
43
+ if (await this.l2BlockSource.isEpochComplete(this.latestEpochNumber)) {
44
+ await this.handler?.handleEpochCompleted(this.latestEpochNumber);
45
+ this.latestEpochNumber += 1n;
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,2 @@
1
+ export * from './claims-monitor.js';
2
+ export * from './epoch-monitor.js';
@@ -0,0 +1,17 @@
1
+ import { type ConfigMappingsType, getConfigFromMappings } from '@aztec/foundation/config';
2
+
3
+ export type ProverCoordinationConfig = {
4
+ proverCoordinationNodeUrl: string | undefined;
5
+ };
6
+
7
+ export const proverCoordinationConfigMappings: ConfigMappingsType<ProverCoordinationConfig> = {
8
+ proverCoordinationNodeUrl: {
9
+ env: 'PROVER_COORDINATION_NODE_URL',
10
+ description: 'The URL of the tx provider node',
11
+ parseEnv: (val: string) => val,
12
+ },
13
+ };
14
+
15
+ export function getTxProviderConfigFromEnv(): ProverCoordinationConfig {
16
+ return getConfigFromMappings<ProverCoordinationConfig>(proverCoordinationConfigMappings);
17
+ }
@@ -0,0 +1,11 @@
1
+ import { type ProverCoordination, createAztecNodeClient } from '@aztec/circuit-types';
2
+
3
+ import { type ProverCoordinationConfig } from './config.js';
4
+
5
+ export function createProverCoordination(config: ProverCoordinationConfig): ProverCoordination {
6
+ if (config.proverCoordinationNodeUrl) {
7
+ return createAztecNodeClient(config.proverCoordinationNodeUrl);
8
+ } else {
9
+ throw new Error(`Aztec Node URL for Tx Provider is not set.`);
10
+ }
11
+ }
@@ -1,3 +1,2 @@
1
- export * from './aztec-node-tx-provider.js';
2
- export * from './factory.js';
3
1
  export * from './config.js';
2
+ export * from './factory.js';
@@ -1,64 +1,160 @@
1
1
  import {
2
+ type EpochProofClaim,
3
+ type EpochProofQuote,
4
+ EpochProofQuotePayload,
5
+ type EpochProverManager,
2
6
  type L1ToL2MessageSource,
7
+ type L2Block,
3
8
  type L2BlockSource,
4
- type MerkleTreeOperations,
5
- type ProverClient,
6
- type TxProvider,
9
+ type MerkleTreeWriteOperations,
10
+ type ProverCoordination,
7
11
  type WorldStateSynchronizer,
8
12
  } from '@aztec/circuit-types';
13
+ import { type ContractDataSource } from '@aztec/circuits.js';
14
+ import { compact } from '@aztec/foundation/collection';
9
15
  import { createDebugLogger } from '@aztec/foundation/log';
10
- import { RunningPromise } from '@aztec/foundation/running-promise';
11
16
  import { type L1Publisher } from '@aztec/sequencer-client';
12
17
  import { PublicProcessorFactory, type SimulationProvider } from '@aztec/simulator';
13
18
  import { type TelemetryClient } from '@aztec/telemetry-client';
14
- import { type ContractDataSource } from '@aztec/types/contracts';
15
19
 
16
- import { BlockProvingJob, type BlockProvingJobState } from './job/block-proving-job.js';
20
+ import { type BondManager } from './bond/bond-manager.js';
21
+ import { EpochProvingJob, type EpochProvingJobState } from './job/epoch-proving-job.js';
17
22
  import { ProverNodeMetrics } from './metrics.js';
23
+ import { type ClaimsMonitor, type ClaimsMonitorHandler } from './monitors/claims-monitor.js';
24
+ import { type EpochMonitor, type EpochMonitorHandler } from './monitors/epoch-monitor.js';
25
+ import { type QuoteProvider } from './quote-provider/index.js';
26
+ import { type QuoteSigner } from './quote-signer.js';
27
+
28
+ export type ProverNodeOptions = {
29
+ pollingIntervalMs: number;
30
+ maxPendingJobs: number;
31
+ };
18
32
 
19
33
  /**
20
34
  * An Aztec Prover Node is a standalone process that monitors the unfinalised chain on L1 for unproven blocks,
21
- * fetches their txs from a tx source in the p2p network or an external node, re-executes their public functions,
22
- * creates a rollup proof, and submits it to L1.
35
+ * submits bids for proving them, and monitors if they are accepted. If so, the prover node fetches the txs
36
+ * from a tx source in the p2p network or an external node, re-executes their public functions, creates a rollup
37
+ * proof for the epoch, and submits it to L1.
23
38
  */
24
- export class ProverNode {
39
+ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler {
25
40
  private log = createDebugLogger('aztec:prover-node');
26
- private runningPromise: RunningPromise | undefined;
27
- private latestBlockWeAreProving: number | undefined;
28
- private jobs: Map<string, BlockProvingJob> = new Map();
29
- private options: { pollingIntervalMs: number; disableAutomaticProving: boolean; maxPendingJobs: number };
41
+
42
+ private latestEpochWeAreProving: bigint | undefined;
43
+ private jobs: Map<string, EpochProvingJob> = new Map();
44
+ private options: ProverNodeOptions;
30
45
  private metrics: ProverNodeMetrics;
31
46
 
32
47
  constructor(
33
- private prover: ProverClient,
34
- private publisher: L1Publisher,
35
- private l2BlockSource: L2BlockSource,
36
- private l1ToL2MessageSource: L1ToL2MessageSource,
37
- private contractDataSource: ContractDataSource,
38
- private worldState: WorldStateSynchronizer,
39
- private txProvider: TxProvider,
40
- private simulator: SimulationProvider,
41
- private telemetryClient: TelemetryClient,
42
- options: { pollingIntervalMs?: number; disableAutomaticProving?: boolean; maxPendingJobs?: number } = {},
48
+ private readonly prover: EpochProverManager,
49
+ private readonly publisher: L1Publisher,
50
+ private readonly l2BlockSource: L2BlockSource,
51
+ private readonly l1ToL2MessageSource: L1ToL2MessageSource,
52
+ private readonly contractDataSource: ContractDataSource,
53
+ private readonly worldState: WorldStateSynchronizer,
54
+ private readonly coordination: ProverCoordination,
55
+ private readonly simulator: SimulationProvider,
56
+ private readonly quoteProvider: QuoteProvider,
57
+ private readonly quoteSigner: QuoteSigner,
58
+ private readonly claimsMonitor: ClaimsMonitor,
59
+ private readonly epochsMonitor: EpochMonitor,
60
+ private readonly bondManager: BondManager,
61
+ private readonly telemetryClient: TelemetryClient,
62
+ options: Partial<ProverNodeOptions> = {},
43
63
  ) {
44
64
  this.options = {
45
65
  pollingIntervalMs: 1_000,
46
- disableAutomaticProving: false,
47
66
  maxPendingJobs: 100,
48
- ...options,
67
+ ...compact(options),
49
68
  };
50
69
 
51
70
  this.metrics = new ProverNodeMetrics(telemetryClient, 'ProverNode');
52
71
  }
53
72
 
73
+ async handleClaim(proofClaim: EpochProofClaim): Promise<void> {
74
+ if (proofClaim.epochToProve === this.latestEpochWeAreProving) {
75
+ this.log.verbose(`Already proving claim for epoch ${proofClaim.epochToProve}`);
76
+ return;
77
+ }
78
+
79
+ try {
80
+ await this.startProof(proofClaim.epochToProve);
81
+ this.latestEpochWeAreProving = proofClaim.epochToProve;
82
+ } catch (err) {
83
+ this.log.error(`Error handling claim for epoch ${proofClaim.epochToProve}`, err);
84
+ }
85
+
86
+ try {
87
+ // Staked amounts are lowered after a claim, so this is a good time for doing a top-up if needed
88
+ await this.bondManager.ensureBond();
89
+ } catch (err) {
90
+ this.log.error(`Error ensuring prover bond after handling claim for epoch ${proofClaim.epochToProve}`, err);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Handles the epoch number to prove when the prover node starts by checking if there
96
+ * is an existing claim for it. If not, it creates and sends a quote for it.
97
+ * @param epochNumber - The epoch immediately before the current one when the prover node starts.
98
+ */
99
+ async handleInitialEpochSync(epochNumber: bigint): Promise<void> {
100
+ try {
101
+ const claim = await this.publisher.getProofClaim();
102
+ if (!claim || claim.epochToProve < epochNumber) {
103
+ await this.handleEpochCompleted(epochNumber);
104
+ } else if (claim && claim.bondProvider.equals(this.publisher.getSenderAddress())) {
105
+ const lastEpochProven = await this.l2BlockSource.getProvenL2EpochNumber();
106
+ if (lastEpochProven === undefined || lastEpochProven < claim.epochToProve) {
107
+ await this.handleClaim(claim);
108
+ }
109
+ }
110
+ } catch (err) {
111
+ this.log.error(`Error handling initial epoch sync`, err);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Handles an epoch being completed by sending a quote for proving it.
117
+ * @param epochNumber - The epoch number that was just completed.
118
+ */
119
+ async handleEpochCompleted(epochNumber: bigint): Promise<void> {
120
+ try {
121
+ // Construct a quote for the epoch
122
+ const blocks = await this.l2BlockSource.getBlocksForEpoch(epochNumber);
123
+ const partialQuote = await this.quoteProvider.getQuote(Number(epochNumber), blocks);
124
+ if (!partialQuote) {
125
+ this.log.verbose(`No quote produced for epoch ${epochNumber}`);
126
+ return;
127
+ }
128
+
129
+ // Ensure we have deposited enough funds for sending this quote
130
+ await this.bondManager.ensureBond(partialQuote.bondAmount);
131
+
132
+ // Assemble and sign full quote
133
+ const quote = EpochProofQuotePayload.from({
134
+ ...partialQuote,
135
+ epochToProve: BigInt(epochNumber),
136
+ prover: this.publisher.getSenderAddress(),
137
+ validUntilSlot: partialQuote.validUntilSlot ?? BigInt(Number.MAX_SAFE_INTEGER), // Should we constrain this?
138
+ });
139
+ const signed = await this.quoteSigner.sign(quote);
140
+
141
+ // Send it to the coordinator
142
+ await this.sendEpochProofQuote(signed);
143
+ } catch (err) {
144
+ this.log.error(`Error handling epoch completed`, err);
145
+ }
146
+ }
147
+
54
148
  /**
55
- * Starts the prover node so it periodically checks for unproven blocks in the unfinalised chain from L1 and proves them.
56
- * This may change once we implement a prover coordination mechanism.
149
+ * Starts the prover node so it periodically checks for unproven epochs in the unfinalised chain from L1 and sends
150
+ * quotes for them, as well as monitors the claims for the epochs it has sent quotes for and starts proving jobs.
151
+ * This method returns once the prover node has deposited an initial bond into the escrow contract.
57
152
  */
58
- start() {
59
- this.runningPromise = new RunningPromise(this.work.bind(this), this.options.pollingIntervalMs);
60
- this.runningPromise.start();
61
- this.log.info('Started ProverNode');
153
+ async start() {
154
+ await this.bondManager.ensureBond();
155
+ this.epochsMonitor.start(this);
156
+ this.claimsMonitor.start(this);
157
+ this.log.info('Started ProverNode', this.options);
62
158
  }
63
159
 
64
160
  /**
@@ -66,79 +162,38 @@ export class ProverNode {
66
162
  */
67
163
  async stop() {
68
164
  this.log.info('Stopping ProverNode');
69
- await this.runningPromise?.stop();
165
+ await this.epochsMonitor.stop();
166
+ await this.claimsMonitor.stop();
70
167
  await this.prover.stop();
71
168
  await this.l2BlockSource.stop();
72
169
  this.publisher.interrupt();
73
- this.jobs.forEach(job => job.stop());
170
+ await Promise.all(Array.from(this.jobs.values()).map(job => job.stop()));
74
171
  await this.worldState.stop();
75
172
  this.log.info('Stopped ProverNode');
76
173
  }
77
174
 
78
175
  /**
79
- * Single iteration of recurring work. This method is called periodically by the running promise.
80
- * Checks whether there are new blocks to prove, proves them, and submits them.
176
+ * Sends an epoch proof quote to the coordinator.
81
177
  */
82
- protected async work() {
83
- try {
84
- if (this.options.disableAutomaticProving) {
85
- return;
86
- }
87
-
88
- if (!this.checkMaximumPendingJobs()) {
89
- this.log.debug(`Maximum pending proving jobs reached. Skipping work.`, {
90
- maxPendingJobs: this.options.maxPendingJobs,
91
- pendingJobs: this.jobs.size,
92
- });
93
- return;
94
- }
95
-
96
- const [latestBlockNumber, latestProvenBlockNumber] = await Promise.all([
97
- this.l2BlockSource.getBlockNumber(),
98
- this.l2BlockSource.getProvenBlockNumber(),
99
- ]);
100
-
101
- // Consider both the latest block we are proving and the last block proven on the chain
102
- const latestBlockBeingProven = this.latestBlockWeAreProving ?? 0;
103
- const latestProven = Math.max(latestBlockBeingProven, latestProvenBlockNumber);
104
- if (latestProven >= latestBlockNumber) {
105
- this.log.debug(`No new blocks to prove`, {
106
- latestBlockNumber,
107
- latestProvenBlockNumber,
108
- latestBlockBeingProven,
109
- });
110
- return;
111
- }
112
-
113
- const fromBlock = latestProven + 1;
114
- const toBlock = fromBlock; // We only prove one block at a time for now
115
-
116
- try {
117
- await this.startProof(fromBlock, toBlock);
118
- } finally {
119
- // If we fail to create a proving job for the given block, skip it instead of getting stuck on it.
120
- this.log.verbose(`Setting ${toBlock} as latest block we are proving`);
121
- this.latestBlockWeAreProving = toBlock;
122
- }
123
- } catch (err) {
124
- this.log.error(`Error in prover node work`, err);
125
- }
178
+ public sendEpochProofQuote(quote: EpochProofQuote): Promise<void> {
179
+ this.log.info(`Sending quote for epoch`, quote.toViemArgs().quote);
180
+ return this.coordination.addEpochProofQuote(quote);
126
181
  }
127
182
 
128
183
  /**
129
184
  * Creates a proof for a block range. Returns once the proof has been submitted to L1.
130
185
  */
131
- public async prove(fromBlock: number, toBlock: number) {
132
- const job = await this.createProvingJob(fromBlock);
133
- return job.run(fromBlock, toBlock);
186
+ public async prove(epochNumber: number | bigint) {
187
+ const job = await this.createProvingJob(BigInt(epochNumber));
188
+ return job.run();
134
189
  }
135
190
 
136
191
  /**
137
192
  * Starts a proving process and returns immediately.
138
193
  */
139
- public async startProof(fromBlock: number, toBlock: number) {
140
- const job = await this.createProvingJob(fromBlock);
141
- void job.run(fromBlock, toBlock);
194
+ public async startProof(epochNumber: number | bigint) {
195
+ const job = await this.createProvingJob(BigInt(epochNumber));
196
+ void job.run().catch(err => this.log.error(`Error proving epoch ${epochNumber}`, err));
142
197
  }
143
198
 
144
199
  /**
@@ -151,7 +206,7 @@ export class ProverNode {
151
206
  /**
152
207
  * Returns an array of jobs being processed.
153
208
  */
154
- public getJobs(): { uuid: string; status: BlockProvingJobState }[] {
209
+ public getJobs(): { uuid: string; status: EpochProvingJobState }[] {
155
210
  return Array.from(this.jobs.entries()).map(([uuid, job]) => ({ uuid, status: job.getState() }));
156
211
  }
157
212
 
@@ -160,52 +215,67 @@ export class ProverNode {
160
215
  return maxPendingJobs === 0 || this.jobs.size < maxPendingJobs;
161
216
  }
162
217
 
163
- private async createProvingJob(fromBlock: number) {
218
+ private async createProvingJob(epochNumber: bigint) {
164
219
  if (!this.checkMaximumPendingJobs()) {
165
220
  throw new Error(`Maximum pending proving jobs ${this.options.maxPendingJobs} reached. Cannot create new job.`);
166
221
  }
167
222
 
168
- if ((await this.worldState.status()).syncedToL2Block >= fromBlock) {
169
- throw new Error(`Cannot create proving job for block ${fromBlock} as it is behind the current world state`);
223
+ // Gather blocks for this epoch
224
+ const blocks = await this.l2BlockSource.getBlocksForEpoch(epochNumber);
225
+ if (blocks.length === 0) {
226
+ throw new Error(`No blocks found for epoch ${epochNumber}`);
170
227
  }
228
+ const fromBlock = blocks[0].number;
229
+ const toBlock = blocks.at(-1)!.number;
171
230
 
172
231
  // Fast forward world state to right before the target block and get a fork
173
- this.log.verbose(`Creating proving job for block ${fromBlock}`);
174
- const db = await this.worldState.syncImmediateAndFork(fromBlock - 1, true);
232
+ this.log.verbose(`Creating proving job for epoch ${epochNumber} for block range ${fromBlock} to ${toBlock}`);
233
+ await this.worldState.syncImmediate(fromBlock - 1);
234
+ const db = await this.worldState.fork(fromBlock - 1);
175
235
 
176
236
  // Create a processor using the forked world state
177
237
  const publicProcessorFactory = new PublicProcessorFactory(
178
- db,
179
238
  this.contractDataSource,
180
239
  this.simulator,
181
240
  this.telemetryClient,
182
241
  );
183
242
 
184
243
  const cleanUp = async () => {
185
- await db.delete();
244
+ await db.close();
186
245
  this.jobs.delete(job.getId());
187
246
  };
188
247
 
189
- const job = this.doCreateBlockProvingJob(db, publicProcessorFactory, cleanUp);
248
+ const job = this.doCreateEpochProvingJob(epochNumber, blocks, db, publicProcessorFactory, cleanUp);
190
249
  this.jobs.set(job.getId(), job);
191
250
  return job;
192
251
  }
193
252
 
194
253
  /** Extracted for testing purposes. */
195
- protected doCreateBlockProvingJob(
196
- db: MerkleTreeOperations,
254
+ protected doCreateEpochProvingJob(
255
+ epochNumber: bigint,
256
+ blocks: L2Block[],
257
+ db: MerkleTreeWriteOperations,
197
258
  publicProcessorFactory: PublicProcessorFactory,
198
259
  cleanUp: () => Promise<void>,
199
260
  ) {
200
- return new BlockProvingJob(
201
- this.prover.createBlockProver(db),
261
+ return new EpochProvingJob(
262
+ db,
263
+ epochNumber,
264
+ blocks,
265
+ this.prover.createEpochProver(db),
202
266
  publicProcessorFactory,
203
267
  this.publisher,
204
268
  this.l2BlockSource,
205
269
  this.l1ToL2MessageSource,
206
- this.txProvider,
270
+ this.coordination,
207
271
  this.metrics,
208
272
  cleanUp,
209
273
  );
210
274
  }
275
+
276
+ /** Extracted for testing purposes. */
277
+ protected async triggerMonitors() {
278
+ await this.epochsMonitor.work();
279
+ await this.claimsMonitor.work();
280
+ }
211
281
  }
@@ -0,0 +1,47 @@
1
+ import { type L2Block } from '@aztec/circuit-types';
2
+
3
+ import { type QuoteProvider, type QuoteProviderResult } from './index.js';
4
+ import { getTotalFees, getTxCount } from './utils.js';
5
+
6
+ export class HttpQuoteProvider implements QuoteProvider {
7
+ constructor(private readonly url: string) {}
8
+
9
+ public async getQuote(epochNumber: number, epoch: L2Block[]): Promise<QuoteProviderResult | undefined> {
10
+ const payload: HttpQuoteRequestPayload = {
11
+ epochNumber,
12
+ fromBlock: epoch[0].number,
13
+ toBlock: epoch.at(-1)!.number,
14
+ totalFees: getTotalFees(epoch).toString(),
15
+ txCount: getTxCount(epoch),
16
+ };
17
+
18
+ const response = await fetch(this.url, {
19
+ method: 'POST',
20
+ body: JSON.stringify(payload),
21
+ headers: { 'content-type': 'application/json' },
22
+ });
23
+
24
+ if (!response.ok) {
25
+ throw new Error(`Failed to fetch quote: ${response.statusText}`);
26
+ }
27
+
28
+ const data = await response.json();
29
+ if (!data.basisPointFee || !data.bondAmount) {
30
+ throw new Error(`Missing required fields in response: ${JSON.stringify(data)}`);
31
+ }
32
+
33
+ const basisPointFee = Number(data.basisPointFee);
34
+ const bondAmount = BigInt(data.bondAmount);
35
+ const validUntilSlot = data.validUntilSlot ? BigInt(data.validUntilSlot) : undefined;
36
+
37
+ return { basisPointFee, bondAmount, validUntilSlot };
38
+ }
39
+ }
40
+
41
+ export type HttpQuoteRequestPayload = {
42
+ epochNumber: number;
43
+ fromBlock: number;
44
+ toBlock: number;
45
+ totalFees: string;
46
+ txCount: number;
47
+ };
@@ -0,0 +1,8 @@
1
+ import { type EpochProofQuotePayload, type L2Block } from '@aztec/circuit-types';
2
+
3
+ export type QuoteProviderResult = Pick<EpochProofQuotePayload, 'basisPointFee' | 'bondAmount'> &
4
+ Partial<Pick<EpochProofQuotePayload, 'validUntilSlot'>>;
5
+
6
+ export interface QuoteProvider {
7
+ getQuote(epochNumber: number, epoch: L2Block[]): Promise<QuoteProviderResult | undefined>;
8
+ }
@@ -0,0 +1,15 @@
1
+ import { type EpochProofQuotePayload, type L2Block } from '@aztec/circuit-types';
2
+
3
+ import { type QuoteProvider } from './index.js';
4
+
5
+ export class SimpleQuoteProvider implements QuoteProvider {
6
+ constructor(public readonly basisPointFee: number, public readonly bondAmount: bigint) {}
7
+
8
+ getQuote(
9
+ _epochNumber: number,
10
+ _epoch: L2Block[],
11
+ ): Promise<Pick<EpochProofQuotePayload, 'basisPointFee' | 'bondAmount'>> {
12
+ const { basisPointFee, bondAmount } = this;
13
+ return Promise.resolve({ basisPointFee, bondAmount });
14
+ }
15
+ }
@@ -0,0 +1,10 @@
1
+ import { type L2Block } from '@aztec/circuit-types';
2
+ import { Fr } from '@aztec/circuits.js';
3
+
4
+ export function getTotalFees(epoch: L2Block[]) {
5
+ return epoch.reduce((total, block) => total.add(block.header.totalFees), Fr.ZERO).toBigInt();
6
+ }
7
+
8
+ export function getTxCount(epoch: L2Block[]) {
9
+ return epoch.reduce((total, block) => total + block.body.txEffects.length, 0);
10
+ }
@@ -0,0 +1,24 @@
1
+ import { EpochProofQuote, type EpochProofQuotePayload } from '@aztec/circuit-types';
2
+ import { Buffer32 } from '@aztec/foundation/buffer';
3
+ import { Secp256k1Signer } from '@aztec/foundation/crypto';
4
+ import { type RollupAbi } from '@aztec/l1-artifacts';
5
+
6
+ import { type GetContractReturnType, type PublicClient } from 'viem';
7
+
8
+ export class QuoteSigner {
9
+ constructor(
10
+ private readonly signer: Secp256k1Signer,
11
+ private readonly quoteToDigest: (payload: EpochProofQuotePayload) => Promise<Buffer32>,
12
+ ) {}
13
+
14
+ static new(privateKey: Buffer32, rollupContract: GetContractReturnType<typeof RollupAbi, PublicClient>): QuoteSigner {
15
+ const quoteToDigest = (payload: EpochProofQuotePayload) =>
16
+ rollupContract.read.quoteToDigest([payload.toViemArgs()]).then(Buffer32.fromString);
17
+ return new QuoteSigner(new Secp256k1Signer(privateKey), quoteToDigest);
18
+ }
19
+
20
+ public async sign(payload: EpochProofQuotePayload) {
21
+ const digest = await this.quoteToDigest(payload);
22
+ return EpochProofQuote.new(digest, payload, this.signer);
23
+ }
24
+ }
@@ -1,33 +0,0 @@
1
- import { type BlockProver, type L1ToL2MessageSource, type L2BlockSource, type TxProvider } from '@aztec/circuit-types';
2
- import { type L1Publisher } from '@aztec/sequencer-client';
3
- import { type PublicProcessorFactory } from '@aztec/simulator';
4
- import { type ProverNodeMetrics } from '../metrics.js';
5
- /**
6
- * Job that grabs a range of blocks from the unfinalised chain from L1, gets their txs given their hashes,
7
- * re-executes their public calls, generates a rollup proof, and submits it to L1. This job will update the
8
- * world state as part of public call execution via the public processor.
9
- */
10
- export declare class BlockProvingJob {
11
- private prover;
12
- private publicProcessorFactory;
13
- private publisher;
14
- private l2BlockSource;
15
- private l1ToL2MessageSource;
16
- private txProvider;
17
- private metrics;
18
- private cleanUp;
19
- private state;
20
- private log;
21
- private uuid;
22
- constructor(prover: BlockProver, publicProcessorFactory: PublicProcessorFactory, publisher: L1Publisher, l2BlockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, metrics: ProverNodeMetrics, cleanUp?: (job: BlockProvingJob) => Promise<void>);
23
- getId(): string;
24
- getState(): BlockProvingJobState;
25
- run(fromBlock: number, toBlock: number): Promise<void>;
26
- stop(): void;
27
- private getBlock;
28
- private getTxs;
29
- private getL1ToL2Messages;
30
- private processTxs;
31
- }
32
- export type BlockProvingJobState = 'initialized' | 'processing' | 'awaiting-prover' | 'publishing-proof' | 'completed' | 'failed';
33
- //# sourceMappingURL=block-proving-job.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"block-proving-job.d.ts","sourceRoot":"","sources":["../../src/job/block-proving-job.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,mBAAmB,EAExB,KAAK,aAAa,EAKlB,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAwB,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAIrF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;GAIG;AACH,qBAAa,eAAe;IAMxB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;IAZjB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,GAAG,CAAgD;IAC3D,OAAO,CAAC,IAAI,CAAS;gBAGX,MAAM,EAAE,WAAW,EACnB,sBAAsB,EAAE,sBAAsB,EAC9C,SAAS,EAAE,WAAW,EACtB,aAAa,EAAE,aAAa,EAC5B,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,GAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAA2B;IAK7E,KAAK,IAAI,MAAM;IAIf,QAAQ,IAAI,oBAAoB;IAI1B,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IA8E5C,IAAI;YAIG,QAAQ;YAQR,MAAM;IAWpB,OAAO,CAAC,iBAAiB;YAIX,UAAU;CAoBzB;AAED,MAAM,MAAM,oBAAoB,GAC5B,aAAa,GACb,YAAY,GACZ,iBAAiB,GACjB,kBAAkB,GAClB,WAAW,GACX,QAAQ,CAAC"}