@aztec/prover-client 0.0.1-commit.b2a5d0dd1 → 0.0.1-commit.b3d3157a
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/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +4 -0
- package/dest/light/lightweight_checkpoint_builder.d.ts +1 -1
- package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -1
- package/dest/light/lightweight_checkpoint_builder.js +12 -4
- package/dest/mocks/test_context.d.ts +3 -1
- package/dest/mocks/test_context.d.ts.map +1 -1
- package/dest/mocks/test_context.js +3 -1
- package/dest/orchestrator/block-building-helpers.d.ts +1 -1
- package/dest/orchestrator/checkpoint-proving-state.d.ts +8 -1
- package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/checkpoint-proving-state.js +10 -1
- package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts +107 -0
- package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts.map +1 -0
- package/dest/orchestrator/checkpoint-sub-tree-orchestrator.js +151 -0
- package/dest/orchestrator/epoch-proving-context.d.ts +51 -0
- package/dest/orchestrator/epoch-proving-context.d.ts.map +1 -0
- package/dest/orchestrator/epoch-proving-context.js +81 -0
- package/dest/orchestrator/index.d.ts +4 -1
- package/dest/orchestrator/index.d.ts.map +1 -1
- package/dest/orchestrator/index.js +3 -0
- package/dest/orchestrator/orchestrator.d.ts +14 -26
- package/dest/orchestrator/orchestrator.d.ts.map +1 -1
- package/dest/orchestrator/orchestrator.js +32 -169
- package/dest/orchestrator/proving-scheduler.d.ts +72 -0
- package/dest/orchestrator/proving-scheduler.d.ts.map +1 -0
- package/dest/orchestrator/proving-scheduler.js +117 -0
- package/dest/orchestrator/top-tree-orchestrator.d.ts +83 -0
- package/dest/orchestrator/top-tree-orchestrator.d.ts.map +1 -0
- package/dest/orchestrator/top-tree-orchestrator.js +182 -0
- package/dest/orchestrator/top-tree-proving-scheduler.d.ts +62 -0
- package/dest/orchestrator/top-tree-proving-scheduler.d.ts.map +1 -0
- package/dest/orchestrator/top-tree-proving-scheduler.js +73 -0
- package/dest/orchestrator/top-tree-proving-state.d.ts +61 -0
- package/dest/orchestrator/top-tree-proving-state.d.ts.map +1 -0
- package/dest/orchestrator/top-tree-proving-state.js +185 -0
- package/dest/prover-client/prover-client.d.ts +61 -2
- package/dest/prover-client/prover-client.d.ts.map +1 -1
- package/dest/prover-client/prover-client.js +49 -1
- package/dest/proving_broker/config.d.ts +8 -72
- package/dest/proving_broker/config.d.ts.map +1 -1
- package/dest/proving_broker/config.js +2 -2
- package/dest/proving_broker/index.d.ts +2 -1
- package/dest/proving_broker/index.d.ts.map +1 -1
- package/dest/proving_broker/index.js +1 -0
- package/dest/proving_broker/proving_broker.d.ts +2 -2
- package/dest/proving_broker/proving_broker.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker.js +5 -3
- package/dest/proving_broker/proving_broker_database/persisted.js +2 -2
- package/dest/proving_broker/rpc.d.ts +1 -1
- package/dest/proving_broker/rpc.d.ts.map +1 -1
- package/dest/proving_broker/rpc.js +64 -9
- package/package.json +17 -17
- package/src/config.ts +5 -0
- package/src/light/lightweight_checkpoint_builder.ts +14 -6
- package/src/mocks/test_context.ts +3 -1
- package/src/orchestrator/checkpoint-proving-state.ts +14 -1
- package/src/orchestrator/checkpoint-sub-tree-orchestrator.ts +271 -0
- package/src/orchestrator/epoch-proving-context.ts +101 -0
- package/src/orchestrator/index.ts +8 -0
- package/src/orchestrator/orchestrator.ts +46 -225
- package/src/orchestrator/proving-scheduler.ts +156 -0
- package/src/orchestrator/top-tree-orchestrator.ts +314 -0
- package/src/orchestrator/top-tree-proving-scheduler.ts +154 -0
- package/src/orchestrator/top-tree-proving-state.ts +220 -0
- package/src/prover-client/prover-client.ts +125 -1
- package/src/proving_broker/config.ts +2 -1
- package/src/proving_broker/index.ts +1 -0
- package/src/proving_broker/proving_broker.ts +5 -3
- package/src/proving_broker/proving_broker_database/persisted.ts +2 -2
- package/src/proving_broker/rpc.ts +24 -21
|
@@ -3,18 +3,13 @@ import {
|
|
|
3
3
|
L1_TO_L2_MSG_SUBTREE_HEIGHT,
|
|
4
4
|
L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
5
5
|
NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH,
|
|
6
|
-
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
7
6
|
NUM_BASE_PARITY_PER_ROOT_PARITY,
|
|
8
7
|
} from '@aztec/constants';
|
|
9
8
|
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
10
|
-
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
11
9
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
12
|
-
import {
|
|
13
|
-
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
10
|
+
import type { LoggerBindings } from '@aztec/foundation/log';
|
|
14
11
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
15
|
-
import { SerialQueue } from '@aztec/foundation/queue';
|
|
16
12
|
import { assertLength } from '@aztec/foundation/serialize';
|
|
17
|
-
import { sleep } from '@aztec/foundation/sleep';
|
|
18
13
|
import { pushTestData } from '@aztec/foundation/testing';
|
|
19
14
|
import { elapsed } from '@aztec/foundation/timer';
|
|
20
15
|
import type { TreeNodeLocation } from '@aztec/foundation/trees';
|
|
@@ -27,6 +22,7 @@ import type {
|
|
|
27
22
|
ReadonlyWorldStateAccess,
|
|
28
23
|
ServerCircuitProver,
|
|
29
24
|
} from '@aztec/stdlib/interfaces/server';
|
|
25
|
+
import { appendL1ToL2MessagesToTree } from '@aztec/stdlib/messaging';
|
|
30
26
|
import type { Proof } from '@aztec/stdlib/proofs';
|
|
31
27
|
import {
|
|
32
28
|
type BaseRollupHints,
|
|
@@ -71,6 +67,7 @@ import type { BlockProvingState } from './block-proving-state.js';
|
|
|
71
67
|
import type { CheckpointProvingState } from './checkpoint-proving-state.js';
|
|
72
68
|
import { EpochProvingState, type ProvingResult, type TreeSnapshots } from './epoch-proving-state.js';
|
|
73
69
|
import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
|
|
70
|
+
import { TopTreeProvingScheduler } from './top-tree-proving-scheduler.js';
|
|
74
71
|
import { TxProvingState } from './tx-proving-state.js';
|
|
75
72
|
|
|
76
73
|
/**
|
|
@@ -87,29 +84,25 @@ import { TxProvingState } from './tx-proving-state.js';
|
|
|
87
84
|
/**
|
|
88
85
|
* The orchestrator, managing the flow of recursive proving operations required to build the rollup proof tree.
|
|
89
86
|
*/
|
|
90
|
-
export class ProvingOrchestrator implements EpochProver {
|
|
91
|
-
|
|
92
|
-
private pendingProvingJobs: AbortController[] = [];
|
|
87
|
+
export class ProvingOrchestrator extends TopTreeProvingScheduler implements EpochProver {
|
|
88
|
+
protected provingState: EpochProvingState | undefined = undefined;
|
|
93
89
|
|
|
94
|
-
|
|
90
|
+
protected provingPromise: Promise<ProvingResult> | undefined = undefined;
|
|
95
91
|
private metrics: ProvingOrchestratorMetrics;
|
|
96
|
-
|
|
92
|
+
|
|
97
93
|
private dbs: Map<BlockNumber, MerkleTreeWriteOperations> = new Map();
|
|
98
|
-
private logger: Logger;
|
|
99
|
-
private deferredJobQueue = new SerialQueue();
|
|
100
94
|
|
|
101
95
|
constructor(
|
|
102
96
|
private dbProvider: ReadonlyWorldStateAccess & ForkMerkleTreeOperations,
|
|
103
|
-
|
|
97
|
+
prover: ServerCircuitProver,
|
|
104
98
|
private readonly proverId: EthAddress,
|
|
105
99
|
private readonly cancelJobsOnStop: boolean = false,
|
|
106
|
-
|
|
100
|
+
enqueueConcurrency: number,
|
|
107
101
|
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
108
102
|
bindings?: LoggerBindings,
|
|
109
103
|
) {
|
|
110
|
-
|
|
104
|
+
super(prover, enqueueConcurrency, 'prover-client:orchestrator', bindings);
|
|
111
105
|
this.metrics = new ProvingOrchestratorMetrics(telemetryClient, 'ProvingOrchestrator');
|
|
112
|
-
this.deferredJobQueue.start(this.enqueueConcurrency);
|
|
113
106
|
}
|
|
114
107
|
|
|
115
108
|
get tracer(): Tracer {
|
|
@@ -124,11 +117,24 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
124
117
|
return this.dbs.size;
|
|
125
118
|
}
|
|
126
119
|
|
|
127
|
-
|
|
128
|
-
// Grab the old queue before cancel() replaces it, so we can await its draining.
|
|
129
|
-
const oldQueue = this.deferredJobQueue;
|
|
120
|
+
protected override cancelInternal(): void {
|
|
130
121
|
this.cancel();
|
|
131
|
-
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
protected override wrapCircuitCall<T>(
|
|
125
|
+
circuitName: string,
|
|
126
|
+
fn: (signal: AbortSignal) => Promise<T>,
|
|
127
|
+
): (signal: AbortSignal) => Promise<T> {
|
|
128
|
+
return wrapCallbackInSpan(
|
|
129
|
+
this.tracer,
|
|
130
|
+
`ProvingOrchestrator.prover.${circuitName}`,
|
|
131
|
+
{ [Attributes.PROTOCOL_CIRCUIT_NAME]: circuitName as CircuitName },
|
|
132
|
+
fn,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
protected override onRootRollupComplete(state: EpochProvingState) {
|
|
137
|
+
state.resolve({ status: 'success' });
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
public startNewEpoch(
|
|
@@ -521,16 +527,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
521
527
|
* If cancelJobsOnStop is false (default), jobs remain in the broker queue and can be reused on restart/reorg.
|
|
522
528
|
*/
|
|
523
529
|
public cancel() {
|
|
524
|
-
|
|
525
|
-
// Recreate the queue so it can accept jobs for subsequent epochs.
|
|
526
|
-
this.deferredJobQueue = new SerialQueue();
|
|
527
|
-
this.deferredJobQueue.start(this.enqueueConcurrency);
|
|
528
|
-
|
|
529
|
-
if (this.cancelJobsOnStop) {
|
|
530
|
-
for (const controller of this.pendingProvingJobs) {
|
|
531
|
-
controller.abort();
|
|
532
|
-
}
|
|
533
|
-
}
|
|
530
|
+
this.resetSchedulerState(this.cancelJobsOnStop);
|
|
534
531
|
|
|
535
532
|
this.provingState?.cancel();
|
|
536
533
|
|
|
@@ -577,79 +574,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
577
574
|
return epochProofResult;
|
|
578
575
|
}
|
|
579
576
|
|
|
580
|
-
/**
|
|
581
|
-
* Enqueue a job to be scheduled
|
|
582
|
-
* @param provingState - The proving state object being operated on
|
|
583
|
-
* @param jobType - The type of job to be queued
|
|
584
|
-
* @param job - The actual job, returns a promise notifying of the job's completion
|
|
585
|
-
*/
|
|
586
|
-
private deferredProving<T>(
|
|
587
|
-
provingState: EpochProvingState | CheckpointProvingState | BlockProvingState,
|
|
588
|
-
request: (signal: AbortSignal) => Promise<T>,
|
|
589
|
-
callback: (result: T) => void | Promise<void>,
|
|
590
|
-
) {
|
|
591
|
-
if (!provingState.verifyState()) {
|
|
592
|
-
this.logger.debug(`Not enqueuing job, state no longer valid`);
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
const controller = new AbortController();
|
|
597
|
-
this.pendingProvingJobs.push(controller);
|
|
598
|
-
|
|
599
|
-
// We use a 'safeJob'. We don't want promise rejections in the proving pool, we want to capture the error here
|
|
600
|
-
// and reject the proving job whilst keeping the event loop free of rejections
|
|
601
|
-
const safeJob = async () => {
|
|
602
|
-
try {
|
|
603
|
-
// there's a delay between enqueueing this job and it actually running
|
|
604
|
-
if (controller.signal.aborted) {
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
const result = await request(controller.signal);
|
|
609
|
-
if (!provingState.verifyState()) {
|
|
610
|
-
this.logger.debug(`State no longer valid, discarding result`);
|
|
611
|
-
return;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// we could have been cancelled whilst waiting for the result
|
|
615
|
-
// and the prover ignored the signal. Drop the result in that case
|
|
616
|
-
if (controller.signal.aborted) {
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
await callback(result);
|
|
621
|
-
} catch (err) {
|
|
622
|
-
if (err instanceof AbortError) {
|
|
623
|
-
// operation was cancelled, probably because the block was cancelled
|
|
624
|
-
// drop this result
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
this.logger.error(`Error thrown when proving job`, err);
|
|
629
|
-
provingState!.reject(`${err}`);
|
|
630
|
-
} finally {
|
|
631
|
-
const index = this.pendingProvingJobs.indexOf(controller);
|
|
632
|
-
if (index > -1) {
|
|
633
|
-
this.pendingProvingJobs.splice(index, 1);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
};
|
|
637
|
-
|
|
638
|
-
void this.deferredJobQueue.put(async () => {
|
|
639
|
-
void safeJob();
|
|
640
|
-
// we yield here to the macro task queue such to give Nodejs a chance to run other operatoins in between enqueues
|
|
641
|
-
await sleep(0);
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
|
|
645
577
|
private async updateL1ToL2MessageTree(l1ToL2Messages: Fr[], db: MerkleTreeWriteOperations) {
|
|
646
|
-
const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
|
|
647
|
-
l1ToL2Messages,
|
|
648
|
-
Fr.ZERO,
|
|
649
|
-
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
650
|
-
'Too many L1 to L2 messages',
|
|
651
|
-
);
|
|
652
|
-
|
|
653
578
|
const lastL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
|
|
654
579
|
const lastL1ToL2MessageSubtreeRootSiblingPath = assertLength(
|
|
655
580
|
await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db),
|
|
@@ -657,7 +582,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
657
582
|
);
|
|
658
583
|
|
|
659
584
|
// Update the local trees to include the new l1 to l2 messages
|
|
660
|
-
await db
|
|
585
|
+
await appendL1ToL2MessagesToTree(db, l1ToL2Messages);
|
|
661
586
|
|
|
662
587
|
const newL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
|
|
663
588
|
const newL1ToL2MessageSubtreeRootSiblingPath = assertLength(
|
|
@@ -764,7 +689,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
764
689
|
|
|
765
690
|
// Enqueues the public chonk verifier circuit for a given transaction index, or reuses the one already enqueued.
|
|
766
691
|
// Once completed, will enqueue the the public tx base rollup.
|
|
767
|
-
|
|
692
|
+
protected getOrEnqueueChonkVerifier(provingState: BlockProvingState, txIndex: number) {
|
|
768
693
|
if (!provingState.verifyState()) {
|
|
769
694
|
this.logger.debug('Not running chonk verifier circuit, state invalid');
|
|
770
695
|
return;
|
|
@@ -772,7 +697,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
772
697
|
|
|
773
698
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
774
699
|
const txHash = txProvingState.processedTx.hash.toString();
|
|
775
|
-
NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH;
|
|
776
700
|
const handleResult = (
|
|
777
701
|
result: PublicInputsAndRecursiveProof<
|
|
778
702
|
PublicChonkVerifierPublicInputs,
|
|
@@ -897,7 +821,11 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
897
821
|
},
|
|
898
822
|
),
|
|
899
823
|
async result => {
|
|
900
|
-
this.logger.debug(`Completed ${rollupType} proof for block ${provingState.blockNumber}
|
|
824
|
+
this.logger.debug(`Completed ${rollupType} proof for block ${provingState.blockNumber}`, {
|
|
825
|
+
blockNumber: provingState.blockNumber,
|
|
826
|
+
checkpointIndex: provingState.parentCheckpoint.index,
|
|
827
|
+
...result.inputs.toInspect(),
|
|
828
|
+
});
|
|
901
829
|
|
|
902
830
|
const leafLocation = provingState.setBlockRootRollupProof(result);
|
|
903
831
|
const checkpointProvingState = provingState.parentCheckpoint;
|
|
@@ -1016,6 +944,11 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1016
944
|
signal => this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber),
|
|
1017
945
|
),
|
|
1018
946
|
async result => {
|
|
947
|
+
this.logger.debug(`Completed block merge rollup proof for checkpoint ${provingState.index}`, {
|
|
948
|
+
checkpointIndex: provingState.index,
|
|
949
|
+
mergeLocation: location,
|
|
950
|
+
...result.inputs.toInspect(),
|
|
951
|
+
});
|
|
1019
952
|
provingState.setBlockMergeRollupProof(location, result);
|
|
1020
953
|
await this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
|
|
1021
954
|
},
|
|
@@ -1068,7 +1001,10 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1068
1001
|
return;
|
|
1069
1002
|
}
|
|
1070
1003
|
|
|
1071
|
-
this.logger.debug(`Completed ${rollupType} proof for checkpoint ${provingState.index}
|
|
1004
|
+
this.logger.debug(`Completed ${rollupType} proof for checkpoint ${provingState.index}`, {
|
|
1005
|
+
checkpointIndex: provingState.index,
|
|
1006
|
+
...result.inputs.toInspect(),
|
|
1007
|
+
});
|
|
1072
1008
|
|
|
1073
1009
|
const leafLocation = provingState.setCheckpointRootRollupProof(result);
|
|
1074
1010
|
const epochProvingState = provingState.parentEpoch;
|
|
@@ -1082,99 +1018,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1082
1018
|
);
|
|
1083
1019
|
}
|
|
1084
1020
|
|
|
1085
|
-
private enqueueCheckpointMergeRollup(provingState: EpochProvingState, location: TreeNodeLocation) {
|
|
1086
|
-
if (!provingState.verifyState()) {
|
|
1087
|
-
this.logger.debug('Not running checkpoint merge rollup. State no longer valid.');
|
|
1088
|
-
return;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
if (!provingState.tryStartProvingCheckpointMerge(location)) {
|
|
1092
|
-
this.logger.debug('Checkpoint merge rollup already started.');
|
|
1093
|
-
return;
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
const inputs = provingState.getCheckpointMergeRollupInputs(location);
|
|
1097
|
-
|
|
1098
|
-
this.deferredProving(
|
|
1099
|
-
provingState,
|
|
1100
|
-
wrapCallbackInSpan(
|
|
1101
|
-
this.tracer,
|
|
1102
|
-
'ProvingOrchestrator.prover.getCheckpointMergeRollupProof',
|
|
1103
|
-
{
|
|
1104
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-merge' satisfies CircuitName,
|
|
1105
|
-
},
|
|
1106
|
-
signal => this.prover.getCheckpointMergeRollupProof(inputs, signal, provingState.epochNumber),
|
|
1107
|
-
),
|
|
1108
|
-
result => {
|
|
1109
|
-
this.logger.debug('Completed proof for checkpoint merge rollup.');
|
|
1110
|
-
provingState.setCheckpointMergeRollupProof(location, result);
|
|
1111
|
-
this.checkAndEnqueueNextCheckpointMergeRollup(provingState, location);
|
|
1112
|
-
},
|
|
1113
|
-
);
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
private enqueueEpochPadding(provingState: EpochProvingState) {
|
|
1117
|
-
if (!provingState.verifyState()) {
|
|
1118
|
-
this.logger.debug('Not running epoch padding. State no longer valid.');
|
|
1119
|
-
return;
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
if (!provingState.tryStartProvingPaddingCheckpoint()) {
|
|
1123
|
-
this.logger.debug('Padding checkpoint already started.');
|
|
1124
|
-
return;
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
this.logger.debug('Padding epoch proof with a padding block root proof.');
|
|
1128
|
-
|
|
1129
|
-
const inputs = provingState.getPaddingCheckpointInputs();
|
|
1130
|
-
|
|
1131
|
-
this.deferredProving(
|
|
1132
|
-
provingState,
|
|
1133
|
-
wrapCallbackInSpan(
|
|
1134
|
-
this.tracer,
|
|
1135
|
-
'ProvingOrchestrator.prover.getCheckpointPaddingRollupProof',
|
|
1136
|
-
{
|
|
1137
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-padding' satisfies CircuitName,
|
|
1138
|
-
},
|
|
1139
|
-
signal => this.prover.getCheckpointPaddingRollupProof(inputs, signal, provingState.epochNumber),
|
|
1140
|
-
),
|
|
1141
|
-
result => {
|
|
1142
|
-
this.logger.debug('Completed proof for padding checkpoint.');
|
|
1143
|
-
provingState.setCheckpointPaddingProof(result);
|
|
1144
|
-
this.checkAndEnqueueRootRollup(provingState);
|
|
1145
|
-
},
|
|
1146
|
-
);
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
// Executes the root rollup circuit
|
|
1150
|
-
private enqueueRootRollup(provingState: EpochProvingState) {
|
|
1151
|
-
if (!provingState.verifyState()) {
|
|
1152
|
-
this.logger.debug('Not running root rollup, state no longer valid');
|
|
1153
|
-
return;
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
this.logger.debug(`Preparing root rollup`);
|
|
1157
|
-
|
|
1158
|
-
const inputs = provingState.getRootRollupInputs();
|
|
1159
|
-
|
|
1160
|
-
this.deferredProving(
|
|
1161
|
-
provingState,
|
|
1162
|
-
wrapCallbackInSpan(
|
|
1163
|
-
this.tracer,
|
|
1164
|
-
'ProvingOrchestrator.prover.getRootRollupProof',
|
|
1165
|
-
{
|
|
1166
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-root' satisfies CircuitName,
|
|
1167
|
-
},
|
|
1168
|
-
signal => this.prover.getRootRollupProof(inputs, signal, provingState.epochNumber),
|
|
1169
|
-
),
|
|
1170
|
-
result => {
|
|
1171
|
-
this.logger.verbose(`Orchestrator completed root rollup for epoch ${provingState.epochNumber}`);
|
|
1172
|
-
provingState.setRootRollupProof(result);
|
|
1173
|
-
provingState.resolve({ status: 'success' });
|
|
1174
|
-
},
|
|
1175
|
-
);
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
1021
|
private checkAndEnqueueNextMergeRollup(provingState: BlockProvingState, currentLocation: TreeNodeLocation) {
|
|
1179
1022
|
if (!provingState.isReadyForMergeRollup(currentLocation)) {
|
|
1180
1023
|
return;
|
|
@@ -1213,7 +1056,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1213
1056
|
}
|
|
1214
1057
|
}
|
|
1215
1058
|
|
|
1216
|
-
|
|
1059
|
+
protected async checkAndEnqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
|
|
1217
1060
|
if (!provingState.isReadyForCheckpointRoot()) {
|
|
1218
1061
|
return;
|
|
1219
1062
|
}
|
|
@@ -1221,28 +1064,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1221
1064
|
await this.enqueueCheckpointRootRollup(provingState);
|
|
1222
1065
|
}
|
|
1223
1066
|
|
|
1224
|
-
private checkAndEnqueueNextCheckpointMergeRollup(provingState: EpochProvingState, currentLocation: TreeNodeLocation) {
|
|
1225
|
-
if (!provingState.isReadyForCheckpointMerge(currentLocation)) {
|
|
1226
|
-
return;
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
const parentLocation = provingState.getParentLocation(currentLocation);
|
|
1230
|
-
if (parentLocation.level === 0) {
|
|
1231
|
-
this.checkAndEnqueueRootRollup(provingState);
|
|
1232
|
-
} else {
|
|
1233
|
-
this.enqueueCheckpointMergeRollup(provingState, parentLocation);
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
private checkAndEnqueueRootRollup(provingState: EpochProvingState) {
|
|
1238
|
-
if (!provingState.isReadyForRootRollup()) {
|
|
1239
|
-
this.logger.debug('Not ready for root rollup');
|
|
1240
|
-
return;
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
this.enqueueRootRollup(provingState);
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
1067
|
/**
|
|
1247
1068
|
* Executes the VM circuit for a public function, will enqueue the corresponding kernel if the
|
|
1248
1069
|
* previous kernel is ready
|
|
@@ -1276,7 +1097,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1276
1097
|
});
|
|
1277
1098
|
}
|
|
1278
1099
|
|
|
1279
|
-
|
|
1100
|
+
protected checkAndEnqueueBaseRollup(provingState: BlockProvingState, txIndex: number) {
|
|
1280
1101
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
1281
1102
|
if (!txProvingState.ready()) {
|
|
1282
1103
|
return;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { AbortError } from '@aztec/foundation/error';
|
|
2
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { SerialQueue } from '@aztec/foundation/queue';
|
|
4
|
+
import { sleep } from '@aztec/foundation/sleep';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Minimal surface a deferred-proving state must expose. Both `EpochProvingState` /
|
|
8
|
+
* `CheckpointProvingState` / `BlockProvingState` (used by `ProvingOrchestrator`) and
|
|
9
|
+
* `TopTreeProvingState` (used by `TopTreeOrchestrator`) satisfy it.
|
|
10
|
+
*/
|
|
11
|
+
export interface ProvingStateLike {
|
|
12
|
+
/** Returns false once the state has been cancelled or otherwise invalidated. */
|
|
13
|
+
verifyState(): boolean;
|
|
14
|
+
/** Surfaces a proving error to the state's owner. */
|
|
15
|
+
reject(reason: string): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Common scheduling infrastructure shared by every orchestrator that drives broker
|
|
20
|
+
* proving jobs:
|
|
21
|
+
*
|
|
22
|
+
* - One `SerialQueue` (`deferredJobQueue`) acting as the enqueue-throttle.
|
|
23
|
+
* - A list of `AbortController`s (`pendingProvingJobs`) so a `cancel()` can abort
|
|
24
|
+
* in-flight broker jobs when needed.
|
|
25
|
+
* - A `deferredProving<T>(state, request, callback, isCancelled?)` method that wraps
|
|
26
|
+
* a broker request in the standard "submit, drop result if state invalidated, push
|
|
27
|
+
* errors to state.reject" envelope.
|
|
28
|
+
*
|
|
29
|
+
* Subclasses own their own concrete proving state and define `cancelInternal()` for
|
|
30
|
+
* the rest of the cleanup work (closing world-state forks, marking sub-trees
|
|
31
|
+
* cancelled, etc.). `stop()` lives on the base class and follows the standard pattern
|
|
32
|
+
* of grabbing the old queue, calling `cancelInternal()` (which recreates the queue),
|
|
33
|
+
* and awaiting the old queue's drain.
|
|
34
|
+
*/
|
|
35
|
+
export abstract class ProvingScheduler {
|
|
36
|
+
protected pendingProvingJobs: AbortController[] = [];
|
|
37
|
+
protected logger: Logger;
|
|
38
|
+
private deferredJobQueue: SerialQueue;
|
|
39
|
+
|
|
40
|
+
constructor(
|
|
41
|
+
private readonly enqueueConcurrency: number,
|
|
42
|
+
loggerName = 'prover-client:proving-scheduler',
|
|
43
|
+
bindings?: LoggerBindings,
|
|
44
|
+
) {
|
|
45
|
+
this.logger = createLogger(loggerName, bindings);
|
|
46
|
+
this.deferredJobQueue = new SerialQueue();
|
|
47
|
+
this.deferredJobQueue.start(this.enqueueConcurrency);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Number of broker jobs currently in flight. */
|
|
51
|
+
public getNumPendingProvingJobs(): number {
|
|
52
|
+
return this.pendingProvingJobs.length;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Drains the deferred-job queue, recreates it (so the subclass can be reused), and
|
|
57
|
+
* optionally aborts every in-flight broker job. Aborting is the right choice on
|
|
58
|
+
* reorg-driven cancel (where the in-flight inputs are no longer valid) and the
|
|
59
|
+
* wrong choice on shutdown (where leaving jobs in the broker queue lets a restart
|
|
60
|
+
* pick them up).
|
|
61
|
+
*/
|
|
62
|
+
protected resetSchedulerState(abortJobs: boolean): void {
|
|
63
|
+
void this.deferredJobQueue.cancel();
|
|
64
|
+
this.deferredJobQueue = new SerialQueue();
|
|
65
|
+
this.deferredJobQueue.start(this.enqueueConcurrency);
|
|
66
|
+
if (abortJobs) {
|
|
67
|
+
for (const controller of this.pendingProvingJobs) {
|
|
68
|
+
controller.abort();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Subclass-defined cancellation. Implementations call `resetSchedulerState(...)`
|
|
75
|
+
* and then do their own cleanup (close world-state forks, propagate cancel into
|
|
76
|
+
* the proving state, etc.).
|
|
77
|
+
*/
|
|
78
|
+
protected abstract cancelInternal(): void;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Standard stop: grab the old queue, cancel (which recreates the queue), then
|
|
82
|
+
* await the old queue's drain so any final job tear-down has unwound before we
|
|
83
|
+
* return.
|
|
84
|
+
*/
|
|
85
|
+
public async stop(): Promise<void> {
|
|
86
|
+
const oldQueue = this.deferredJobQueue;
|
|
87
|
+
this.cancelInternal();
|
|
88
|
+
await oldQueue.cancel();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Submits a broker request. The returned-via-callback result is dropped if the
|
|
93
|
+
* state has become invalid (re-org, cancellation) by the time it lands. Errors
|
|
94
|
+
* are routed to `state.reject` unless they are abort-driven or the state is
|
|
95
|
+
* already invalid (in which case they're a stale echo of the cancel).
|
|
96
|
+
*
|
|
97
|
+
* @param state - Object exposing `verifyState()` and `reject()`.
|
|
98
|
+
* @param request - The broker call. Receives the controller's signal.
|
|
99
|
+
* @param callback - Runs on success, after `verifyState()` is checked.
|
|
100
|
+
* @param isCancelled - Optional extra cancellation predicate (e.g. a `cancelled`
|
|
101
|
+
* flag the subclass maintains independently of the state). Defaults to never.
|
|
102
|
+
*/
|
|
103
|
+
protected deferredProving<S extends ProvingStateLike, T>(
|
|
104
|
+
state: S,
|
|
105
|
+
request: (signal: AbortSignal) => Promise<T>,
|
|
106
|
+
callback: (result: T) => void | Promise<void>,
|
|
107
|
+
isCancelled: () => boolean = () => false,
|
|
108
|
+
): void {
|
|
109
|
+
if (!state.verifyState()) {
|
|
110
|
+
this.logger.debug(`Not enqueuing job, state no longer valid`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const controller = new AbortController();
|
|
115
|
+
this.pendingProvingJobs.push(controller);
|
|
116
|
+
|
|
117
|
+
// We use a 'safeJob'. We don't want promise rejections in the proving pool — we
|
|
118
|
+
// want to capture the error here and reject the proving state while keeping the
|
|
119
|
+
// event loop free of rejections.
|
|
120
|
+
const safeJob = async () => {
|
|
121
|
+
try {
|
|
122
|
+
if (controller.signal.aborted) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const result = await request(controller.signal);
|
|
126
|
+
if (controller.signal.aborted || !state.verifyState() || isCancelled()) {
|
|
127
|
+
this.logger.debug(`State no longer valid, discarding result`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
await callback(result);
|
|
131
|
+
} catch (err) {
|
|
132
|
+
if (err instanceof AbortError || isCancelled()) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (!state.verifyState()) {
|
|
136
|
+
this.logger.debug(`State no longer valid, discarding error from proving job`, err);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
this.logger.error(`Error thrown when proving job`, err);
|
|
140
|
+
state.reject(`${err}`);
|
|
141
|
+
} finally {
|
|
142
|
+
const idx = this.pendingProvingJobs.indexOf(controller);
|
|
143
|
+
if (idx > -1) {
|
|
144
|
+
this.pendingProvingJobs.splice(idx, 1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
void this.deferredJobQueue.put(async () => {
|
|
150
|
+
void safeJob();
|
|
151
|
+
// Yield to the macrotask queue so Node has a chance to interleave other work
|
|
152
|
+
// between enqueues.
|
|
153
|
+
await sleep(0);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|