@aztec/prover-client 0.65.1 → 0.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/block_builder/index.d.ts +6 -0
- package/dest/block_builder/index.d.ts.map +1 -0
- package/dest/block_builder/index.js +2 -0
- package/dest/block_builder/light.d.ts +32 -0
- package/dest/block_builder/light.d.ts.map +1 -0
- package/dest/block_builder/light.js +71 -0
- package/dest/config.d.ts +4 -10
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +8 -7
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +3 -3
- package/dest/mocks/fixtures.d.ts +1 -2
- package/dest/mocks/fixtures.d.ts.map +1 -1
- package/dest/mocks/fixtures.js +3 -7
- package/dest/mocks/test_context.d.ts +28 -10
- package/dest/mocks/test_context.d.ts.map +1 -1
- package/dest/mocks/test_context.js +59 -21
- package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
- package/dest/orchestrator/block-building-helpers.js +10 -18
- package/dest/orchestrator/block-proving-state.js +2 -2
- package/dest/orchestrator/epoch-proving-state.d.ts +5 -6
- package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/epoch-proving-state.js +10 -12
- package/dest/orchestrator/orchestrator.d.ts +8 -6
- package/dest/orchestrator/orchestrator.d.ts.map +1 -1
- package/dest/orchestrator/orchestrator.js +83 -72
- package/dest/orchestrator/tx-proving-state.d.ts +0 -1
- package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/tx-proving-state.js +2 -34
- package/dest/prover-agent/memory-proving-queue.d.ts +10 -8
- package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
- package/dest/prover-agent/memory-proving-queue.js +35 -35
- package/dest/prover-agent/prover-agent.d.ts +1 -0
- package/dest/prover-agent/prover-agent.d.ts.map +1 -1
- package/dest/prover-agent/prover-agent.js +12 -9
- package/dest/prover-client/factory.d.ts +6 -0
- package/dest/prover-client/factory.d.ts.map +1 -0
- package/dest/prover-client/factory.js +6 -0
- package/dest/prover-client/index.d.ts +3 -0
- package/dest/prover-client/index.d.ts.map +1 -0
- package/dest/prover-client/index.js +3 -0
- package/dest/prover-client/prover-client.d.ts +41 -0
- package/dest/prover-client/prover-client.d.ts.map +1 -0
- package/dest/prover-client/prover-client.js +107 -0
- package/dest/proving_broker/caching_broker_facade.d.ts +30 -0
- package/dest/proving_broker/caching_broker_facade.d.ts.map +1 -0
- package/dest/proving_broker/caching_broker_facade.js +150 -0
- package/dest/proving_broker/factory.d.ts +5 -0
- package/dest/proving_broker/factory.d.ts.map +1 -0
- package/dest/proving_broker/factory.js +17 -0
- package/dest/proving_broker/index.d.ts +9 -0
- package/dest/proving_broker/index.d.ts.map +1 -0
- package/dest/proving_broker/index.js +9 -0
- package/dest/proving_broker/proof_store.d.ts +46 -0
- package/dest/proving_broker/proof_store.d.ts.map +1 -0
- package/dest/proving_broker/proof_store.js +37 -0
- package/dest/proving_broker/prover_cache/memory.d.ts +9 -0
- package/dest/proving_broker/prover_cache/memory.d.ts.map +1 -0
- package/dest/proving_broker/prover_cache/memory.js +16 -0
- package/dest/proving_broker/proving_agent.d.ts +16 -6
- package/dest/proving_broker/proving_agent.d.ts.map +1 -1
- package/dest/proving_broker/proving_agent.js +59 -20
- package/dest/proving_broker/proving_agent_instrumentation.d.ts +8 -0
- package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +1 -0
- package/dest/proving_broker/proving_agent_instrumentation.js +16 -0
- package/dest/proving_broker/proving_broker.d.ts +22 -16
- package/dest/proving_broker/proving_broker.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker.js +79 -25
- package/dest/proving_broker/proving_broker_database/memory.d.ts +14 -0
- package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -0
- package/dest/proving_broker/proving_broker_database/memory.js +35 -0
- package/dest/proving_broker/proving_broker_database/persisted.d.ts +17 -0
- package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -0
- package/dest/proving_broker/proving_broker_database/persisted.js +43 -0
- package/dest/proving_broker/{proving_job_database.d.ts → proving_broker_database.d.ts} +8 -8
- package/dest/proving_broker/proving_broker_database.d.ts.map +1 -0
- package/dest/proving_broker/proving_broker_database.js +2 -0
- package/dest/proving_broker/proving_broker_instrumentation.d.ts +25 -0
- package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -0
- package/dest/proving_broker/proving_broker_instrumentation.js +91 -0
- package/dest/proving_broker/proving_job_controller.d.ts +13 -8
- package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
- package/dest/proving_broker/proving_job_controller.js +43 -43
- package/dest/proving_broker/rpc.d.ts +11 -0
- package/dest/proving_broker/rpc.d.ts.map +1 -0
- package/dest/proving_broker/rpc.js +44 -0
- package/dest/test/mock_prover.d.ts +16 -2
- package/dest/test/mock_prover.d.ts.map +1 -1
- package/dest/test/mock_prover.js +37 -1
- package/package.json +17 -14
- package/src/block_builder/index.ts +6 -0
- package/src/block_builder/light.ts +117 -0
- package/src/config.ts +17 -16
- package/src/index.ts +2 -2
- package/src/mocks/fixtures.ts +2 -14
- package/src/mocks/test_context.ts +81 -25
- package/src/orchestrator/block-building-helpers.ts +22 -33
- package/src/orchestrator/block-proving-state.ts +1 -1
- package/src/orchestrator/epoch-proving-state.ts +10 -13
- package/src/orchestrator/orchestrator.ts +97 -77
- package/src/orchestrator/tx-proving-state.ts +1 -56
- package/src/prover-agent/memory-proving-queue.ts +43 -44
- package/src/prover-agent/prover-agent.ts +16 -20
- package/src/prover-client/factory.ts +15 -0
- package/src/prover-client/index.ts +2 -0
- package/src/prover-client/prover-client.ts +172 -0
- package/src/proving_broker/caching_broker_facade.ts +312 -0
- package/src/proving_broker/factory.ts +25 -0
- package/src/proving_broker/index.ts +8 -0
- package/src/proving_broker/proof_store.ts +106 -0
- package/src/proving_broker/prover_cache/memory.ts +20 -0
- package/src/proving_broker/proving_agent.ts +90 -20
- package/src/proving_broker/proving_agent_instrumentation.ts +21 -0
- package/src/proving_broker/proving_broker.ts +143 -67
- package/src/proving_broker/proving_broker_database/memory.ts +43 -0
- package/src/proving_broker/proving_broker_database/persisted.ts +60 -0
- package/src/proving_broker/{proving_job_database.ts → proving_broker_database.ts} +7 -12
- package/src/proving_broker/proving_broker_instrumentation.ts +130 -0
- package/src/proving_broker/proving_job_controller.ts +54 -46
- package/src/proving_broker/rpc.ts +64 -0
- package/src/test/mock_prover.ts +52 -0
- package/dest/proving_broker/proving_broker_interface.d.ts +0 -61
- package/dest/proving_broker/proving_broker_interface.d.ts.map +0 -1
- package/dest/proving_broker/proving_broker_interface.js +0 -2
- package/dest/proving_broker/proving_job_database/memory.d.ts +0 -14
- package/dest/proving_broker/proving_job_database/memory.d.ts.map +0 -1
- package/dest/proving_broker/proving_job_database/memory.js +0 -35
- package/dest/proving_broker/proving_job_database/persisted.d.ts +0 -15
- package/dest/proving_broker/proving_job_database/persisted.d.ts.map +0 -1
- package/dest/proving_broker/proving_job_database/persisted.js +0 -35
- package/dest/proving_broker/proving_job_database.d.ts.map +0 -1
- package/dest/proving_broker/proving_job_database.js +0 -2
- package/dest/tx-prover/factory.d.ts +0 -5
- package/dest/tx-prover/factory.d.ts.map +0 -1
- package/dest/tx-prover/factory.js +0 -6
- package/dest/tx-prover/tx-prover.d.ts +0 -38
- package/dest/tx-prover/tx-prover.d.ts.map +0 -1
- package/dest/tx-prover/tx-prover.js +0 -93
- package/src/proving_broker/proving_broker_interface.ts +0 -74
- package/src/proving_broker/proving_job_database/memory.ts +0 -43
- package/src/proving_broker/proving_job_database/persisted.ts +0 -45
- package/src/tx-prover/factory.ts +0 -9
- package/src/tx-prover/tx-prover.ts +0 -130
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ProofAndVerificationKey,
|
|
3
|
+
type ProverCache,
|
|
4
|
+
type ProvingJobId,
|
|
5
|
+
type ProvingJobInputsMap,
|
|
6
|
+
type ProvingJobProducer,
|
|
7
|
+
type ProvingJobResultsMap,
|
|
8
|
+
ProvingRequestType,
|
|
9
|
+
type PublicInputsAndRecursiveProof,
|
|
10
|
+
type ServerCircuitProver,
|
|
11
|
+
} from '@aztec/circuit-types';
|
|
12
|
+
import {
|
|
13
|
+
type AVM_PROOF_LENGTH_IN_FIELDS,
|
|
14
|
+
type AvmCircuitInputs,
|
|
15
|
+
type BaseOrMergeRollupPublicInputs,
|
|
16
|
+
type BaseParityInputs,
|
|
17
|
+
type BlockMergeRollupInputs,
|
|
18
|
+
type BlockRootOrBlockMergePublicInputs,
|
|
19
|
+
type BlockRootRollupInputs,
|
|
20
|
+
type EmptyBlockRootRollupInputs,
|
|
21
|
+
type KernelCircuitPublicInputs,
|
|
22
|
+
type MergeRollupInputs,
|
|
23
|
+
type NESTED_RECURSIVE_PROOF_LENGTH,
|
|
24
|
+
type ParityPublicInputs,
|
|
25
|
+
type PrivateBaseRollupInputs,
|
|
26
|
+
type PrivateKernelEmptyInputData,
|
|
27
|
+
type PublicBaseRollupInputs,
|
|
28
|
+
type RECURSIVE_PROOF_LENGTH,
|
|
29
|
+
type RootParityInputs,
|
|
30
|
+
type RootRollupInputs,
|
|
31
|
+
type RootRollupPublicInputs,
|
|
32
|
+
type TUBE_PROOF_LENGTH,
|
|
33
|
+
type TubeInputs,
|
|
34
|
+
} from '@aztec/circuits.js';
|
|
35
|
+
import { sha256 } from '@aztec/foundation/crypto';
|
|
36
|
+
import { createDebugLogger } from '@aztec/foundation/log';
|
|
37
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
38
|
+
|
|
39
|
+
import { InlineProofStore, type ProofStore } from './proof_store.js';
|
|
40
|
+
import { InMemoryProverCache } from './prover_cache/memory.js';
|
|
41
|
+
|
|
42
|
+
// 20 minutes, roughly the length of an Aztec epoch. If a proof isn't ready in this amount of time then we've failed to prove the whole epoch
|
|
43
|
+
const MAX_WAIT_MS = 1_200_000;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A facade around a job broker that generates stable job ids and caches results
|
|
47
|
+
*/
|
|
48
|
+
export class CachingBrokerFacade implements ServerCircuitProver {
|
|
49
|
+
constructor(
|
|
50
|
+
private broker: ProvingJobProducer,
|
|
51
|
+
private cache: ProverCache = new InMemoryProverCache(),
|
|
52
|
+
private proofStore: ProofStore = new InlineProofStore(),
|
|
53
|
+
private waitTimeoutMs = MAX_WAIT_MS,
|
|
54
|
+
private pollIntervalMs = 1000,
|
|
55
|
+
private log = createDebugLogger('aztec:prover-client:caching-prover-broker'),
|
|
56
|
+
) {}
|
|
57
|
+
|
|
58
|
+
private async enqueueAndWaitForJob<T extends ProvingRequestType>(
|
|
59
|
+
id: ProvingJobId,
|
|
60
|
+
type: T,
|
|
61
|
+
inputs: ProvingJobInputsMap[T],
|
|
62
|
+
signal?: AbortSignal,
|
|
63
|
+
): Promise<ProvingJobResultsMap[T]> {
|
|
64
|
+
// first try the cache
|
|
65
|
+
let jobEnqueued = false;
|
|
66
|
+
try {
|
|
67
|
+
const cachedResult = await this.cache.getProvingJobStatus(id);
|
|
68
|
+
if (cachedResult.status !== 'not-found') {
|
|
69
|
+
this.log.debug(`Found cached result for job=${id}: status=${cachedResult.status}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (cachedResult.status === 'fulfilled') {
|
|
73
|
+
const output = await this.proofStore.getProofOutput(cachedResult.value);
|
|
74
|
+
if (output.type === type) {
|
|
75
|
+
return output.result as ProvingJobResultsMap[T];
|
|
76
|
+
} else {
|
|
77
|
+
this.log.warn(`Cached result type mismatch for job=${id}. Expected=${type} but got=${output.type}`);
|
|
78
|
+
}
|
|
79
|
+
} else if (cachedResult.status === 'rejected') {
|
|
80
|
+
// prefer returning a rejected promises so that we don't trigger the catch block below
|
|
81
|
+
return Promise.reject(new Error(cachedResult.reason));
|
|
82
|
+
} else if (cachedResult.status === 'in-progress' || cachedResult.status === 'in-queue') {
|
|
83
|
+
jobEnqueued = true;
|
|
84
|
+
} else {
|
|
85
|
+
jobEnqueued = false;
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
this.log.warn(`Failed to get cached proving job id=${id}: ${err}. Re-running job`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!jobEnqueued) {
|
|
92
|
+
try {
|
|
93
|
+
const inputsUri = await this.proofStore.saveProofInput(id, type, inputs);
|
|
94
|
+
await this.broker.enqueueProvingJob({
|
|
95
|
+
id,
|
|
96
|
+
type,
|
|
97
|
+
inputsUri,
|
|
98
|
+
});
|
|
99
|
+
await this.cache.setProvingJobStatus(id, { status: 'in-queue' });
|
|
100
|
+
} catch (err) {
|
|
101
|
+
this.log.error(`Failed to enqueue proving job id=${id}: ${err}`);
|
|
102
|
+
await this.cache.setProvingJobStatus(id, { status: 'not-found' });
|
|
103
|
+
throw err;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// notify broker of cancelled job
|
|
108
|
+
const abortFn = async () => {
|
|
109
|
+
signal?.removeEventListener('abort', abortFn);
|
|
110
|
+
await this.broker.removeAndCancelProvingJob(id);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
signal?.addEventListener('abort', abortFn);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
// loop here until the job settles
|
|
117
|
+
// NOTE: this could also terminate because the job was cancelled through event listener above
|
|
118
|
+
const result = await retryUntil(
|
|
119
|
+
async () => {
|
|
120
|
+
try {
|
|
121
|
+
return await this.broker.waitForJobToSettle(id);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
// waitForJobToSettle can only fail for network errors
|
|
124
|
+
// keep retrying until we time out
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
`Proving job=${id} type=${ProvingRequestType[type]}`,
|
|
128
|
+
this.waitTimeoutMs / 1000,
|
|
129
|
+
this.pollIntervalMs / 1000,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await this.cache.setProvingJobStatus(id, result);
|
|
134
|
+
} catch (err) {
|
|
135
|
+
this.log.warn(`Failed to cache proving job id=${id} resultStatus=${result.status}: ${err}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (result.status === 'fulfilled') {
|
|
139
|
+
const output = await this.proofStore.getProofOutput(result.value);
|
|
140
|
+
if (output.type === type) {
|
|
141
|
+
return output.result as ProvingJobResultsMap[T];
|
|
142
|
+
} else {
|
|
143
|
+
return Promise.reject(new Error(`Unexpected proof type: ${output.type}. Expected: ${type}`));
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
return Promise.reject(new Error(result.reason));
|
|
147
|
+
}
|
|
148
|
+
} finally {
|
|
149
|
+
signal?.removeEventListener('abort', abortFn);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
getAvmProof(
|
|
154
|
+
inputs: AvmCircuitInputs,
|
|
155
|
+
signal?: AbortSignal,
|
|
156
|
+
_blockNumber?: number,
|
|
157
|
+
): Promise<ProofAndVerificationKey<typeof AVM_PROOF_LENGTH_IN_FIELDS>> {
|
|
158
|
+
return this.enqueueAndWaitForJob(
|
|
159
|
+
this.generateId(ProvingRequestType.PUBLIC_VM, inputs),
|
|
160
|
+
ProvingRequestType.PUBLIC_VM,
|
|
161
|
+
inputs,
|
|
162
|
+
signal,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
getBaseParityProof(
|
|
167
|
+
inputs: BaseParityInputs,
|
|
168
|
+
signal?: AbortSignal,
|
|
169
|
+
_epochNumber?: number,
|
|
170
|
+
): Promise<PublicInputsAndRecursiveProof<ParityPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
171
|
+
return this.enqueueAndWaitForJob(
|
|
172
|
+
this.generateId(ProvingRequestType.BASE_PARITY, inputs),
|
|
173
|
+
ProvingRequestType.BASE_PARITY,
|
|
174
|
+
inputs,
|
|
175
|
+
signal,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
getBlockMergeRollupProof(
|
|
180
|
+
input: BlockMergeRollupInputs,
|
|
181
|
+
signal?: AbortSignal,
|
|
182
|
+
_epochNumber?: number,
|
|
183
|
+
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
184
|
+
return this.enqueueAndWaitForJob(
|
|
185
|
+
this.generateId(ProvingRequestType.BLOCK_MERGE_ROLLUP, input),
|
|
186
|
+
ProvingRequestType.BLOCK_MERGE_ROLLUP,
|
|
187
|
+
input,
|
|
188
|
+
signal,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getBlockRootRollupProof(
|
|
193
|
+
input: BlockRootRollupInputs,
|
|
194
|
+
signal?: AbortSignal,
|
|
195
|
+
_epochNumber?: number,
|
|
196
|
+
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
197
|
+
return this.enqueueAndWaitForJob(
|
|
198
|
+
this.generateId(ProvingRequestType.BLOCK_ROOT_ROLLUP, input),
|
|
199
|
+
ProvingRequestType.BLOCK_ROOT_ROLLUP,
|
|
200
|
+
input,
|
|
201
|
+
signal,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
getEmptyBlockRootRollupProof(
|
|
206
|
+
input: EmptyBlockRootRollupInputs,
|
|
207
|
+
signal?: AbortSignal,
|
|
208
|
+
_epochNumber?: number,
|
|
209
|
+
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>> {
|
|
210
|
+
return this.enqueueAndWaitForJob(
|
|
211
|
+
this.generateId(ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP, input),
|
|
212
|
+
ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP,
|
|
213
|
+
input,
|
|
214
|
+
signal,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
getEmptyPrivateKernelProof(
|
|
219
|
+
inputs: PrivateKernelEmptyInputData,
|
|
220
|
+
signal?: AbortSignal,
|
|
221
|
+
_epochNumber?: number,
|
|
222
|
+
): Promise<PublicInputsAndRecursiveProof<KernelCircuitPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
223
|
+
return this.enqueueAndWaitForJob(
|
|
224
|
+
this.generateId(ProvingRequestType.PRIVATE_KERNEL_EMPTY, inputs),
|
|
225
|
+
ProvingRequestType.PRIVATE_KERNEL_EMPTY,
|
|
226
|
+
inputs,
|
|
227
|
+
signal,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
getMergeRollupProof(
|
|
232
|
+
input: MergeRollupInputs,
|
|
233
|
+
signal?: AbortSignal,
|
|
234
|
+
_epochNumber?: number,
|
|
235
|
+
): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
236
|
+
return this.enqueueAndWaitForJob(
|
|
237
|
+
this.generateId(ProvingRequestType.MERGE_ROLLUP, input),
|
|
238
|
+
ProvingRequestType.MERGE_ROLLUP,
|
|
239
|
+
input,
|
|
240
|
+
signal,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
getPrivateBaseRollupProof(
|
|
244
|
+
baseRollupInput: PrivateBaseRollupInputs,
|
|
245
|
+
signal?: AbortSignal,
|
|
246
|
+
_epochNumber?: number,
|
|
247
|
+
): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
248
|
+
return this.enqueueAndWaitForJob(
|
|
249
|
+
this.generateId(ProvingRequestType.PRIVATE_BASE_ROLLUP, baseRollupInput),
|
|
250
|
+
ProvingRequestType.PRIVATE_BASE_ROLLUP,
|
|
251
|
+
baseRollupInput,
|
|
252
|
+
signal,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
getPublicBaseRollupProof(
|
|
257
|
+
inputs: PublicBaseRollupInputs,
|
|
258
|
+
signal?: AbortSignal,
|
|
259
|
+
_epochNumber?: number,
|
|
260
|
+
): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
261
|
+
return this.enqueueAndWaitForJob(
|
|
262
|
+
this.generateId(ProvingRequestType.PUBLIC_BASE_ROLLUP, inputs),
|
|
263
|
+
ProvingRequestType.PUBLIC_BASE_ROLLUP,
|
|
264
|
+
inputs,
|
|
265
|
+
signal,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
getRootParityProof(
|
|
270
|
+
inputs: RootParityInputs,
|
|
271
|
+
signal?: AbortSignal,
|
|
272
|
+
_epochNumber?: number,
|
|
273
|
+
): Promise<PublicInputsAndRecursiveProof<ParityPublicInputs, typeof NESTED_RECURSIVE_PROOF_LENGTH>> {
|
|
274
|
+
return this.enqueueAndWaitForJob(
|
|
275
|
+
this.generateId(ProvingRequestType.ROOT_PARITY, inputs),
|
|
276
|
+
ProvingRequestType.ROOT_PARITY,
|
|
277
|
+
inputs,
|
|
278
|
+
signal,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
getRootRollupProof(
|
|
283
|
+
input: RootRollupInputs,
|
|
284
|
+
signal?: AbortSignal,
|
|
285
|
+
_epochNumber?: number,
|
|
286
|
+
): Promise<PublicInputsAndRecursiveProof<RootRollupPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
287
|
+
return this.enqueueAndWaitForJob(
|
|
288
|
+
this.generateId(ProvingRequestType.ROOT_ROLLUP, input),
|
|
289
|
+
ProvingRequestType.ROOT_ROLLUP,
|
|
290
|
+
input,
|
|
291
|
+
signal,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
getTubeProof(
|
|
296
|
+
tubeInput: TubeInputs,
|
|
297
|
+
signal?: AbortSignal,
|
|
298
|
+
_epochNumber?: number,
|
|
299
|
+
): Promise<ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>> {
|
|
300
|
+
return this.enqueueAndWaitForJob(
|
|
301
|
+
this.generateId(ProvingRequestType.TUBE_PROOF, tubeInput),
|
|
302
|
+
ProvingRequestType.TUBE_PROOF,
|
|
303
|
+
tubeInput,
|
|
304
|
+
signal,
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private generateId(type: ProvingRequestType, inputs: { toBuffer(): Buffer }) {
|
|
309
|
+
const inputsHash = sha256(inputs.toBuffer());
|
|
310
|
+
return `${ProvingRequestType[type]}:${inputsHash.toString('hex')}`;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ProverBrokerConfig } from '@aztec/circuit-types';
|
|
2
|
+
import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
|
|
3
|
+
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
4
|
+
|
|
5
|
+
import { ProvingBroker } from './proving_broker.js';
|
|
6
|
+
import { InMemoryBrokerDatabase } from './proving_broker_database/memory.js';
|
|
7
|
+
import { KVBrokerDatabase } from './proving_broker_database/persisted.js';
|
|
8
|
+
|
|
9
|
+
export async function createAndStartProvingBroker(
|
|
10
|
+
config: ProverBrokerConfig,
|
|
11
|
+
client: TelemetryClient,
|
|
12
|
+
): Promise<ProvingBroker> {
|
|
13
|
+
const database = config.proverBrokerDataDirectory
|
|
14
|
+
? new KVBrokerDatabase(AztecLmdbStore.open(config.proverBrokerDataDirectory), client)
|
|
15
|
+
: new InMemoryBrokerDatabase();
|
|
16
|
+
|
|
17
|
+
const broker = new ProvingBroker(database, client, {
|
|
18
|
+
jobTimeoutMs: config.proverBrokerJobTimeoutMs,
|
|
19
|
+
maxRetries: config.proverBrokerJobMaxRetries,
|
|
20
|
+
timeoutIntervalMs: config.proverBrokerPollIntervalMs,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
await broker.start();
|
|
24
|
+
return broker;
|
|
25
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './proving_agent.js';
|
|
2
|
+
export * from './proving_broker.js';
|
|
3
|
+
export * from './rpc.js';
|
|
4
|
+
export * from './proving_broker_database.js';
|
|
5
|
+
export * from './proving_broker_database/memory.js';
|
|
6
|
+
export * from './proving_broker_database/persisted.js';
|
|
7
|
+
export * from './proof_store.js';
|
|
8
|
+
export * from './factory.js';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ProofUri,
|
|
3
|
+
type ProvingJobId,
|
|
4
|
+
ProvingJobInputs,
|
|
5
|
+
type ProvingJobInputsMap,
|
|
6
|
+
ProvingJobResult,
|
|
7
|
+
type ProvingJobResultsMap,
|
|
8
|
+
type ProvingRequestType,
|
|
9
|
+
} from '@aztec/circuit-types';
|
|
10
|
+
import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
|
|
11
|
+
import { type ZodFor } from '@aztec/foundation/schemas';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A database for storing proof inputs and outputs.
|
|
15
|
+
*/
|
|
16
|
+
export interface ProofStore {
|
|
17
|
+
/**
|
|
18
|
+
* Save a proof input to the database.
|
|
19
|
+
* @param jobId - The ID of the job the proof input is associated with.
|
|
20
|
+
* @param type - The type of the proving request.
|
|
21
|
+
* @param inputs - The proof input to save.
|
|
22
|
+
* @returns The URI of the saved proof input.
|
|
23
|
+
*/
|
|
24
|
+
saveProofInput<T extends ProvingRequestType>(
|
|
25
|
+
jobId: ProvingJobId,
|
|
26
|
+
type: T,
|
|
27
|
+
inputs: ProvingJobInputsMap[T],
|
|
28
|
+
): Promise<ProofUri>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Save a proof output to the database.
|
|
32
|
+
* @param jobId - The ID of the job the proof input is associated with.
|
|
33
|
+
* @param type - The type of the proving request.
|
|
34
|
+
* @param result - The proof output to save.
|
|
35
|
+
* @returns The URI of the saved proof output.
|
|
36
|
+
*/
|
|
37
|
+
saveProofOutput<T extends ProvingRequestType>(
|
|
38
|
+
id: ProvingJobId,
|
|
39
|
+
type: T,
|
|
40
|
+
result: ProvingJobResultsMap[T],
|
|
41
|
+
): Promise<ProofUri>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Retrieve a proof input from the database.
|
|
45
|
+
* @param uri - The URI of the proof input to retrieve.
|
|
46
|
+
* @returns The proof input.
|
|
47
|
+
*/
|
|
48
|
+
getProofInput(uri: ProofUri): Promise<ProvingJobInputs>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Retrieve a proof output from the database.
|
|
52
|
+
* @param uri - The URI of the proof output to retrieve.
|
|
53
|
+
* @returns The proof output.
|
|
54
|
+
*/
|
|
55
|
+
getProofOutput(uri: ProofUri): Promise<ProvingJobResult>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// use an ASCII encoded data uri https://datatracker.ietf.org/doc/html/rfc2397#section-2
|
|
59
|
+
// we do this to avoid double encoding to base64 (since the inputs already serialize to a base64 string)
|
|
60
|
+
const PREFIX = 'data:application/json;charset=utf-8';
|
|
61
|
+
const SEPARATOR = ',';
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* An implementation of a proof input/output database that stores data inline in the URI.
|
|
65
|
+
*/
|
|
66
|
+
export class InlineProofStore implements ProofStore {
|
|
67
|
+
saveProofInput<T extends ProvingRequestType>(
|
|
68
|
+
_id: ProvingJobId,
|
|
69
|
+
type: T,
|
|
70
|
+
inputs: ProvingJobInputsMap[T],
|
|
71
|
+
): Promise<ProofUri> {
|
|
72
|
+
const jobInputs = { type, inputs } as ProvingJobInputs;
|
|
73
|
+
return Promise.resolve(this.encode(jobInputs));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
saveProofOutput<T extends ProvingRequestType>(
|
|
77
|
+
_id: ProvingJobId,
|
|
78
|
+
type: T,
|
|
79
|
+
result: ProvingJobResultsMap[T],
|
|
80
|
+
): Promise<ProofUri> {
|
|
81
|
+
const jobResult = { type, result } as ProvingJobResult;
|
|
82
|
+
return Promise.resolve(this.encode(jobResult));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getProofInput(uri: ProofUri): Promise<ProvingJobInputs> {
|
|
86
|
+
return Promise.resolve(this.decode(uri, ProvingJobInputs));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getProofOutput(uri: ProofUri): Promise<ProvingJobResult> {
|
|
90
|
+
return Promise.resolve(this.decode(uri, ProvingJobResult));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private encode(obj: object): ProofUri {
|
|
94
|
+
const encoded = encodeURIComponent(jsonStringify(obj));
|
|
95
|
+
return (PREFIX + SEPARATOR + encoded) as ProofUri;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private decode<T>(uri: ProofUri, schema: ZodFor<T>): T {
|
|
99
|
+
const [prefix, data] = uri.split(SEPARATOR);
|
|
100
|
+
if (prefix !== PREFIX) {
|
|
101
|
+
throw new Error('Invalid proof input URI: ' + prefix);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return jsonParseWithSchema(decodeURIComponent(data), schema);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ProverCache, ProvingJobStatus } from '@aztec/circuit-types';
|
|
2
|
+
|
|
3
|
+
export class InMemoryProverCache implements ProverCache {
|
|
4
|
+
private proofs: Record<string, ProvingJobStatus> = {};
|
|
5
|
+
|
|
6
|
+
constructor() {}
|
|
7
|
+
|
|
8
|
+
setProvingJobStatus(jobId: string, status: ProvingJobStatus): Promise<void> {
|
|
9
|
+
this.proofs[jobId] = status;
|
|
10
|
+
return Promise.resolve();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getProvingJobStatus(jobId: string): Promise<ProvingJobStatus> {
|
|
14
|
+
return Promise.resolve(this.proofs[jobId] ?? { status: 'not-found' });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
close(): Promise<void> {
|
|
18
|
+
return Promise.resolve();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProvingError,
|
|
3
|
-
type
|
|
3
|
+
type ProvingJob,
|
|
4
|
+
type ProvingJobConsumer,
|
|
5
|
+
type ProvingJobId,
|
|
6
|
+
type ProvingJobInputs,
|
|
7
|
+
type ProvingJobResultsMap,
|
|
8
|
+
ProvingRequestType,
|
|
4
9
|
type ServerCircuitProver,
|
|
5
|
-
type V2ProvingJob,
|
|
6
10
|
} from '@aztec/circuit-types';
|
|
7
11
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
8
12
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
13
|
+
import { Timer } from '@aztec/foundation/timer';
|
|
14
|
+
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
9
15
|
|
|
10
|
-
import { type
|
|
11
|
-
import {
|
|
16
|
+
import { type ProofStore } from './proof_store.js';
|
|
17
|
+
import { ProvingAgentInstrumentation } from './proving_agent_instrumentation.js';
|
|
18
|
+
import { ProvingJobController, ProvingJobControllerStatus } from './proving_job_controller.js';
|
|
12
19
|
|
|
13
20
|
/**
|
|
14
21
|
* A helper class that encapsulates a circuit prover and connects it to a job source.
|
|
@@ -16,18 +23,25 @@ import { ProvingJobController, ProvingJobStatus } from './proving_job_controller
|
|
|
16
23
|
export class ProvingAgent {
|
|
17
24
|
private currentJobController?: ProvingJobController;
|
|
18
25
|
private runningPromise: RunningPromise;
|
|
26
|
+
private instrumentation: ProvingAgentInstrumentation;
|
|
27
|
+
private idleTimer: Timer | undefined;
|
|
19
28
|
|
|
20
29
|
constructor(
|
|
21
30
|
/** The source of proving jobs */
|
|
22
|
-
private
|
|
31
|
+
private broker: ProvingJobConsumer,
|
|
32
|
+
/** Database holding proof inputs and outputs */
|
|
33
|
+
private proofStore: ProofStore,
|
|
23
34
|
/** The prover implementation to defer jobs to */
|
|
24
35
|
private circuitProver: ServerCircuitProver,
|
|
36
|
+
/** A telemetry client through which to emit metrics */
|
|
37
|
+
client: TelemetryClient,
|
|
25
38
|
/** Optional list of allowed proof types to build */
|
|
26
|
-
private proofAllowList
|
|
39
|
+
private proofAllowList: Array<ProvingRequestType> = [],
|
|
27
40
|
/** How long to wait between jobs */
|
|
28
41
|
private pollIntervalMs = 1000,
|
|
29
|
-
private log = createDebugLogger('aztec:
|
|
42
|
+
private log = createDebugLogger('aztec:prover-client:proving-agent'),
|
|
30
43
|
) {
|
|
44
|
+
this.instrumentation = new ProvingAgentInstrumentation(client);
|
|
31
45
|
this.runningPromise = new RunningPromise(this.safeWork, this.pollIntervalMs);
|
|
32
46
|
}
|
|
33
47
|
|
|
@@ -40,6 +54,7 @@ export class ProvingAgent {
|
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
public start(): void {
|
|
57
|
+
this.idleTimer = new Timer();
|
|
43
58
|
this.runningPromise.start();
|
|
44
59
|
}
|
|
45
60
|
|
|
@@ -54,37 +69,92 @@ export class ProvingAgent {
|
|
|
54
69
|
// (1) either do a heartbeat, telling the broker that we're working
|
|
55
70
|
// (2) get a new job
|
|
56
71
|
// If during (1) the broker returns a new job that means we can cancel the current job and start the new one
|
|
57
|
-
let maybeJob: { job:
|
|
58
|
-
if (this.currentJobController?.getStatus() ===
|
|
59
|
-
maybeJob = await this.
|
|
72
|
+
let maybeJob: { job: ProvingJob; time: number } | undefined;
|
|
73
|
+
if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.PROVING) {
|
|
74
|
+
maybeJob = await this.broker.reportProvingJobProgress(
|
|
60
75
|
this.currentJobController.getJobId(),
|
|
61
76
|
this.currentJobController.getStartedAt(),
|
|
62
77
|
{ allowList: this.proofAllowList },
|
|
63
78
|
);
|
|
64
79
|
} else {
|
|
65
|
-
maybeJob = await this.
|
|
80
|
+
maybeJob = await this.broker.getProvingJob({ allowList: this.proofAllowList });
|
|
66
81
|
}
|
|
67
82
|
|
|
68
83
|
if (!maybeJob) {
|
|
69
84
|
return;
|
|
70
85
|
}
|
|
71
86
|
|
|
72
|
-
|
|
87
|
+
let abortedProofJobId: string | undefined;
|
|
88
|
+
let abortedProofName: string | undefined;
|
|
89
|
+
if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.PROVING) {
|
|
90
|
+
abortedProofJobId = this.currentJobController.getJobId();
|
|
91
|
+
abortedProofName = this.currentJobController.getProofTypeName();
|
|
73
92
|
this.currentJobController?.abort();
|
|
74
93
|
}
|
|
75
94
|
|
|
76
95
|
const { job, time } = maybeJob;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
let inputs: ProvingJobInputs;
|
|
97
|
+
try {
|
|
98
|
+
inputs = await this.proofStore.getProofInput(job.inputsUri);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
await this.broker.reportProvingJobError(job.id, 'Failed to load proof inputs', true);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.currentJobController = new ProvingJobController(
|
|
105
|
+
job.id,
|
|
106
|
+
inputs,
|
|
107
|
+
time,
|
|
108
|
+
this.circuitProver,
|
|
109
|
+
this.handleJobResult,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
if (abortedProofJobId) {
|
|
113
|
+
this.log.info(
|
|
114
|
+
`Aborting job id=${abortedProofJobId} type=${abortedProofName} to start new job id=${this.currentJobController.getJobId()} type=${this.currentJobController.getProofTypeName()} inputsUri=${truncateString(
|
|
115
|
+
job.inputsUri,
|
|
116
|
+
)}`,
|
|
117
|
+
);
|
|
118
|
+
} else {
|
|
119
|
+
this.log.info(
|
|
120
|
+
`Starting job id=${this.currentJobController.getJobId()} type=${this.currentJobController.getProofTypeName()} inputsUri=${truncateString(
|
|
121
|
+
job.inputsUri,
|
|
122
|
+
)}`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (this.idleTimer) {
|
|
127
|
+
this.instrumentation.recordIdleTime(this.idleTimer);
|
|
128
|
+
}
|
|
129
|
+
this.idleTimer = undefined;
|
|
130
|
+
|
|
85
131
|
this.currentJobController.start();
|
|
86
132
|
} catch (err) {
|
|
87
133
|
this.log.error(`Error in ProvingAgent: ${String(err)}`);
|
|
88
134
|
}
|
|
89
135
|
};
|
|
136
|
+
|
|
137
|
+
handleJobResult = async <T extends ProvingRequestType>(
|
|
138
|
+
jobId: ProvingJobId,
|
|
139
|
+
type: T,
|
|
140
|
+
err: Error | undefined,
|
|
141
|
+
result: ProvingJobResultsMap[T] | undefined,
|
|
142
|
+
) => {
|
|
143
|
+
this.idleTimer = new Timer();
|
|
144
|
+
if (err) {
|
|
145
|
+
const retry = err.name === ProvingError.NAME ? (err as ProvingError).retry : false;
|
|
146
|
+
this.log.error(`Job id=${jobId} type=${ProvingRequestType[type]} failed err=${err.message} retry=${retry}`, err);
|
|
147
|
+
return this.broker.reportProvingJobError(jobId, err.message, retry);
|
|
148
|
+
} else if (result) {
|
|
149
|
+
const outputUri = await this.proofStore.saveProofOutput(jobId, type, result);
|
|
150
|
+
this.log.info(
|
|
151
|
+
`Job id=${jobId} type=${ProvingRequestType[type]} completed outputUri=${truncateString(outputUri)}`,
|
|
152
|
+
);
|
|
153
|
+
return this.broker.reportProvingJobSuccess(jobId, outputUri);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function truncateString(str: string, length: number = 64): string {
|
|
159
|
+
return str.length > length ? str.slice(0, length) + '...' : str;
|
|
90
160
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Timer } from '@aztec/foundation/timer';
|
|
2
|
+
import { type Histogram, Metrics, type TelemetryClient, ValueType } from '@aztec/telemetry-client';
|
|
3
|
+
|
|
4
|
+
export class ProvingAgentInstrumentation {
|
|
5
|
+
private idleTime: Histogram;
|
|
6
|
+
|
|
7
|
+
constructor(client: TelemetryClient, name = 'ProvingAgent') {
|
|
8
|
+
const meter = client.getMeter(name);
|
|
9
|
+
|
|
10
|
+
this.idleTime = meter.createHistogram(Metrics.PROVING_AGENT_IDLE, {
|
|
11
|
+
description: 'Records how long an agent was idle',
|
|
12
|
+
unit: 'ms',
|
|
13
|
+
valueType: ValueType.INT,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
recordIdleTime(msOrTimer: Timer | number) {
|
|
18
|
+
const duration = typeof msOrTimer === 'number' ? msOrTimer : Math.floor(msOrTimer.ms());
|
|
19
|
+
this.idleTime.record(duration);
|
|
20
|
+
}
|
|
21
|
+
}
|