@aztec/prover-client 0.0.1-commit.b33fc05d0 → 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 +16 -2
- 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 +16 -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 +13 -6
- 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/epoch-proving-state.d.ts +1 -1
- 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 -166
- 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/broker_prover_facade.d.ts +1 -1
- package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
- package/dest/proving_broker/broker_prover_facade.js +10 -16
- 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 +32 -7
- package/dest/proving_broker/proving_broker_database/persisted.js +2 -2
- package/dest/proving_broker/rpc.d.ts +3 -1
- package/dest/proving_broker/rpc.d.ts.map +1 -1
- package/dest/proving_broker/rpc.js +80 -24
- package/dest/test/mock_prover.d.ts +3 -3
- package/package.json +17 -17
- package/src/config.ts +18 -2
- package/src/light/lightweight_checkpoint_builder.ts +21 -6
- package/src/mocks/test_context.ts +11 -7
- 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 -222
- 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/broker_prover_facade.ts +8 -16
- package/src/proving_broker/config.ts +2 -1
- package/src/proving_broker/index.ts +1 -0
- package/src/proving_broker/proving_broker.ts +27 -5
- package/src/proving_broker/proving_broker_database/persisted.ts +2 -2
- package/src/proving_broker/rpc.ts +36 -24
|
@@ -3,16 +3,12 @@ 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
13
|
import { pushTestData } from '@aztec/foundation/testing';
|
|
18
14
|
import { elapsed } from '@aztec/foundation/timer';
|
|
@@ -26,6 +22,7 @@ import type {
|
|
|
26
22
|
ReadonlyWorldStateAccess,
|
|
27
23
|
ServerCircuitProver,
|
|
28
24
|
} from '@aztec/stdlib/interfaces/server';
|
|
25
|
+
import { appendL1ToL2MessagesToTree } from '@aztec/stdlib/messaging';
|
|
29
26
|
import type { Proof } from '@aztec/stdlib/proofs';
|
|
30
27
|
import {
|
|
31
28
|
type BaseRollupHints,
|
|
@@ -70,6 +67,7 @@ import type { BlockProvingState } from './block-proving-state.js';
|
|
|
70
67
|
import type { CheckpointProvingState } from './checkpoint-proving-state.js';
|
|
71
68
|
import { EpochProvingState, type ProvingResult, type TreeSnapshots } from './epoch-proving-state.js';
|
|
72
69
|
import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
|
|
70
|
+
import { TopTreeProvingScheduler } from './top-tree-proving-scheduler.js';
|
|
73
71
|
import { TxProvingState } from './tx-proving-state.js';
|
|
74
72
|
|
|
75
73
|
/**
|
|
@@ -86,29 +84,25 @@ import { TxProvingState } from './tx-proving-state.js';
|
|
|
86
84
|
/**
|
|
87
85
|
* The orchestrator, managing the flow of recursive proving operations required to build the rollup proof tree.
|
|
88
86
|
*/
|
|
89
|
-
export class ProvingOrchestrator implements EpochProver {
|
|
90
|
-
|
|
91
|
-
private pendingProvingJobs: AbortController[] = [];
|
|
87
|
+
export class ProvingOrchestrator extends TopTreeProvingScheduler implements EpochProver {
|
|
88
|
+
protected provingState: EpochProvingState | undefined = undefined;
|
|
92
89
|
|
|
93
|
-
|
|
90
|
+
protected provingPromise: Promise<ProvingResult> | undefined = undefined;
|
|
94
91
|
private metrics: ProvingOrchestratorMetrics;
|
|
95
|
-
|
|
92
|
+
|
|
96
93
|
private dbs: Map<BlockNumber, MerkleTreeWriteOperations> = new Map();
|
|
97
|
-
private logger: Logger;
|
|
98
|
-
private deferredJobQueue = new SerialQueue();
|
|
99
94
|
|
|
100
95
|
constructor(
|
|
101
96
|
private dbProvider: ReadonlyWorldStateAccess & ForkMerkleTreeOperations,
|
|
102
|
-
|
|
97
|
+
prover: ServerCircuitProver,
|
|
103
98
|
private readonly proverId: EthAddress,
|
|
104
99
|
private readonly cancelJobsOnStop: boolean = false,
|
|
105
|
-
|
|
100
|
+
enqueueConcurrency: number,
|
|
106
101
|
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
107
102
|
bindings?: LoggerBindings,
|
|
108
103
|
) {
|
|
109
|
-
|
|
104
|
+
super(prover, enqueueConcurrency, 'prover-client:orchestrator', bindings);
|
|
110
105
|
this.metrics = new ProvingOrchestratorMetrics(telemetryClient, 'ProvingOrchestrator');
|
|
111
|
-
this.deferredJobQueue.start(this.enqueueConcurrency);
|
|
112
106
|
}
|
|
113
107
|
|
|
114
108
|
get tracer(): Tracer {
|
|
@@ -123,11 +117,24 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
123
117
|
return this.dbs.size;
|
|
124
118
|
}
|
|
125
119
|
|
|
126
|
-
|
|
127
|
-
// Grab the old queue before cancel() replaces it, so we can await its draining.
|
|
128
|
-
const oldQueue = this.deferredJobQueue;
|
|
120
|
+
protected override cancelInternal(): void {
|
|
129
121
|
this.cancel();
|
|
130
|
-
|
|
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' });
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
public startNewEpoch(
|
|
@@ -520,16 +527,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
520
527
|
* If cancelJobsOnStop is false (default), jobs remain in the broker queue and can be reused on restart/reorg.
|
|
521
528
|
*/
|
|
522
529
|
public cancel() {
|
|
523
|
-
|
|
524
|
-
// Recreate the queue so it can accept jobs for subsequent epochs.
|
|
525
|
-
this.deferredJobQueue = new SerialQueue();
|
|
526
|
-
this.deferredJobQueue.start(this.enqueueConcurrency);
|
|
527
|
-
|
|
528
|
-
if (this.cancelJobsOnStop) {
|
|
529
|
-
for (const controller of this.pendingProvingJobs) {
|
|
530
|
-
controller.abort();
|
|
531
|
-
}
|
|
532
|
-
}
|
|
530
|
+
this.resetSchedulerState(this.cancelJobsOnStop);
|
|
533
531
|
|
|
534
532
|
this.provingState?.cancel();
|
|
535
533
|
|
|
@@ -576,77 +574,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
576
574
|
return epochProofResult;
|
|
577
575
|
}
|
|
578
576
|
|
|
579
|
-
/**
|
|
580
|
-
* Enqueue a job to be scheduled
|
|
581
|
-
* @param provingState - The proving state object being operated on
|
|
582
|
-
* @param jobType - The type of job to be queued
|
|
583
|
-
* @param job - The actual job, returns a promise notifying of the job's completion
|
|
584
|
-
*/
|
|
585
|
-
private deferredProving<T>(
|
|
586
|
-
provingState: EpochProvingState | CheckpointProvingState | BlockProvingState,
|
|
587
|
-
request: (signal: AbortSignal) => Promise<T>,
|
|
588
|
-
callback: (result: T) => void | Promise<void>,
|
|
589
|
-
) {
|
|
590
|
-
if (!provingState.verifyState()) {
|
|
591
|
-
this.logger.debug(`Not enqueuing job, state no longer valid`);
|
|
592
|
-
return;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
const controller = new AbortController();
|
|
596
|
-
this.pendingProvingJobs.push(controller);
|
|
597
|
-
|
|
598
|
-
// We use a 'safeJob'. We don't want promise rejections in the proving pool, we want to capture the error here
|
|
599
|
-
// and reject the proving job whilst keeping the event loop free of rejections
|
|
600
|
-
const safeJob = async () => {
|
|
601
|
-
try {
|
|
602
|
-
// there's a delay between enqueueing this job and it actually running
|
|
603
|
-
if (controller.signal.aborted) {
|
|
604
|
-
return;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
const result = await request(controller.signal);
|
|
608
|
-
if (!provingState.verifyState()) {
|
|
609
|
-
this.logger.debug(`State no longer valid, discarding result`);
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// we could have been cancelled whilst waiting for the result
|
|
614
|
-
// and the prover ignored the signal. Drop the result in that case
|
|
615
|
-
if (controller.signal.aborted) {
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
await callback(result);
|
|
620
|
-
} catch (err) {
|
|
621
|
-
if (err instanceof AbortError) {
|
|
622
|
-
// operation was cancelled, probably because the block was cancelled
|
|
623
|
-
// drop this result
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
this.logger.error(`Error thrown when proving job`, err);
|
|
628
|
-
provingState!.reject(`${err}`);
|
|
629
|
-
} finally {
|
|
630
|
-
const index = this.pendingProvingJobs.indexOf(controller);
|
|
631
|
-
if (index > -1) {
|
|
632
|
-
this.pendingProvingJobs.splice(index, 1);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
// Enqueue onto the serial queue with limited workers to avoid starving the event loop.
|
|
638
|
-
// Workers yield between jobs via await, allowing I/O callbacks to process.
|
|
639
|
-
void this.deferredJobQueue.put(() => safeJob());
|
|
640
|
-
}
|
|
641
|
-
|
|
642
577
|
private async updateL1ToL2MessageTree(l1ToL2Messages: Fr[], db: MerkleTreeWriteOperations) {
|
|
643
|
-
const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
|
|
644
|
-
l1ToL2Messages,
|
|
645
|
-
Fr.ZERO,
|
|
646
|
-
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
647
|
-
'Too many L1 to L2 messages',
|
|
648
|
-
);
|
|
649
|
-
|
|
650
578
|
const lastL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
|
|
651
579
|
const lastL1ToL2MessageSubtreeRootSiblingPath = assertLength(
|
|
652
580
|
await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db),
|
|
@@ -654,7 +582,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
654
582
|
);
|
|
655
583
|
|
|
656
584
|
// Update the local trees to include the new l1 to l2 messages
|
|
657
|
-
await db
|
|
585
|
+
await appendL1ToL2MessagesToTree(db, l1ToL2Messages);
|
|
658
586
|
|
|
659
587
|
const newL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
|
|
660
588
|
const newL1ToL2MessageSubtreeRootSiblingPath = assertLength(
|
|
@@ -761,7 +689,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
761
689
|
|
|
762
690
|
// Enqueues the public chonk verifier circuit for a given transaction index, or reuses the one already enqueued.
|
|
763
691
|
// Once completed, will enqueue the the public tx base rollup.
|
|
764
|
-
|
|
692
|
+
protected getOrEnqueueChonkVerifier(provingState: BlockProvingState, txIndex: number) {
|
|
765
693
|
if (!provingState.verifyState()) {
|
|
766
694
|
this.logger.debug('Not running chonk verifier circuit, state invalid');
|
|
767
695
|
return;
|
|
@@ -769,7 +697,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
769
697
|
|
|
770
698
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
771
699
|
const txHash = txProvingState.processedTx.hash.toString();
|
|
772
|
-
NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH;
|
|
773
700
|
const handleResult = (
|
|
774
701
|
result: PublicInputsAndRecursiveProof<
|
|
775
702
|
PublicChonkVerifierPublicInputs,
|
|
@@ -894,7 +821,11 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
894
821
|
},
|
|
895
822
|
),
|
|
896
823
|
async result => {
|
|
897
|
-
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
|
+
});
|
|
898
829
|
|
|
899
830
|
const leafLocation = provingState.setBlockRootRollupProof(result);
|
|
900
831
|
const checkpointProvingState = provingState.parentCheckpoint;
|
|
@@ -1013,6 +944,11 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1013
944
|
signal => this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber),
|
|
1014
945
|
),
|
|
1015
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
|
+
});
|
|
1016
952
|
provingState.setBlockMergeRollupProof(location, result);
|
|
1017
953
|
await this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
|
|
1018
954
|
},
|
|
@@ -1065,7 +1001,10 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1065
1001
|
return;
|
|
1066
1002
|
}
|
|
1067
1003
|
|
|
1068
|
-
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
|
+
});
|
|
1069
1008
|
|
|
1070
1009
|
const leafLocation = provingState.setCheckpointRootRollupProof(result);
|
|
1071
1010
|
const epochProvingState = provingState.parentEpoch;
|
|
@@ -1079,99 +1018,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1079
1018
|
);
|
|
1080
1019
|
}
|
|
1081
1020
|
|
|
1082
|
-
private enqueueCheckpointMergeRollup(provingState: EpochProvingState, location: TreeNodeLocation) {
|
|
1083
|
-
if (!provingState.verifyState()) {
|
|
1084
|
-
this.logger.debug('Not running checkpoint merge rollup. State no longer valid.');
|
|
1085
|
-
return;
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
if (!provingState.tryStartProvingCheckpointMerge(location)) {
|
|
1089
|
-
this.logger.debug('Checkpoint merge rollup already started.');
|
|
1090
|
-
return;
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
const inputs = provingState.getCheckpointMergeRollupInputs(location);
|
|
1094
|
-
|
|
1095
|
-
this.deferredProving(
|
|
1096
|
-
provingState,
|
|
1097
|
-
wrapCallbackInSpan(
|
|
1098
|
-
this.tracer,
|
|
1099
|
-
'ProvingOrchestrator.prover.getCheckpointMergeRollupProof',
|
|
1100
|
-
{
|
|
1101
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-merge' satisfies CircuitName,
|
|
1102
|
-
},
|
|
1103
|
-
signal => this.prover.getCheckpointMergeRollupProof(inputs, signal, provingState.epochNumber),
|
|
1104
|
-
),
|
|
1105
|
-
result => {
|
|
1106
|
-
this.logger.debug('Completed proof for checkpoint merge rollup.');
|
|
1107
|
-
provingState.setCheckpointMergeRollupProof(location, result);
|
|
1108
|
-
this.checkAndEnqueueNextCheckpointMergeRollup(provingState, location);
|
|
1109
|
-
},
|
|
1110
|
-
);
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
private enqueueEpochPadding(provingState: EpochProvingState) {
|
|
1114
|
-
if (!provingState.verifyState()) {
|
|
1115
|
-
this.logger.debug('Not running epoch padding. State no longer valid.');
|
|
1116
|
-
return;
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
if (!provingState.tryStartProvingPaddingCheckpoint()) {
|
|
1120
|
-
this.logger.debug('Padding checkpoint already started.');
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
this.logger.debug('Padding epoch proof with a padding block root proof.');
|
|
1125
|
-
|
|
1126
|
-
const inputs = provingState.getPaddingCheckpointInputs();
|
|
1127
|
-
|
|
1128
|
-
this.deferredProving(
|
|
1129
|
-
provingState,
|
|
1130
|
-
wrapCallbackInSpan(
|
|
1131
|
-
this.tracer,
|
|
1132
|
-
'ProvingOrchestrator.prover.getCheckpointPaddingRollupProof',
|
|
1133
|
-
{
|
|
1134
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-padding' satisfies CircuitName,
|
|
1135
|
-
},
|
|
1136
|
-
signal => this.prover.getCheckpointPaddingRollupProof(inputs, signal, provingState.epochNumber),
|
|
1137
|
-
),
|
|
1138
|
-
result => {
|
|
1139
|
-
this.logger.debug('Completed proof for padding checkpoint.');
|
|
1140
|
-
provingState.setCheckpointPaddingProof(result);
|
|
1141
|
-
this.checkAndEnqueueRootRollup(provingState);
|
|
1142
|
-
},
|
|
1143
|
-
);
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
// Executes the root rollup circuit
|
|
1147
|
-
private enqueueRootRollup(provingState: EpochProvingState) {
|
|
1148
|
-
if (!provingState.verifyState()) {
|
|
1149
|
-
this.logger.debug('Not running root rollup, state no longer valid');
|
|
1150
|
-
return;
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
this.logger.debug(`Preparing root rollup`);
|
|
1154
|
-
|
|
1155
|
-
const inputs = provingState.getRootRollupInputs();
|
|
1156
|
-
|
|
1157
|
-
this.deferredProving(
|
|
1158
|
-
provingState,
|
|
1159
|
-
wrapCallbackInSpan(
|
|
1160
|
-
this.tracer,
|
|
1161
|
-
'ProvingOrchestrator.prover.getRootRollupProof',
|
|
1162
|
-
{
|
|
1163
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-root' satisfies CircuitName,
|
|
1164
|
-
},
|
|
1165
|
-
signal => this.prover.getRootRollupProof(inputs, signal, provingState.epochNumber),
|
|
1166
|
-
),
|
|
1167
|
-
result => {
|
|
1168
|
-
this.logger.verbose(`Orchestrator completed root rollup for epoch ${provingState.epochNumber}`);
|
|
1169
|
-
provingState.setRootRollupProof(result);
|
|
1170
|
-
provingState.resolve({ status: 'success' });
|
|
1171
|
-
},
|
|
1172
|
-
);
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
1021
|
private checkAndEnqueueNextMergeRollup(provingState: BlockProvingState, currentLocation: TreeNodeLocation) {
|
|
1176
1022
|
if (!provingState.isReadyForMergeRollup(currentLocation)) {
|
|
1177
1023
|
return;
|
|
@@ -1210,7 +1056,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1210
1056
|
}
|
|
1211
1057
|
}
|
|
1212
1058
|
|
|
1213
|
-
|
|
1059
|
+
protected async checkAndEnqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
|
|
1214
1060
|
if (!provingState.isReadyForCheckpointRoot()) {
|
|
1215
1061
|
return;
|
|
1216
1062
|
}
|
|
@@ -1218,28 +1064,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1218
1064
|
await this.enqueueCheckpointRootRollup(provingState);
|
|
1219
1065
|
}
|
|
1220
1066
|
|
|
1221
|
-
private checkAndEnqueueNextCheckpointMergeRollup(provingState: EpochProvingState, currentLocation: TreeNodeLocation) {
|
|
1222
|
-
if (!provingState.isReadyForCheckpointMerge(currentLocation)) {
|
|
1223
|
-
return;
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
const parentLocation = provingState.getParentLocation(currentLocation);
|
|
1227
|
-
if (parentLocation.level === 0) {
|
|
1228
|
-
this.checkAndEnqueueRootRollup(provingState);
|
|
1229
|
-
} else {
|
|
1230
|
-
this.enqueueCheckpointMergeRollup(provingState, parentLocation);
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
private checkAndEnqueueRootRollup(provingState: EpochProvingState) {
|
|
1235
|
-
if (!provingState.isReadyForRootRollup()) {
|
|
1236
|
-
this.logger.debug('Not ready for root rollup');
|
|
1237
|
-
return;
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
this.enqueueRootRollup(provingState);
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
1067
|
/**
|
|
1244
1068
|
* Executes the VM circuit for a public function, will enqueue the corresponding kernel if the
|
|
1245
1069
|
* previous kernel is ready
|
|
@@ -1273,7 +1097,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
1273
1097
|
});
|
|
1274
1098
|
}
|
|
1275
1099
|
|
|
1276
|
-
|
|
1100
|
+
protected checkAndEnqueueBaseRollup(provingState: BlockProvingState, txIndex: number) {
|
|
1277
1101
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
1278
1102
|
if (!txProvingState.ready()) {
|
|
1279
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
|
+
}
|