@aztec/prover-client 0.0.1-commit.ee80a48 → 0.0.1-commit.ef17749e1
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/light/lightweight_checkpoint_builder.d.ts +10 -5
- package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -1
- package/dest/light/lightweight_checkpoint_builder.js +37 -18
- package/dest/mocks/test_context.js +5 -2
- package/dest/orchestrator/block-building-helpers.d.ts +4 -4
- package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
- package/dest/orchestrator/block-building-helpers.js +2 -2
- package/dest/orchestrator/block-proving-state.d.ts +4 -1
- package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/block-proving-state.js +7 -0
- package/dest/orchestrator/checkpoint-proving-state.d.ts +3 -3
- package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/checkpoint-proving-state.js +3 -3
- package/dest/orchestrator/epoch-proving-state.d.ts +3 -3
- package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/epoch-proving-state.js +5 -3
- package/dest/orchestrator/orchestrator.d.ts +2 -2
- package/dest/orchestrator/orchestrator.d.ts.map +1 -1
- package/dest/orchestrator/orchestrator.js +43 -52
- package/dest/prover-client/prover-client.d.ts +3 -3
- package/dest/prover-client/prover-client.d.ts.map +1 -1
- package/dest/prover-client/prover-client.js +8 -6
- package/dest/proving_broker/config.d.ts +10 -2
- package/dest/proving_broker/config.d.ts.map +1 -1
- package/dest/proving_broker/config.js +14 -3
- package/dest/proving_broker/proof_store/factory.d.ts +2 -5
- package/dest/proving_broker/proof_store/factory.d.ts.map +1 -1
- package/dest/proving_broker/proof_store/factory.js +7 -30
- package/dest/proving_broker/proof_store/file_store_proof_store.d.ts +18 -0
- package/dest/proving_broker/proof_store/file_store_proof_store.d.ts.map +1 -0
- package/dest/proving_broker/proof_store/file_store_proof_store.js +60 -0
- package/dest/proving_broker/proof_store/index.d.ts +2 -2
- package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
- package/dest/proving_broker/proof_store/index.js +1 -1
- package/dest/proving_broker/proving_broker.d.ts +7 -4
- package/dest/proving_broker/proving_broker.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker.js +36 -4
- package/dest/proving_broker/proving_broker_instrumentation.d.ts +3 -1
- package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker_instrumentation.js +7 -0
- package/dest/proving_broker/rpc.d.ts +4 -2
- package/dest/proving_broker/rpc.d.ts.map +1 -1
- package/dest/proving_broker/rpc.js +8 -0
- package/dest/test/mock_prover.d.ts +4 -4
- package/package.json +17 -18
- package/src/light/lightweight_checkpoint_builder.ts +35 -19
- package/src/mocks/test_context.ts +2 -2
- package/src/orchestrator/block-building-helpers.ts +2 -2
- package/src/orchestrator/block-proving-state.ts +9 -0
- package/src/orchestrator/checkpoint-proving-state.ts +4 -4
- package/src/orchestrator/epoch-proving-state.ts +6 -4
- package/src/orchestrator/orchestrator.ts +53 -59
- package/src/prover-client/prover-client.ts +6 -8
- package/src/proving_broker/config.ts +14 -1
- package/src/proving_broker/proof_store/factory.ts +10 -32
- package/src/proving_broker/proof_store/file_store_proof_store.ts +78 -0
- package/src/proving_broker/proof_store/index.ts +1 -1
- package/src/proving_broker/proving_broker.ts +37 -3
- package/src/proving_broker/proving_broker_instrumentation.ts +9 -0
- package/src/proving_broker/rpc.ts +14 -0
- package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +0 -14
- package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +0 -1
- package/dest/proving_broker/proof_store/gcs_proof_store.js +0 -52
- package/src/proving_broker/proof_store/gcs_proof_store.ts +0 -76
|
@@ -76,7 +76,7 @@ export class EpochProvingState {
|
|
|
76
76
|
public readonly epochNumber: EpochNumber,
|
|
77
77
|
public readonly totalNumCheckpoints: number,
|
|
78
78
|
private readonly finalBlobBatchingChallenges: FinalBlobBatchingChallenges,
|
|
79
|
-
private onCheckpointBlobAccumulatorSet: (checkpoint: CheckpointProvingState) => void
|
|
79
|
+
private onCheckpointBlobAccumulatorSet: (checkpoint: CheckpointProvingState) => Promise<void>,
|
|
80
80
|
private completionCallback: (result: ProvingResult) => void,
|
|
81
81
|
private rejectionCallback: (reason: string) => void,
|
|
82
82
|
) {
|
|
@@ -254,9 +254,11 @@ export class EpochProvingState {
|
|
|
254
254
|
}
|
|
255
255
|
outHashes.push(outHash);
|
|
256
256
|
|
|
257
|
-
//
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
// If this is NOT the last checkpoint, get or create the hint for the next checkpoint.
|
|
258
|
+
if (i !== this.totalNumCheckpoints - 1) {
|
|
259
|
+
hint = checkpoint.getOutHashHintForNextCheckpoint() ?? (await computeOutHashHint(outHashes));
|
|
260
|
+
checkpoint.setOutHashHintForNextCheckpoint(hint);
|
|
261
|
+
}
|
|
260
262
|
}
|
|
261
263
|
}
|
|
262
264
|
|
|
@@ -71,11 +71,6 @@ import { EpochProvingState, type ProvingResult, type TreeSnapshots } from './epo
|
|
|
71
71
|
import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
|
|
72
72
|
import { TxProvingState } from './tx-proving-state.js';
|
|
73
73
|
|
|
74
|
-
type WorldStateFork = {
|
|
75
|
-
fork: MerkleTreeWriteOperations;
|
|
76
|
-
cleanupPromise: Promise<void> | undefined;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
74
|
/**
|
|
80
75
|
* Implements an event driven proving scheduler to build the recursive proof tree. The idea being:
|
|
81
76
|
* 1. Transactions are provided to the scheduler post simulation.
|
|
@@ -97,7 +92,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
97
92
|
private provingPromise: Promise<ProvingResult> | undefined = undefined;
|
|
98
93
|
private metrics: ProvingOrchestratorMetrics;
|
|
99
94
|
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
100
|
-
private dbs: Map<BlockNumber,
|
|
95
|
+
private dbs: Map<BlockNumber, MerkleTreeWriteOperations> = new Map();
|
|
101
96
|
private logger: Logger;
|
|
102
97
|
|
|
103
98
|
constructor(
|
|
@@ -182,7 +177,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
182
177
|
const db = await this.dbProvider.fork(lastBlockNumber);
|
|
183
178
|
|
|
184
179
|
const firstBlockNumber = BlockNumber(lastBlockNumber + 1);
|
|
185
|
-
this.dbs.set(firstBlockNumber,
|
|
180
|
+
this.dbs.set(firstBlockNumber, db);
|
|
186
181
|
|
|
187
182
|
// Get archive sibling path before any block in this checkpoint lands.
|
|
188
183
|
const lastArchiveSiblingPath = await getLastSiblingPath(MerkleTreeId.ARCHIVE, db);
|
|
@@ -240,9 +235,9 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
240
235
|
if (!this.dbs.has(blockNumber)) {
|
|
241
236
|
// Fork world state at the end of the immediately previous block
|
|
242
237
|
const db = await this.dbProvider.fork(BlockNumber(blockNumber - 1));
|
|
243
|
-
this.dbs.set(blockNumber,
|
|
238
|
+
this.dbs.set(blockNumber, db);
|
|
244
239
|
}
|
|
245
|
-
const db = this.
|
|
240
|
+
const db = this.getDbForBlock(blockNumber);
|
|
246
241
|
|
|
247
242
|
// Get archive snapshot and sibling path before any txs in this block lands.
|
|
248
243
|
const lastArchiveTreeSnapshot = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
|
|
@@ -317,7 +312,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
317
312
|
|
|
318
313
|
this.logger.info(`Adding ${txs.length} transactions to block ${blockNumber}`);
|
|
319
314
|
|
|
320
|
-
const db = this.
|
|
315
|
+
const db = this.getDbForBlock(blockNumber);
|
|
321
316
|
const lastArchive = provingState.lastArchiveTreeSnapshot;
|
|
322
317
|
const newL1ToL2MessageTreeSnapshot = provingState.newL1ToL2MessageTreeSnapshot;
|
|
323
318
|
const spongeBlobState = provingState.getStartSpongeBlob().clone();
|
|
@@ -445,14 +440,20 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
445
440
|
throw new Error('Block header mismatch');
|
|
446
441
|
}
|
|
447
442
|
|
|
448
|
-
// Get db for this block
|
|
449
|
-
const db = this.
|
|
443
|
+
// Get db for this block and remove from map — no other code should use it after this point.
|
|
444
|
+
const db = this.getDbForBlock(provingState.blockNumber);
|
|
445
|
+
this.dbs.delete(provingState.blockNumber);
|
|
450
446
|
|
|
451
|
-
// Update the archive tree,
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
447
|
+
// Update the archive tree, capture the snapshot, and close the fork deterministically.
|
|
448
|
+
try {
|
|
449
|
+
this.logger.verbose(
|
|
450
|
+
`Updating archive tree with block ${provingState.blockNumber} header ${(await header.hash()).toString()}`,
|
|
451
|
+
);
|
|
452
|
+
await db.updateArchive(header);
|
|
453
|
+
provingState.setBuiltArchive(await getTreeSnapshot(MerkleTreeId.ARCHIVE, db));
|
|
454
|
+
} finally {
|
|
455
|
+
await db.close();
|
|
456
|
+
}
|
|
456
457
|
|
|
457
458
|
await this.verifyBuiltBlockAgainstSyncedState(provingState);
|
|
458
459
|
|
|
@@ -472,6 +473,13 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
472
473
|
this.logger.debug('Block root rollup proof not built yet, skipping header check.');
|
|
473
474
|
return;
|
|
474
475
|
}
|
|
476
|
+
|
|
477
|
+
const newArchive = provingState.getBuiltArchive();
|
|
478
|
+
if (!newArchive) {
|
|
479
|
+
this.logger.debug('Archive snapshot not yet captured, skipping header check.');
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
475
483
|
const header = await buildHeaderFromCircuitOutputs(output);
|
|
476
484
|
|
|
477
485
|
if (!(await header.hash()).equals(await builtBlockHeader.hash())) {
|
|
@@ -480,11 +488,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
480
488
|
return;
|
|
481
489
|
}
|
|
482
490
|
|
|
483
|
-
// Get db for this block
|
|
484
491
|
const blockNumber = provingState.blockNumber;
|
|
485
|
-
const db = this.dbs.get(blockNumber)!.fork;
|
|
486
|
-
|
|
487
|
-
const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
|
|
488
492
|
const syncedArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.dbProvider.getSnapshot(blockNumber));
|
|
489
493
|
if (!syncedArchive.equals(newArchive)) {
|
|
490
494
|
this.logger.error(
|
|
@@ -502,12 +506,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
502
506
|
provingState.reject(`New archive mismatch.`);
|
|
503
507
|
return;
|
|
504
508
|
}
|
|
505
|
-
|
|
506
|
-
// TODO(palla/prover): This closes the fork only on the happy path. If this epoch orchestrator
|
|
507
|
-
// is aborted and never reaches this point, it will leak the fork. We need to add a global cleanup,
|
|
508
|
-
// but have to make sure it only runs once all operations are completed, otherwise some function here
|
|
509
|
-
// will attempt to access the fork after it was closed.
|
|
510
|
-
void this.cleanupDBFork(blockNumber);
|
|
511
509
|
}
|
|
512
510
|
|
|
513
511
|
/**
|
|
@@ -523,6 +521,19 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
523
521
|
}
|
|
524
522
|
|
|
525
523
|
this.provingState?.cancel();
|
|
524
|
+
|
|
525
|
+
for (const [blockNumber, db] of this.dbs.entries()) {
|
|
526
|
+
void db.close().catch(err => this.logger.error(`Error closing db for block ${blockNumber}`, err));
|
|
527
|
+
}
|
|
528
|
+
this.dbs.clear();
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
private getDbForBlock(blockNumber: BlockNumber): MerkleTreeWriteOperations {
|
|
532
|
+
const db = this.dbs.get(blockNumber);
|
|
533
|
+
if (!db) {
|
|
534
|
+
throw new Error(`World state fork for block ${blockNumber} not found.`);
|
|
535
|
+
}
|
|
536
|
+
return db;
|
|
526
537
|
}
|
|
527
538
|
|
|
528
539
|
/**
|
|
@@ -554,24 +565,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
554
565
|
return epochProofResult;
|
|
555
566
|
}
|
|
556
567
|
|
|
557
|
-
private async cleanupDBFork(blockNumber: BlockNumber): Promise<void> {
|
|
558
|
-
this.logger.debug(`Cleaning up world state fork for ${blockNumber}`);
|
|
559
|
-
const fork = this.dbs.get(blockNumber);
|
|
560
|
-
if (!fork) {
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
try {
|
|
565
|
-
if (!fork.cleanupPromise) {
|
|
566
|
-
fork.cleanupPromise = fork.fork.close();
|
|
567
|
-
}
|
|
568
|
-
await fork.cleanupPromise;
|
|
569
|
-
this.dbs.delete(blockNumber);
|
|
570
|
-
} catch (err) {
|
|
571
|
-
this.logger.error(`Error closing db for block ${blockNumber}`, err);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
568
|
/**
|
|
576
569
|
* Enqueue a job to be scheduled
|
|
577
570
|
* @param provingState - The proving state object being operated on
|
|
@@ -894,17 +887,15 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
894
887
|
const leafLocation = provingState.setBlockRootRollupProof(result);
|
|
895
888
|
const checkpointProvingState = provingState.parentCheckpoint;
|
|
896
889
|
|
|
897
|
-
//
|
|
890
|
+
// Verification is called from both here and setBlockCompleted. Whichever runs last
|
|
891
|
+
// will be the first to see all three pieces (header, proof output, archive) and run the checks.
|
|
898
892
|
await this.verifyBuiltBlockAgainstSyncedState(provingState);
|
|
899
893
|
|
|
900
894
|
if (checkpointProvingState.totalNumBlocks === 1) {
|
|
901
|
-
this.checkAndEnqueueCheckpointRootRollup(checkpointProvingState);
|
|
895
|
+
await this.checkAndEnqueueCheckpointRootRollup(checkpointProvingState);
|
|
902
896
|
} else {
|
|
903
|
-
this.checkAndEnqueueNextBlockMergeRollup(checkpointProvingState, leafLocation);
|
|
897
|
+
await this.checkAndEnqueueNextBlockMergeRollup(checkpointProvingState, leafLocation);
|
|
904
898
|
}
|
|
905
|
-
|
|
906
|
-
// We are finished with the block at this point, ensure the fork is cleaned up
|
|
907
|
-
void this.cleanupDBFork(provingState.blockNumber);
|
|
908
899
|
},
|
|
909
900
|
);
|
|
910
901
|
}
|
|
@@ -1009,14 +1000,14 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1009
1000
|
},
|
|
1010
1001
|
signal => this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber),
|
|
1011
1002
|
),
|
|
1012
|
-
result => {
|
|
1003
|
+
async result => {
|
|
1013
1004
|
provingState.setBlockMergeRollupProof(location, result);
|
|
1014
|
-
this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
|
|
1005
|
+
await this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
|
|
1015
1006
|
},
|
|
1016
1007
|
);
|
|
1017
1008
|
}
|
|
1018
1009
|
|
|
1019
|
-
private enqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
|
|
1010
|
+
private async enqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
|
|
1020
1011
|
if (!provingState.verifyState()) {
|
|
1021
1012
|
this.logger.debug('Not running checkpoint root rollup. State no longer valid.');
|
|
1022
1013
|
return;
|
|
@@ -1031,7 +1022,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1031
1022
|
|
|
1032
1023
|
this.logger.debug(`Enqueuing ${rollupType} for checkpoint ${provingState.index}.`);
|
|
1033
1024
|
|
|
1034
|
-
const inputs = provingState.getCheckpointRootRollupInputs();
|
|
1025
|
+
const inputs = await provingState.getCheckpointRootRollupInputs();
|
|
1035
1026
|
|
|
1036
1027
|
this.deferredProving(
|
|
1037
1028
|
provingState,
|
|
@@ -1191,25 +1182,28 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1191
1182
|
this.enqueueBlockRootRollup(provingState);
|
|
1192
1183
|
}
|
|
1193
1184
|
|
|
1194
|
-
private checkAndEnqueueNextBlockMergeRollup(
|
|
1185
|
+
private async checkAndEnqueueNextBlockMergeRollup(
|
|
1186
|
+
provingState: CheckpointProvingState,
|
|
1187
|
+
currentLocation: TreeNodeLocation,
|
|
1188
|
+
) {
|
|
1195
1189
|
if (!provingState.isReadyForBlockMerge(currentLocation)) {
|
|
1196
1190
|
return;
|
|
1197
1191
|
}
|
|
1198
1192
|
|
|
1199
1193
|
const parentLocation = provingState.getParentLocation(currentLocation);
|
|
1200
1194
|
if (parentLocation.level === 0) {
|
|
1201
|
-
this.checkAndEnqueueCheckpointRootRollup(provingState);
|
|
1195
|
+
await this.checkAndEnqueueCheckpointRootRollup(provingState);
|
|
1202
1196
|
} else {
|
|
1203
1197
|
this.enqueueBlockMergeRollup(provingState, parentLocation);
|
|
1204
1198
|
}
|
|
1205
1199
|
}
|
|
1206
1200
|
|
|
1207
|
-
private checkAndEnqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
|
|
1201
|
+
private async checkAndEnqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
|
|
1208
1202
|
if (!provingState.isReadyForCheckpointRoot()) {
|
|
1209
1203
|
return;
|
|
1210
1204
|
}
|
|
1211
1205
|
|
|
1212
|
-
this.enqueueCheckpointRootRollup(provingState);
|
|
1206
|
+
await this.enqueueCheckpointRootRollup(provingState);
|
|
1213
1207
|
}
|
|
1214
1208
|
|
|
1215
1209
|
private checkAndEnqueueNextCheckpointMergeRollup(provingState: EpochProvingState, currentLocation: TreeNodeLocation) {
|
|
@@ -29,20 +29,16 @@ export class ProverClient implements EpochProverManager {
|
|
|
29
29
|
private running = false;
|
|
30
30
|
private agents: ProvingAgent[] = [];
|
|
31
31
|
|
|
32
|
-
private proofStore: ProofStore;
|
|
33
|
-
private failedProofStore: ProofStore | undefined;
|
|
34
|
-
|
|
35
32
|
private constructor(
|
|
36
33
|
private config: ProverClientConfig,
|
|
37
34
|
private worldState: ForkMerkleTreeOperations & ReadonlyWorldStateAccess,
|
|
38
35
|
private orchestratorClient: ProvingJobProducer,
|
|
36
|
+
private proofStore: ProofStore,
|
|
37
|
+
private failedProofStore: ProofStore | undefined,
|
|
39
38
|
private agentClient?: ProvingJobConsumer,
|
|
40
39
|
private telemetry: TelemetryClient = getTelemetryClient(),
|
|
41
40
|
private log: Logger = createLogger('prover-client:tx-prover'),
|
|
42
|
-
) {
|
|
43
|
-
this.proofStore = new InlineProofStore();
|
|
44
|
-
this.failedProofStore = this.config.failedProofStore ? createProofStore(this.config.failedProofStore) : undefined;
|
|
45
|
-
}
|
|
41
|
+
) {}
|
|
46
42
|
|
|
47
43
|
public createEpochProver(): EpochProver {
|
|
48
44
|
const bindings = this.log.getBindings();
|
|
@@ -118,7 +114,9 @@ export class ProverClient implements EpochProverManager {
|
|
|
118
114
|
broker: ProvingJobBroker,
|
|
119
115
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
120
116
|
) {
|
|
121
|
-
const
|
|
117
|
+
const proofStore = await createProofStore(config.proofStore);
|
|
118
|
+
const failedProofStore = config.failedProofStore ? await createProofStore(config.failedProofStore) : undefined;
|
|
119
|
+
const prover = new ProverClient(config, worldState, broker, proofStore, failedProofStore, broker, telemetry);
|
|
122
120
|
await prover.start();
|
|
123
121
|
return prover;
|
|
124
122
|
}
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
numberConfigHelper,
|
|
7
7
|
} from '@aztec/foundation/config';
|
|
8
8
|
import { pickConfigMappings } from '@aztec/foundation/config';
|
|
9
|
-
import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';
|
|
10
9
|
import { type ChainConfig, chainConfigMappings } from '@aztec/stdlib/config';
|
|
10
|
+
import { type DataStoreConfig, dataConfigMappings } from '@aztec/stdlib/kv-store';
|
|
11
11
|
import { ProvingRequestType } from '@aztec/stdlib/proofs';
|
|
12
12
|
|
|
13
13
|
import { z } from 'zod';
|
|
@@ -31,6 +31,8 @@ export const ProverBrokerConfig = z.object({
|
|
|
31
31
|
proverBrokerBatchIntervalMs: z.number().int().nonnegative(),
|
|
32
32
|
/** The maximum number of epochs to keep results for */
|
|
33
33
|
proverBrokerMaxEpochsToKeepResultsFor: z.number().int().nonnegative(),
|
|
34
|
+
/** Enable debug replay mode for replaying proving jobs from stored inputs */
|
|
35
|
+
proverBrokerDebugReplayEnabled: z.boolean(),
|
|
34
36
|
});
|
|
35
37
|
|
|
36
38
|
export type ProverBrokerConfig = z.infer<typeof ProverBrokerConfig> &
|
|
@@ -74,6 +76,11 @@ export const proverBrokerConfigMappings: ConfigMappingsType<ProverBrokerConfig>
|
|
|
74
76
|
parseEnv: (val: string | undefined) => (val ? +val : undefined),
|
|
75
77
|
description: "The size of the prover broker's database. Will override the dataStoreMapSizeKb if set.",
|
|
76
78
|
},
|
|
79
|
+
proverBrokerDebugReplayEnabled: {
|
|
80
|
+
env: 'PROVER_BROKER_DEBUG_REPLAY_ENABLED',
|
|
81
|
+
description: 'Enable debug replay mode for replaying proving jobs from stored inputs',
|
|
82
|
+
...booleanConfigHelper(false),
|
|
83
|
+
},
|
|
77
84
|
...dataConfigMappings,
|
|
78
85
|
...l1ReaderConfigMappings,
|
|
79
86
|
...pickConfigMappings(chainConfigMappings, ['rollupVersion']),
|
|
@@ -102,6 +109,8 @@ export const ProverAgentConfig = z.object({
|
|
|
102
109
|
proverTestVerificationDelayMs: z.number().optional(),
|
|
103
110
|
/** Whether to abort pending proving jobs when the orchestrator is cancelled */
|
|
104
111
|
cancelJobsOnStop: z.boolean(),
|
|
112
|
+
/** Where to store proving results. Must be accessible to both prover node and agents. If not set will inline-encode the parameters */
|
|
113
|
+
proofStore: z.string().optional(),
|
|
105
114
|
});
|
|
106
115
|
|
|
107
116
|
export type ProverAgentConfig = z.infer<typeof ProverAgentConfig>;
|
|
@@ -162,4 +171,8 @@ export const proverAgentConfigMappings: ConfigMappingsType<ProverAgentConfig> =
|
|
|
162
171
|
'When false (default), jobs remain in the broker queue and can be reused on restart/reorg.',
|
|
163
172
|
...booleanConfigHelper(false),
|
|
164
173
|
},
|
|
174
|
+
proofStore: {
|
|
175
|
+
env: 'PROVER_PROOF_STORE',
|
|
176
|
+
description: 'Optional proof input store for the prover',
|
|
177
|
+
},
|
|
165
178
|
};
|
|
@@ -1,42 +1,20 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import { createFileStore } from '@aztec/stdlib/file-store';
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
+
import { FileStoreProofStore } from './file_store_proof_store.js';
|
|
4
5
|
import { InlineProofStore } from './inline_proof_store.js';
|
|
5
6
|
import type { ProofStore } from './proof_store.js';
|
|
6
7
|
|
|
7
|
-
export function createProofStore(
|
|
8
|
-
|
|
8
|
+
export async function createProofStore(
|
|
9
|
+
config: string | undefined,
|
|
10
|
+
logger = createLogger('prover-client:proof-store'),
|
|
11
|
+
): Promise<ProofStore> {
|
|
12
|
+
if (!config) {
|
|
9
13
|
logger.info('Creating inline proof store');
|
|
10
14
|
return new InlineProofStore();
|
|
11
|
-
} else if (config.startsWith('gs://')) {
|
|
12
|
-
try {
|
|
13
|
-
const url = new URL(config);
|
|
14
|
-
const bucket = url.host;
|
|
15
|
-
const path = url.pathname.replace(/^\/+/, '');
|
|
16
|
-
logger.info(`Creating google cloud proof store at ${bucket}`, { bucket, path });
|
|
17
|
-
return new GoogleCloudStorageProofStore(bucket, path);
|
|
18
|
-
} catch {
|
|
19
|
-
throw new Error(
|
|
20
|
-
`Invalid google cloud proof store definition: '${config}'. Supported values are 'gs://bucket-name/path/to/store'.`,
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
} else {
|
|
24
|
-
throw new Error(`Unknown proof store config: '${config}'. Supported values are 'gs://bucket-name/path/to/store'.`);
|
|
25
15
|
}
|
|
26
|
-
}
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
): Pick<ProofStore, 'getProofInput' | 'getProofOutput'> {
|
|
32
|
-
if (uri.startsWith('data://')) {
|
|
33
|
-
return createProofStore(undefined, logger);
|
|
34
|
-
} else if (uri.startsWith('gs://')) {
|
|
35
|
-
const url = new URL(uri);
|
|
36
|
-
const basePath = url.pathname.replace(/^\/+/, '').split('/').slice(0, -3);
|
|
37
|
-
url.pathname = basePath.join('/');
|
|
38
|
-
return createProofStore(uri, logger);
|
|
39
|
-
} else {
|
|
40
|
-
throw new Error(`Unknown proof store config: '${uri}'. Supported protocols are 'data://' and 'gs://'.`);
|
|
41
|
-
}
|
|
17
|
+
const fileStore = await createFileStore(config, logger);
|
|
18
|
+
logger.info(`Creating file store proof store at ${config}`);
|
|
19
|
+
return new FileStoreProofStore(fileStore);
|
|
42
20
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
|
|
2
|
+
import type { FileStore } from '@aztec/stdlib/file-store';
|
|
3
|
+
import {
|
|
4
|
+
type ProofUri,
|
|
5
|
+
type ProvingJobId,
|
|
6
|
+
type ProvingJobInputs,
|
|
7
|
+
type ProvingJobInputsMap,
|
|
8
|
+
ProvingJobResult,
|
|
9
|
+
type ProvingJobResultsMap,
|
|
10
|
+
getProvingJobInputClassFor,
|
|
11
|
+
} from '@aztec/stdlib/interfaces/server';
|
|
12
|
+
import { ProvingRequestType } from '@aztec/stdlib/proofs';
|
|
13
|
+
|
|
14
|
+
import type { ProofStore } from './proof_store.js';
|
|
15
|
+
|
|
16
|
+
const INPUTS_PATH = 'inputs';
|
|
17
|
+
const OUTPUTS_PATH = 'outputs';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A proof store implementation backed by a generic FileStore.
|
|
21
|
+
* Supports any storage backend (GCS, S3, local filesystem) via the FileStore abstraction.
|
|
22
|
+
*/
|
|
23
|
+
export class FileStoreProofStore implements ProofStore {
|
|
24
|
+
constructor(private readonly fileStore: FileStore) {}
|
|
25
|
+
|
|
26
|
+
async saveProofInput<T extends ProvingRequestType>(
|
|
27
|
+
id: ProvingJobId,
|
|
28
|
+
type: T,
|
|
29
|
+
inputs: ProvingJobInputsMap[T],
|
|
30
|
+
): Promise<ProofUri> {
|
|
31
|
+
const path = `${INPUTS_PATH}/${ProvingRequestType[type]}/${id}`;
|
|
32
|
+
const uri = await this.fileStore.save(path, inputs.toBuffer());
|
|
33
|
+
return uri as ProofUri;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async saveProofOutput<T extends ProvingRequestType>(
|
|
37
|
+
id: ProvingJobId,
|
|
38
|
+
type: T,
|
|
39
|
+
result: ProvingJobResultsMap[T],
|
|
40
|
+
): Promise<ProofUri> {
|
|
41
|
+
const jobResult = { type, result } as ProvingJobResult;
|
|
42
|
+
const json = jsonStringify(jobResult);
|
|
43
|
+
const path = `${OUTPUTS_PATH}/${ProvingRequestType[type]}/${id}.json`;
|
|
44
|
+
const uri = await this.fileStore.save(path, Buffer.from(json, 'utf-8'));
|
|
45
|
+
return uri as ProofUri;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async getProofInput(uri: ProofUri): Promise<ProvingJobInputs> {
|
|
49
|
+
try {
|
|
50
|
+
const buffer = await this.fileStore.read(uri);
|
|
51
|
+
const type = this.extractTypeFromUri(uri);
|
|
52
|
+
const inputs = getProvingJobInputClassFor(type).fromBuffer(buffer);
|
|
53
|
+
return { inputs, type } as ProvingJobInputs;
|
|
54
|
+
} catch (err) {
|
|
55
|
+
throw new Error(`Error getting proof input at ${uri}: ${err}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async getProofOutput(uri: ProofUri): Promise<ProvingJobResult> {
|
|
60
|
+
try {
|
|
61
|
+
const buffer = await this.fileStore.read(uri);
|
|
62
|
+
return jsonParseWithSchema(buffer.toString('utf-8'), ProvingJobResult);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
throw new Error(`Error getting proof output at ${uri}: ${err}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private extractTypeFromUri(uri: string): ProvingRequestType {
|
|
69
|
+
const url = new URL(uri);
|
|
70
|
+
const pathParts = url.pathname.split('/').filter(Boolean);
|
|
71
|
+
const typeString = pathParts.at(-2);
|
|
72
|
+
const type = typeString ? ProvingRequestType[typeString as keyof typeof ProvingRequestType] : undefined;
|
|
73
|
+
if (type === undefined) {
|
|
74
|
+
throw new Error(`Unrecognized proof type ${typeString} in URI ${uri}`);
|
|
75
|
+
}
|
|
76
|
+
return type;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type GetProvingJobResponse,
|
|
8
8
|
type ProofUri,
|
|
9
9
|
type ProvingJob,
|
|
10
|
+
type ProvingJobBrokerDebug,
|
|
10
11
|
type ProvingJobConsumer,
|
|
11
12
|
type ProvingJobFilter,
|
|
12
13
|
type ProvingJobId,
|
|
@@ -36,7 +37,7 @@ type EnqueuedProvingJob = Pick<ProvingJob, 'id' | 'epochNumber'>;
|
|
|
36
37
|
* A broker that manages proof requests and distributes them to workers based on their priority.
|
|
37
38
|
* It takes a backend that is responsible for storing and retrieving proof requests and results.
|
|
38
39
|
*/
|
|
39
|
-
export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Traceable {
|
|
40
|
+
export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, ProvingJobBrokerDebug, Traceable {
|
|
40
41
|
private queues: ProvingQueues = {
|
|
41
42
|
[ProvingRequestType.PUBLIC_VM]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
42
43
|
[ProvingRequestType.PUBLIC_CHONK_VERIFIER]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
@@ -114,6 +115,8 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
114
115
|
|
|
115
116
|
private started = false;
|
|
116
117
|
|
|
118
|
+
private debugReplayEnabled: boolean;
|
|
119
|
+
|
|
117
120
|
public constructor(
|
|
118
121
|
private database: ProvingBrokerDatabase,
|
|
119
122
|
{
|
|
@@ -121,6 +124,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
121
124
|
proverBrokerPollIntervalMs,
|
|
122
125
|
proverBrokerJobMaxRetries,
|
|
123
126
|
proverBrokerMaxEpochsToKeepResultsFor,
|
|
127
|
+
proverBrokerDebugReplayEnabled,
|
|
124
128
|
}: Required<
|
|
125
129
|
Pick<
|
|
126
130
|
ProverBrokerConfig,
|
|
@@ -128,6 +132,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
128
132
|
| 'proverBrokerPollIntervalMs'
|
|
129
133
|
| 'proverBrokerJobMaxRetries'
|
|
130
134
|
| 'proverBrokerMaxEpochsToKeepResultsFor'
|
|
135
|
+
| 'proverBrokerDebugReplayEnabled'
|
|
131
136
|
>
|
|
132
137
|
> = defaultProverBrokerConfig,
|
|
133
138
|
client: TelemetryClient = getTelemetryClient(),
|
|
@@ -139,6 +144,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
139
144
|
this.jobTimeoutMs = proverBrokerJobTimeoutMs!;
|
|
140
145
|
this.maxRetries = proverBrokerJobMaxRetries!;
|
|
141
146
|
this.maxEpochsToKeepResultsFor = proverBrokerMaxEpochsToKeepResultsFor!;
|
|
147
|
+
this.debugReplayEnabled = proverBrokerDebugReplayEnabled ?? false;
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
private measureQueueDepth: MonitorCallback = (type: ProvingRequestType) => {
|
|
@@ -241,6 +247,29 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
241
247
|
return Promise.resolve(this.#reportProvingJobProgress(id, startedAt, filter));
|
|
242
248
|
}
|
|
243
249
|
|
|
250
|
+
public async replayProvingJob(
|
|
251
|
+
jobId: ProvingJobId,
|
|
252
|
+
type: ProvingRequestType,
|
|
253
|
+
epochNumber: EpochNumber,
|
|
254
|
+
inputsUri: ProofUri,
|
|
255
|
+
): Promise<ProvingJobStatus> {
|
|
256
|
+
if (!this.debugReplayEnabled) {
|
|
257
|
+
throw new Error('Debug replay not enabled. Set PROVER_BROKER_DEBUG_REPLAY_ENABLED=true');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this.logger.info(`Replaying proving job`, { provingJobId: jobId, epochNumber, inputsUri });
|
|
261
|
+
|
|
262
|
+
// Clear existing state and enqueue
|
|
263
|
+
this.cleanUpProvingJobState([jobId]);
|
|
264
|
+
|
|
265
|
+
const job: ProvingJob = { id: jobId, type, epochNumber, inputsUri };
|
|
266
|
+
this.jobsCache.set(jobId, job);
|
|
267
|
+
await this.database.addProvingJob(job);
|
|
268
|
+
this.enqueueJobInternal(job);
|
|
269
|
+
|
|
270
|
+
return { status: 'in-queue' };
|
|
271
|
+
}
|
|
272
|
+
|
|
244
273
|
async #enqueueProvingJob(job: ProvingJob): Promise<ProvingJobStatus> {
|
|
245
274
|
// We return the job status at the start of this call
|
|
246
275
|
const jobStatus = this.#getProvingJobStatus(job.id);
|
|
@@ -285,7 +314,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
285
314
|
// notify listeners of the cancellation
|
|
286
315
|
if (!this.resultsCache.has(id)) {
|
|
287
316
|
this.logger.info(`Cancelling job id=${id}`, { provingJobId: id });
|
|
288
|
-
await this.#reportProvingJobError(id, 'Aborted', false);
|
|
317
|
+
await this.#reportProvingJobError(id, 'Aborted', false, undefined, true);
|
|
289
318
|
}
|
|
290
319
|
}
|
|
291
320
|
|
|
@@ -366,6 +395,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
366
395
|
err: string,
|
|
367
396
|
retry = false,
|
|
368
397
|
filter?: ProvingJobFilter,
|
|
398
|
+
aborted = false,
|
|
369
399
|
): Promise<GetProvingJobResponse | undefined> {
|
|
370
400
|
const info = this.inProgress.get(id);
|
|
371
401
|
const item = this.jobsCache.get(id);
|
|
@@ -426,7 +456,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
426
456
|
this.promises.get(id)!.resolve(result);
|
|
427
457
|
this.completedJobNotifications.push(id);
|
|
428
458
|
|
|
429
|
-
|
|
459
|
+
if (aborted) {
|
|
460
|
+
this.instrumentation.incAbortedJobs(item.type);
|
|
461
|
+
} else {
|
|
462
|
+
this.instrumentation.incRejectedJobs(item.type);
|
|
463
|
+
}
|
|
430
464
|
if (info) {
|
|
431
465
|
const duration = this.msTimeSource() - info.startedAt;
|
|
432
466
|
this.instrumentation.recordJobDuration(item.type, duration);
|
|
@@ -18,6 +18,7 @@ export class ProvingBrokerInstrumentation {
|
|
|
18
18
|
private activeJobs: ObservableGauge;
|
|
19
19
|
private resolvedJobs: UpDownCounter;
|
|
20
20
|
private rejectedJobs: UpDownCounter;
|
|
21
|
+
private abortedJobs: UpDownCounter;
|
|
21
22
|
private timedOutJobs: UpDownCounter;
|
|
22
23
|
private cachedJobs: UpDownCounter;
|
|
23
24
|
private totalJobs: UpDownCounter;
|
|
@@ -39,6 +40,8 @@ export class ProvingBrokerInstrumentation {
|
|
|
39
40
|
|
|
40
41
|
this.rejectedJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_REJECTED_JOBS, provingJobAttrs);
|
|
41
42
|
|
|
43
|
+
this.abortedJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_ABORTED_JOBS, provingJobAttrs);
|
|
44
|
+
|
|
42
45
|
this.retriedJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_RETRIED_JOBS, provingJobAttrs);
|
|
43
46
|
|
|
44
47
|
this.timedOutJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_TIMED_OUT_JOBS, provingJobAttrs);
|
|
@@ -72,6 +75,12 @@ export class ProvingBrokerInstrumentation {
|
|
|
72
75
|
});
|
|
73
76
|
}
|
|
74
77
|
|
|
78
|
+
incAbortedJobs(proofType: ProvingRequestType) {
|
|
79
|
+
this.abortedJobs.add(1, {
|
|
80
|
+
[Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
75
84
|
incRetriedJobs(proofType: ProvingRequestType) {
|
|
76
85
|
this.retriedJobs.add(1, {
|
|
77
86
|
[Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { EpochNumberSchema } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { createSafeJsonRpcClient } from '@aztec/foundation/json-rpc/client';
|
|
2
3
|
import {
|
|
3
4
|
type GetProvingJobResponse,
|
|
4
5
|
ProofUri,
|
|
5
6
|
ProvingJob,
|
|
6
7
|
type ProvingJobBroker,
|
|
8
|
+
type ProvingJobBrokerDebug,
|
|
7
9
|
type ProvingJobConsumer,
|
|
8
10
|
ProvingJobId,
|
|
9
11
|
type ProvingJobProducer,
|
|
@@ -53,6 +55,18 @@ export const ProvingJobBrokerSchema: ApiSchemaFor<ProvingJobBroker> = {
|
|
|
53
55
|
...ProvingJobProducerSchema,
|
|
54
56
|
};
|
|
55
57
|
|
|
58
|
+
export const ProvingJobBrokerDebugSchema: ApiSchemaFor<ProvingJobBrokerDebug> = {
|
|
59
|
+
replayProvingJob: z
|
|
60
|
+
.function()
|
|
61
|
+
.args(ProvingJobId, z.nativeEnum(ProvingRequestType), EpochNumberSchema, ProofUri)
|
|
62
|
+
.returns(ProvingJobStatus),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const ProvingJobBrokerSchemaWithDebug: ApiSchemaFor<ProvingJobBroker & ProvingJobBrokerDebug> = {
|
|
66
|
+
...ProvingJobBrokerSchema,
|
|
67
|
+
...ProvingJobBrokerDebugSchema,
|
|
68
|
+
};
|
|
69
|
+
|
|
56
70
|
export function createProvingJobBrokerClient(
|
|
57
71
|
url: string,
|
|
58
72
|
versions: Partial<ComponentsVersions>,
|