@aztec/prover-node 0.76.4-devnet-test → 0.76.4-devnet-test-rc3
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.
- package/dest/bond/bond-manager.d.ts +22 -0
- package/dest/bond/bond-manager.d.ts.map +1 -0
- package/dest/bond/bond-manager.js +42 -0
- package/dest/bond/config.d.ts +8 -0
- package/dest/bond/config.d.ts.map +1 -0
- package/dest/bond/config.js +17 -0
- package/dest/bond/escrow-contract.d.ts +19 -0
- package/dest/bond/escrow-contract.d.ts.map +1 -0
- package/dest/bond/escrow-contract.js +32 -0
- package/dest/bond/factory.d.ts +6 -0
- package/dest/bond/factory.d.ts.map +1 -0
- package/dest/bond/factory.js +17 -0
- package/dest/bond/index.d.ts +3 -0
- package/dest/bond/index.d.ts.map +1 -0
- package/dest/bond/index.js +3 -0
- package/dest/bond/token-contract.d.ts +26 -0
- package/dest/bond/token-contract.d.ts.map +1 -0
- package/dest/bond/token-contract.js +58 -0
- package/dest/config.d.ts +7 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +23 -2
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +32 -3
- package/dest/job/epoch-proving-job.d.ts +0 -1
- package/dest/job/epoch-proving-job.d.ts.map +1 -1
- package/dest/job/epoch-proving-job.js +1 -4
- package/dest/monitors/claims-monitor.d.ts +24 -0
- package/dest/monitors/claims-monitor.d.ts.map +1 -0
- package/dest/monitors/claims-monitor.js +54 -0
- package/dest/monitors/epoch-monitor.d.ts +1 -0
- package/dest/monitors/epoch-monitor.d.ts.map +1 -1
- package/dest/monitors/epoch-monitor.js +2 -2
- package/dest/monitors/index.d.ts +1 -0
- package/dest/monitors/index.d.ts.map +1 -1
- package/dest/monitors/index.js +2 -1
- package/dest/prover-node-publisher.d.ts +7 -0
- package/dest/prover-node-publisher.d.ts.map +1 -1
- package/dest/prover-node-publisher.js +10 -9
- package/dest/prover-node.d.ts +26 -12
- package/dest/prover-node.d.ts.map +1 -1
- package/dest/prover-node.js +89 -24
- package/dest/quote-provider/http.d.ts +15 -0
- package/dest/quote-provider/http.d.ts.map +1 -0
- package/dest/quote-provider/http.js +33 -0
- package/dest/quote-provider/index.d.ts +6 -0
- package/dest/quote-provider/index.d.ts.map +1 -0
- package/dest/quote-provider/index.js +2 -0
- package/dest/quote-provider/simple.d.ts +9 -0
- package/dest/quote-provider/simple.d.ts.map +1 -0
- package/dest/quote-provider/simple.js +11 -0
- package/dest/quote-provider/utils.d.ts +4 -0
- package/dest/quote-provider/utils.d.ts.map +1 -0
- package/dest/quote-provider/utils.js +8 -0
- package/dest/quote-signer.d.ts +13 -0
- package/dest/quote-signer.d.ts.map +1 -0
- package/dest/quote-signer.js +18 -0
- package/package.json +20 -20
- package/src/bond/bond-manager.ts +48 -0
- package/src/bond/config.ts +25 -0
- package/src/bond/escrow-contract.ts +50 -0
- package/src/bond/factory.ts +28 -0
- package/src/bond/index.ts +2 -0
- package/src/bond/token-contract.ts +72 -0
- package/src/config.ts +37 -1
- package/src/factory.ts +40 -2
- package/src/job/epoch-proving-job.ts +0 -4
- package/src/monitors/claims-monitor.ts +69 -0
- package/src/monitors/epoch-monitor.ts +2 -1
- package/src/monitors/index.ts +1 -0
- package/src/prover-node-publisher.ts +10 -8
- package/src/prover-node.ts +106 -29
- package/src/quote-provider/http.ts +48 -0
- package/src/quote-provider/index.ts +8 -0
- package/src/quote-provider/simple.ts +15 -0
- package/src/quote-provider/utils.ts +10 -0
- package/src/quote-signer.ts +24 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type EpochProofClaim } from '@aztec/circuit-types';
|
|
2
|
+
import { type EthAddress } from '@aztec/circuits.js';
|
|
3
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
5
|
+
import {
|
|
6
|
+
type TelemetryClient,
|
|
7
|
+
type Traceable,
|
|
8
|
+
type Tracer,
|
|
9
|
+
getTelemetryClient,
|
|
10
|
+
trackSpan,
|
|
11
|
+
} from '@aztec/telemetry-client';
|
|
12
|
+
|
|
13
|
+
import { type ProverNodePublisher } from '../prover-node-publisher.js';
|
|
14
|
+
|
|
15
|
+
export interface ClaimsMonitorHandler {
|
|
16
|
+
handleClaim(proofClaim: EpochProofClaim): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class ClaimsMonitor implements Traceable {
|
|
20
|
+
private runningPromise: RunningPromise;
|
|
21
|
+
private log = createLogger('prover-node:claims-monitor');
|
|
22
|
+
|
|
23
|
+
private handler: ClaimsMonitorHandler | undefined;
|
|
24
|
+
private lastClaimEpochNumber: bigint | undefined;
|
|
25
|
+
|
|
26
|
+
public readonly tracer: Tracer;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
private readonly l1Publisher: ProverNodePublisher,
|
|
30
|
+
private options: { pollingIntervalMs: number },
|
|
31
|
+
telemetry: TelemetryClient = getTelemetryClient(),
|
|
32
|
+
) {
|
|
33
|
+
this.tracer = telemetry.getTracer('ClaimsMonitor');
|
|
34
|
+
this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.options.pollingIntervalMs);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public start(handler: ClaimsMonitorHandler) {
|
|
38
|
+
this.handler = handler;
|
|
39
|
+
this.runningPromise.start();
|
|
40
|
+
this.log.info(`Started ClaimsMonitor with prover address ${this.getProverAddress().toString()}`, this.options);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public async stop() {
|
|
44
|
+
this.log.verbose('Stopping ClaimsMonitor');
|
|
45
|
+
await this.runningPromise.stop();
|
|
46
|
+
this.log.info('Stopped ClaimsMonitor');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@trackSpan('ClaimsMonitor.work')
|
|
50
|
+
public async work() {
|
|
51
|
+
const proofClaim = await this.l1Publisher.getProofClaim();
|
|
52
|
+
if (!proofClaim) {
|
|
53
|
+
this.log.trace(`Found no proof claim`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (this.lastClaimEpochNumber === undefined || proofClaim.epochToProve > this.lastClaimEpochNumber) {
|
|
58
|
+
this.log.verbose(`Found new claim for epoch ${proofClaim.epochToProve} by ${proofClaim.bondProvider.toString()}`);
|
|
59
|
+
if (proofClaim.bondProvider.equals(this.getProverAddress())) {
|
|
60
|
+
await this.handler?.handleClaim(proofClaim);
|
|
61
|
+
}
|
|
62
|
+
this.lastClaimEpochNumber = proofClaim.epochToProve;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected getProverAddress(): EthAddress {
|
|
67
|
+
return this.l1Publisher.getSenderAddress();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from '@aztec/telemetry-client';
|
|
11
11
|
|
|
12
12
|
export interface EpochMonitorHandler {
|
|
13
|
+
handleInitialEpochSync(epochNumber: bigint): Promise<void>;
|
|
13
14
|
handleEpochCompleted(epochNumber: bigint): Promise<void>;
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -47,7 +48,7 @@ export class EpochMonitor implements Traceable {
|
|
|
47
48
|
if (!this.latestEpochNumber) {
|
|
48
49
|
const epochNumber = await this.l2BlockSource.getL2EpochNumber();
|
|
49
50
|
if (epochNumber > 0n) {
|
|
50
|
-
await this.handler?.
|
|
51
|
+
await this.handler?.handleInitialEpochSync(epochNumber - 1n);
|
|
51
52
|
}
|
|
52
53
|
this.latestEpochNumber = epochNumber;
|
|
53
54
|
return;
|
package/src/monitors/index.ts
CHANGED
|
@@ -85,6 +85,10 @@ export class ProverNodePublisher {
|
|
|
85
85
|
return EthAddress.fromString(this.l1TxUtils.getSenderAddress());
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
public getProofClaim() {
|
|
89
|
+
return this.rollupContract.getProofClaim();
|
|
90
|
+
}
|
|
91
|
+
|
|
88
92
|
public async submitEpochProof(args: {
|
|
89
93
|
epochNumber: number;
|
|
90
94
|
fromBlock: number;
|
|
@@ -201,12 +205,11 @@ export class ProverNodePublisher {
|
|
|
201
205
|
|
|
202
206
|
const txArgs = [
|
|
203
207
|
{
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
aggregationObject: argsArray[5],
|
|
208
|
+
epochSize: argsArray[0],
|
|
209
|
+
args: argsArray[1],
|
|
210
|
+
fees: argsArray[2],
|
|
211
|
+
blobPublicInputs: argsArray[3],
|
|
212
|
+
aggregationObject: argsArray[4],
|
|
210
213
|
proof: proofHex,
|
|
211
214
|
},
|
|
212
215
|
] as const;
|
|
@@ -249,8 +252,7 @@ export class ProverNodePublisher {
|
|
|
249
252
|
proof: Proof;
|
|
250
253
|
}) {
|
|
251
254
|
return [
|
|
252
|
-
BigInt(args.fromBlock),
|
|
253
|
-
BigInt(args.toBlock),
|
|
255
|
+
BigInt(args.toBlock - args.fromBlock + 1),
|
|
254
256
|
[
|
|
255
257
|
args.publicInputs.previousArchive.root.toString(),
|
|
256
258
|
args.publicInputs.endArchive.root.toString(),
|
package/src/prover-node.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type EpochProofClaim,
|
|
3
|
+
type EpochProofQuote,
|
|
4
|
+
EpochProofQuotePayload,
|
|
2
5
|
type EpochProverManager,
|
|
3
|
-
EpochProvingJobTerminalState,
|
|
4
6
|
type L1ToL2MessageSource,
|
|
5
7
|
type L2Block,
|
|
6
8
|
type L2BlockSource,
|
|
@@ -32,10 +34,14 @@ import {
|
|
|
32
34
|
trackSpan,
|
|
33
35
|
} from '@aztec/telemetry-client';
|
|
34
36
|
|
|
37
|
+
import { type BondManager } from './bond/bond-manager.js';
|
|
35
38
|
import { EpochProvingJob, type EpochProvingJobState } from './job/epoch-proving-job.js';
|
|
36
39
|
import { ProverNodeMetrics } from './metrics.js';
|
|
40
|
+
import { type ClaimsMonitor, type ClaimsMonitorHandler } from './monitors/claims-monitor.js';
|
|
37
41
|
import { type EpochMonitor, type EpochMonitorHandler } from './monitors/epoch-monitor.js';
|
|
38
42
|
import { type ProverNodePublisher } from './prover-node-publisher.js';
|
|
43
|
+
import { type QuoteProvider } from './quote-provider/index.js';
|
|
44
|
+
import { type QuoteSigner } from './quote-signer.js';
|
|
39
45
|
|
|
40
46
|
export type ProverNodeOptions = {
|
|
41
47
|
pollingIntervalMs: number;
|
|
@@ -52,7 +58,7 @@ export type ProverNodeOptions = {
|
|
|
52
58
|
* from a tx source in the p2p network or an external node, re-executes their public functions, creates a rollup
|
|
53
59
|
* proof for the epoch, and submits it to L1.
|
|
54
60
|
*/
|
|
55
|
-
export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable {
|
|
61
|
+
export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, ProverNodeApi, Traceable {
|
|
56
62
|
private log = createLogger('prover-node');
|
|
57
63
|
private dateProvider = new DateProvider();
|
|
58
64
|
|
|
@@ -75,7 +81,11 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
|
|
|
75
81
|
protected readonly contractDataSource: ContractDataSource,
|
|
76
82
|
protected readonly worldState: WorldStateSynchronizer,
|
|
77
83
|
protected readonly coordination: ProverCoordination & Maybe<Service>,
|
|
84
|
+
protected readonly quoteProvider: QuoteProvider,
|
|
85
|
+
protected readonly quoteSigner: QuoteSigner,
|
|
86
|
+
protected readonly claimsMonitor: ClaimsMonitor,
|
|
78
87
|
protected readonly epochsMonitor: EpochMonitor,
|
|
88
|
+
protected readonly bondManager: BondManager,
|
|
79
89
|
options: Partial<ProverNodeOptions> = {},
|
|
80
90
|
protected readonly telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
81
91
|
) {
|
|
@@ -102,23 +112,89 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
|
|
|
102
112
|
return undefined;
|
|
103
113
|
}
|
|
104
114
|
|
|
115
|
+
async handleClaim(proofClaim: EpochProofClaim): Promise<void> {
|
|
116
|
+
if (proofClaim.epochToProve === this.latestEpochWeAreProving) {
|
|
117
|
+
this.log.verbose(`Already proving claim for epoch ${proofClaim.epochToProve}`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const provenEpoch = await this.l2BlockSource.getProvenL2EpochNumber();
|
|
122
|
+
if (provenEpoch !== undefined && proofClaim.epochToProve <= provenEpoch) {
|
|
123
|
+
this.log.verbose(`Claim for epoch ${proofClaim.epochToProve} is already proven`);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await this.startProof(proofClaim.epochToProve);
|
|
129
|
+
this.latestEpochWeAreProving = proofClaim.epochToProve;
|
|
130
|
+
} catch (err) {
|
|
131
|
+
this.log.error(`Error handling claim for epoch ${proofClaim.epochToProve}`, err);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
// Staked amounts are lowered after a claim, so this is a good time for doing a top-up if needed
|
|
136
|
+
await this.bondManager.ensureBond();
|
|
137
|
+
} catch (err) {
|
|
138
|
+
this.log.error(`Error ensuring prover bond after handling claim for epoch ${proofClaim.epochToProve}`, err);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
105
142
|
/**
|
|
106
|
-
* Handles
|
|
143
|
+
* Handles the epoch number to prove when the prover node starts by checking if there
|
|
144
|
+
* is an existing claim for it. If not, it creates and sends a quote for it.
|
|
145
|
+
* @param epochNumber - The epoch immediately before the current one when the prover node starts.
|
|
146
|
+
*/
|
|
147
|
+
async handleInitialEpochSync(epochNumber: bigint): Promise<void> {
|
|
148
|
+
try {
|
|
149
|
+
const claim = await this.publisher.getProofClaim();
|
|
150
|
+
if (!claim || claim.epochToProve < epochNumber) {
|
|
151
|
+
this.log.verbose(`Handling epoch ${epochNumber} completed as initial sync`);
|
|
152
|
+
await this.handleEpochCompleted(epochNumber);
|
|
153
|
+
}
|
|
154
|
+
} catch (err) {
|
|
155
|
+
this.log.error(`Error handling initial epoch sync`, err);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Handles an epoch being completed by sending a quote for proving it.
|
|
107
161
|
* @param epochNumber - The epoch number that was just completed.
|
|
108
162
|
*/
|
|
109
163
|
async handleEpochCompleted(epochNumber: bigint): Promise<void> {
|
|
110
164
|
try {
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
165
|
+
// Gather data for the epoch
|
|
166
|
+
const epochData = await this.gatherEpochData(epochNumber);
|
|
167
|
+
const { blocks } = epochData;
|
|
168
|
+
this.cachedEpochData = { epochNumber, ...epochData };
|
|
169
|
+
|
|
170
|
+
// Construct a quote for the epoch
|
|
171
|
+
const partialQuote = await this.quoteProvider.getQuote(Number(epochNumber), blocks);
|
|
172
|
+
if (!partialQuote) {
|
|
173
|
+
this.log.info(`No quote produced for epoch ${epochNumber}`);
|
|
115
174
|
return;
|
|
116
175
|
}
|
|
117
|
-
|
|
118
|
-
|
|
176
|
+
|
|
177
|
+
// Ensure we have deposited enough funds for sending this quote
|
|
178
|
+
await this.bondManager.ensureBond(partialQuote.bondAmount);
|
|
179
|
+
|
|
180
|
+
// Assemble and sign full quote
|
|
181
|
+
const quote = EpochProofQuotePayload.from({
|
|
182
|
+
...partialQuote,
|
|
183
|
+
epochToProve: BigInt(epochNumber),
|
|
184
|
+
prover: this.publisher.getSenderAddress(),
|
|
185
|
+
validUntilSlot: partialQuote.validUntilSlot ?? BigInt(Number.MAX_SAFE_INTEGER), // Should we constrain this?
|
|
186
|
+
});
|
|
187
|
+
const signed = await this.quoteSigner.sign(quote);
|
|
188
|
+
|
|
189
|
+
// Send it to the coordinator
|
|
190
|
+
this.log.info(
|
|
191
|
+
`Sending quote for epoch ${epochNumber} with blocks ${blocks[0].number} to ${blocks.at(-1)!.number}`,
|
|
192
|
+
quote.toViemArgs(),
|
|
193
|
+
);
|
|
194
|
+
await this.doSendEpochProofQuote(signed);
|
|
119
195
|
} catch (err) {
|
|
120
196
|
if (err instanceof EmptyEpochError) {
|
|
121
|
-
this.log.info(`Not
|
|
197
|
+
this.log.info(`Not producing quote for ${epochNumber} since no blocks were found`);
|
|
122
198
|
} else {
|
|
123
199
|
this.log.error(`Error handling epoch completed`, err);
|
|
124
200
|
}
|
|
@@ -126,12 +202,15 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
|
|
|
126
202
|
}
|
|
127
203
|
|
|
128
204
|
/**
|
|
129
|
-
* Starts the prover node so it periodically checks for unproven epochs in the unfinalised chain from L1 and
|
|
130
|
-
* starts proving jobs
|
|
205
|
+
* Starts the prover node so it periodically checks for unproven epochs in the unfinalised chain from L1 and sends
|
|
206
|
+
* quotes for them, as well as monitors the claims for the epochs it has sent quotes for and starts proving jobs.
|
|
207
|
+
* This method returns once the prover node has deposited an initial bond into the escrow contract.
|
|
131
208
|
*/
|
|
132
|
-
start() {
|
|
209
|
+
async start() {
|
|
133
210
|
this.txFetcher.start();
|
|
211
|
+
await this.bondManager.ensureBond();
|
|
134
212
|
this.epochsMonitor.start(this);
|
|
213
|
+
this.claimsMonitor.start(this);
|
|
135
214
|
this.log.info('Started ProverNode', this.options);
|
|
136
215
|
}
|
|
137
216
|
|
|
@@ -142,6 +221,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
|
|
|
142
221
|
this.log.info('Stopping ProverNode');
|
|
143
222
|
await this.txFetcher.stop();
|
|
144
223
|
await this.epochsMonitor.stop();
|
|
224
|
+
await this.claimsMonitor.stop();
|
|
145
225
|
await this.prover.stop();
|
|
146
226
|
await tryStop(this.l2BlockSource);
|
|
147
227
|
this.publisher.interrupt();
|
|
@@ -152,6 +232,16 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
|
|
|
152
232
|
this.log.info('Stopped ProverNode');
|
|
153
233
|
}
|
|
154
234
|
|
|
235
|
+
/** Sends an epoch proof quote to the coordinator. */
|
|
236
|
+
public sendEpochProofQuote(quote: EpochProofQuote): Promise<void> {
|
|
237
|
+
this.log.info(`Sending quote for epoch`, quote.toViemArgs().quote);
|
|
238
|
+
return this.doSendEpochProofQuote(quote);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private doSendEpochProofQuote(quote: EpochProofQuote) {
|
|
242
|
+
return this.coordination.addEpochProofQuote(quote);
|
|
243
|
+
}
|
|
244
|
+
|
|
155
245
|
/**
|
|
156
246
|
* Creates a proof for a block range. Returns once the proof has been submitted to L1.
|
|
157
247
|
*/
|
|
@@ -178,22 +268,8 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
|
|
|
178
268
|
/**
|
|
179
269
|
* Returns an array of jobs being processed.
|
|
180
270
|
*/
|
|
181
|
-
public getJobs(): Promise<{ uuid: string; status: EpochProvingJobState
|
|
182
|
-
return Promise.resolve(
|
|
183
|
-
Array.from(this.jobs.entries()).map(([uuid, job]) => ({
|
|
184
|
-
uuid,
|
|
185
|
-
status: job.getState(),
|
|
186
|
-
epochNumber: Number(job.getEpochNumber()),
|
|
187
|
-
})),
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
protected async getActiveJobsForEpoch(
|
|
192
|
-
epochBigInt: bigint,
|
|
193
|
-
): Promise<{ uuid: string; status: EpochProvingJobState }[]> {
|
|
194
|
-
const jobs = await this.getJobs();
|
|
195
|
-
const epochNumber = Number(epochBigInt);
|
|
196
|
-
return jobs.filter(job => job.epochNumber === epochNumber && !EpochProvingJobTerminalState.includes(job.status));
|
|
271
|
+
public getJobs(): Promise<{ uuid: string; status: EpochProvingJobState }[]> {
|
|
272
|
+
return Promise.resolve(Array.from(this.jobs.entries()).map(([uuid, job]) => ({ uuid, status: job.getState() })));
|
|
197
273
|
}
|
|
198
274
|
|
|
199
275
|
private checkMaximumPendingJobs() {
|
|
@@ -322,6 +398,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
|
|
|
322
398
|
/** Extracted for testing purposes. */
|
|
323
399
|
protected async triggerMonitors() {
|
|
324
400
|
await this.epochsMonitor.work();
|
|
401
|
+
await this.claimsMonitor.work();
|
|
325
402
|
}
|
|
326
403
|
}
|
|
327
404
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type L2Block } from '@aztec/circuit-types';
|
|
2
|
+
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
3
|
+
|
|
4
|
+
import { type QuoteProvider, type QuoteProviderResult } from './index.js';
|
|
5
|
+
import { getTotalFees, getTxCount } from './utils.js';
|
|
6
|
+
|
|
7
|
+
export class HttpQuoteProvider implements QuoteProvider {
|
|
8
|
+
constructor(private readonly url: string) {}
|
|
9
|
+
|
|
10
|
+
public async getQuote(epochNumber: number, epoch: L2Block[]): Promise<QuoteProviderResult | undefined> {
|
|
11
|
+
const payload: HttpQuoteRequestPayload = {
|
|
12
|
+
epochNumber,
|
|
13
|
+
fromBlock: epoch[0].number,
|
|
14
|
+
toBlock: epoch.at(-1)!.number,
|
|
15
|
+
totalFees: getTotalFees(epoch).toString(),
|
|
16
|
+
txCount: getTxCount(epoch),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const response = await fetch(this.url, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
body: jsonStringify(payload),
|
|
22
|
+
headers: { 'content-type': 'application/json' },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`Failed to fetch quote: ${response.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
if (!data.basisPointFee || !data.bondAmount) {
|
|
31
|
+
throw new Error(`Missing required fields (basisPointFee | bondAmount) in response: ${jsonStringify(data)}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const basisPointFee = Number(data.basisPointFee);
|
|
35
|
+
const bondAmount = BigInt(data.bondAmount);
|
|
36
|
+
const validUntilSlot = data.validUntilSlot ? BigInt(data.validUntilSlot) : undefined;
|
|
37
|
+
|
|
38
|
+
return { basisPointFee, bondAmount, validUntilSlot };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type HttpQuoteRequestPayload = {
|
|
43
|
+
epochNumber: number;
|
|
44
|
+
fromBlock: number;
|
|
45
|
+
toBlock: number;
|
|
46
|
+
totalFees: string;
|
|
47
|
+
txCount: number;
|
|
48
|
+
};
|
|
@@ -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
|
+
}
|