@aztec/prover-client 0.69.0-devnet → 0.69.1-devnet
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/light.d.ts +0 -1
- package/dest/block_builder/light.d.ts.map +1 -1
- package/dest/block_builder/light.js +4 -14
- package/dest/config.d.ts +2 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +3 -2
- package/dest/mocks/test_context.d.ts +2 -2
- package/dest/mocks/test_context.d.ts.map +1 -1
- package/dest/mocks/test_context.js +6 -6
- package/dest/orchestrator/block-building-helpers.d.ts +10 -25
- package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
- package/dest/orchestrator/block-building-helpers.js +33 -44
- package/dest/orchestrator/block-proving-state.d.ts +40 -44
- package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/block-proving-state.js +149 -85
- package/dest/orchestrator/epoch-proving-state.d.ts +23 -30
- package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/epoch-proving-state.js +92 -65
- package/dest/orchestrator/orchestrator.d.ts +16 -47
- package/dest/orchestrator/orchestrator.d.ts.map +1 -1
- package/dest/orchestrator/orchestrator.js +204 -341
- package/dest/orchestrator/tx-proving-state.d.ts +10 -6
- package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/tx-proving-state.js +57 -46
- package/dest/prover-agent/memory-proving-queue.d.ts +3 -3
- package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
- package/dest/prover-agent/memory-proving-queue.js +4 -4
- package/dest/prover-agent/prover-agent.js +4 -4
- package/dest/prover-client/prover-client.d.ts.map +1 -1
- package/dest/prover-client/prover-client.js +5 -2
- package/dest/prover-client/server-epoch-prover.d.ts +25 -0
- package/dest/prover-client/server-epoch-prover.d.ts.map +1 -0
- package/dest/prover-client/server-epoch-prover.js +40 -0
- package/dest/proving_broker/broker_prover_facade.d.ts +15 -4
- package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
- package/dest/proving_broker/broker_prover_facade.js +247 -44
- package/dest/proving_broker/config.d.ts +61 -0
- package/dest/proving_broker/config.d.ts.map +1 -0
- package/dest/proving_broker/config.js +83 -0
- package/dest/proving_broker/factory.d.ts +1 -1
- package/dest/proving_broker/factory.d.ts.map +1 -1
- package/dest/proving_broker/factory.js +2 -5
- package/dest/proving_broker/fixtures.d.ts +5 -0
- package/dest/proving_broker/fixtures.d.ts.map +1 -0
- package/dest/proving_broker/fixtures.js +12 -0
- package/dest/proving_broker/index.d.ts +1 -0
- package/dest/proving_broker/index.d.ts.map +1 -1
- package/dest/proving_broker/index.js +2 -1
- package/dest/proving_broker/proving_broker.d.ts +16 -12
- package/dest/proving_broker/proving_broker.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker.js +306 -273
- package/dest/proving_broker/proving_broker_database/memory.d.ts +4 -2
- package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker_database/memory.js +17 -4
- package/dest/proving_broker/proving_broker_database/persisted.d.ts +10 -6
- package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker_database/persisted.js +105 -13
- package/dest/proving_broker/proving_broker_database.d.ts +7 -3
- package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
- package/dest/proving_broker/proving_job_controller.js +4 -4
- package/dest/proving_broker/rpc.d.ts.map +1 -1
- package/dest/proving_broker/rpc.js +4 -4
- package/dest/test/mock_prover.d.ts +6 -6
- package/dest/test/mock_prover.d.ts.map +1 -1
- package/dest/test/mock_prover.js +6 -6
- package/package.json +11 -11
- package/src/block_builder/light.ts +3 -21
- package/src/config.ts +4 -4
- package/src/mocks/test_context.ts +3 -6
- package/src/orchestrator/block-building-helpers.ts +44 -118
- package/src/orchestrator/block-proving-state.ts +251 -121
- package/src/orchestrator/epoch-proving-state.ts +159 -88
- package/src/orchestrator/orchestrator.ts +251 -527
- package/src/orchestrator/tx-proving-state.ts +35 -19
- package/src/prover-agent/memory-proving-queue.ts +11 -12
- package/src/prover-agent/prover-agent.ts +4 -4
- package/src/prover-client/prover-client.ts +4 -6
- package/src/prover-client/server-epoch-prover.ts +44 -0
- package/src/proving_broker/broker_prover_facade.ts +321 -61
- package/src/proving_broker/config.ts +93 -0
- package/src/proving_broker/factory.ts +2 -5
- package/src/proving_broker/fixtures.ts +14 -0
- package/src/proving_broker/index.ts +1 -0
- package/src/proving_broker/proving_broker.ts +114 -71
- package/src/proving_broker/proving_broker_database/memory.ts +24 -4
- package/src/proving_broker/proving_broker_database/persisted.ts +141 -19
- package/src/proving_broker/proving_broker_database.ts +8 -3
- package/src/proving_broker/proving_job_controller.ts +5 -5
- package/src/proving_broker/rpc.ts +2 -3
- package/src/test/mock_prover.ts +9 -11
|
@@ -9,10 +9,9 @@ import {
|
|
|
9
9
|
type ProvingJobStatus,
|
|
10
10
|
ProvingRequestType,
|
|
11
11
|
} from '@aztec/circuit-types';
|
|
12
|
-
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
13
12
|
import { createLogger } from '@aztec/foundation/log';
|
|
14
13
|
import { type PromiseWithResolvers, RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
15
|
-
import { PriorityMemoryQueue } from '@aztec/foundation/queue';
|
|
14
|
+
import { PriorityMemoryQueue, SerialQueue } from '@aztec/foundation/queue';
|
|
16
15
|
import { Timer } from '@aztec/foundation/timer';
|
|
17
16
|
import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
18
17
|
|
|
@@ -45,7 +44,6 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
45
44
|
private queues: ProvingQueues = {
|
|
46
45
|
[ProvingRequestType.PUBLIC_VM]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
47
46
|
[ProvingRequestType.TUBE_PROOF]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
48
|
-
[ProvingRequestType.PRIVATE_KERNEL_EMPTY]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
49
47
|
|
|
50
48
|
[ProvingRequestType.PRIVATE_BASE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
51
49
|
[ProvingRequestType.PUBLIC_BASE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
@@ -54,6 +52,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
54
52
|
|
|
55
53
|
[ProvingRequestType.BLOCK_MERGE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
56
54
|
[ProvingRequestType.BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
55
|
+
[ProvingRequestType.SINGLE_TX_BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
57
56
|
[ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
58
57
|
|
|
59
58
|
[ProvingRequestType.BASE_PARITY]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
|
|
@@ -89,21 +88,24 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
89
88
|
private instrumentation: ProvingBrokerInstrumentation;
|
|
90
89
|
public readonly tracer: Tracer;
|
|
91
90
|
|
|
92
|
-
private
|
|
91
|
+
private completedJobNotifications: ProvingJobId[] = [];
|
|
93
92
|
|
|
94
93
|
/**
|
|
95
94
|
* The broker keeps track of the highest epoch its seen.
|
|
96
95
|
* This information is used for garbage collection: once it reaches the next epoch, it can start pruning the database of old state.
|
|
97
|
-
*
|
|
98
|
-
*
|
|
96
|
+
* It is important that this value is initialised to zero. This ensures that we don't delete any old jobs until the current
|
|
97
|
+
* process instance receives a job request informing it of the actual current highest epoch
|
|
99
98
|
* Example:
|
|
100
|
-
* proving epoch 11 - the broker will wipe all
|
|
101
|
-
* finished proving epoch 11 and got first job for epoch 12 -> the broker will wipe all
|
|
102
|
-
* reorged back to end of epoch 10 -> epoch 11 is skipped and epoch 12 starts -> the broker will wipe all
|
|
99
|
+
* proving epoch 11 - the broker will wipe all jobs for epochs 9 and lower
|
|
100
|
+
* finished proving epoch 11 and got first job for epoch 12 -> the broker will wipe all settled jobs for epochs 10 and lower
|
|
101
|
+
* reorged back to end of epoch 10 -> epoch 11 is skipped and epoch 12 starts -> the broker will wipe all settled jobs for epochs 10 and lower
|
|
103
102
|
*/
|
|
104
103
|
private epochHeight = 0;
|
|
105
104
|
private maxEpochsToKeepResultsFor = 1;
|
|
106
105
|
|
|
106
|
+
private requestQueue: SerialQueue = new SerialQueue();
|
|
107
|
+
private started = false;
|
|
108
|
+
|
|
107
109
|
public constructor(
|
|
108
110
|
private database: ProvingBrokerDatabase,
|
|
109
111
|
client: TelemetryClient,
|
|
@@ -112,7 +114,6 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
112
114
|
timeoutIntervalMs = 10_000,
|
|
113
115
|
maxRetries = 3,
|
|
114
116
|
maxEpochsToKeepResultsFor = 1,
|
|
115
|
-
maxParallelCleanUps = 20,
|
|
116
117
|
}: ProofRequestBrokerConfig = {},
|
|
117
118
|
private logger = createLogger('prover-client:proving-broker'),
|
|
118
119
|
) {
|
|
@@ -122,7 +123,6 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
122
123
|
this.jobTimeoutMs = jobTimeoutMs;
|
|
123
124
|
this.maxRetries = maxRetries;
|
|
124
125
|
this.maxEpochsToKeepResultsFor = maxEpochsToKeepResultsFor;
|
|
125
|
-
this.maxParallelCleanUps = maxParallelCleanUps;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
private measureQueueDepth: MonitorCallback = (type: ProvingRequestType) => {
|
|
@@ -142,6 +142,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
public start(): Promise<void> {
|
|
145
|
+
if (this.started) {
|
|
146
|
+
this.logger.info('Proving Broker already started');
|
|
147
|
+
return Promise.resolve();
|
|
148
|
+
}
|
|
149
|
+
this.logger.info('Proving Broker started');
|
|
145
150
|
for (const [item, result] of this.database.allProvingJobs()) {
|
|
146
151
|
this.logger.info(`Restoring proving job id=${item.id} settled=${!!result}`, {
|
|
147
152
|
provingJobId: item.id,
|
|
@@ -161,24 +166,71 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
161
166
|
|
|
162
167
|
this.cleanupPromise.start();
|
|
163
168
|
|
|
169
|
+
this.requestQueue.start();
|
|
170
|
+
|
|
164
171
|
this.instrumentation.monitorQueueDepth(this.measureQueueDepth);
|
|
165
172
|
this.instrumentation.monitorActiveJobs(this.countActiveJobs);
|
|
166
173
|
|
|
174
|
+
this.started = true;
|
|
175
|
+
|
|
167
176
|
return Promise.resolve();
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
public async stop(): Promise<void> {
|
|
180
|
+
if (!this.started) {
|
|
181
|
+
this.logger.warn('ProvingBroker not started');
|
|
182
|
+
return Promise.resolve();
|
|
183
|
+
}
|
|
184
|
+
await this.requestQueue.cancel();
|
|
171
185
|
await this.cleanupPromise.stop();
|
|
172
186
|
}
|
|
173
187
|
|
|
174
|
-
public
|
|
188
|
+
public enqueueProvingJob(job: ProvingJob): Promise<ProvingJobStatus> {
|
|
189
|
+
return this.requestQueue.put(() => this.#enqueueProvingJob(job));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public cancelProvingJob(id: ProvingJobId): Promise<void> {
|
|
193
|
+
return this.requestQueue.put(() => this.#cancelProvingJob(id));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public getProvingJobStatus(id: ProvingJobId): Promise<ProvingJobStatus> {
|
|
197
|
+
return this.requestQueue.put(() => this.#getProvingJobStatus(id));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public getCompletedJobs(ids: ProvingJobId[]): Promise<ProvingJobId[]> {
|
|
201
|
+
return this.requestQueue.put(() => this.#getCompletedJobs(ids));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public getProvingJob(filter?: ProvingJobFilter): Promise<{ job: ProvingJob; time: number } | undefined> {
|
|
205
|
+
return this.requestQueue.put(() => this.#getProvingJob(filter));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public reportProvingJobSuccess(id: ProvingJobId, value: ProofUri): Promise<void> {
|
|
209
|
+
return this.requestQueue.put(() => this.#reportProvingJobSuccess(id, value));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
public reportProvingJobError(id: ProvingJobId, err: string, retry = false): Promise<void> {
|
|
213
|
+
return this.requestQueue.put(() => this.#reportProvingJobError(id, err, retry));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
public reportProvingJobProgress(
|
|
217
|
+
id: ProvingJobId,
|
|
218
|
+
startedAt: number,
|
|
219
|
+
filter?: ProvingJobFilter,
|
|
220
|
+
): Promise<{ job: ProvingJob; time: number } | undefined> {
|
|
221
|
+
return this.requestQueue.put(() => this.#reportProvingJobProgress(id, startedAt, filter));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async #enqueueProvingJob(job: ProvingJob): Promise<ProvingJobStatus> {
|
|
225
|
+
// We return the job status at the start of this call
|
|
226
|
+
const jobStatus = await this.#getProvingJobStatus(job.id);
|
|
175
227
|
if (this.jobsCache.has(job.id)) {
|
|
176
228
|
const existing = this.jobsCache.get(job.id);
|
|
177
229
|
assert.deepStrictEqual(job, existing, 'Duplicate proving job ID');
|
|
178
230
|
this.logger.debug(`Duplicate proving job id=${job.id} epochNumber=${job.epochNumber}. Ignoring`, {
|
|
179
231
|
provingJobId: job.id,
|
|
180
232
|
});
|
|
181
|
-
return;
|
|
233
|
+
return jobStatus;
|
|
182
234
|
}
|
|
183
235
|
|
|
184
236
|
if (this.isJobStale(job)) {
|
|
@@ -199,18 +251,10 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
199
251
|
this.jobsCache.delete(job.id);
|
|
200
252
|
throw err;
|
|
201
253
|
}
|
|
254
|
+
return jobStatus;
|
|
202
255
|
}
|
|
203
256
|
|
|
204
|
-
|
|
205
|
-
const promiseWithResolvers = this.promises.get(id);
|
|
206
|
-
if (!promiseWithResolvers) {
|
|
207
|
-
this.logger.warn(`Job id=${id} not found`, { provingJobId: id });
|
|
208
|
-
return Promise.resolve({ status: 'rejected', reason: `Job ${id} not found` });
|
|
209
|
-
}
|
|
210
|
-
return promiseWithResolvers.promise;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
public async cancelProvingJob(id: ProvingJobId): Promise<void> {
|
|
257
|
+
async #cancelProvingJob(id: ProvingJobId): Promise<void> {
|
|
214
258
|
if (!this.jobsCache.has(id)) {
|
|
215
259
|
this.logger.warn(`Can't cancel a job that doesn't exist id=${id}`, { provingJobId: id });
|
|
216
260
|
return;
|
|
@@ -219,31 +263,21 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
219
263
|
// notify listeners of the cancellation
|
|
220
264
|
if (!this.resultsCache.has(id)) {
|
|
221
265
|
this.logger.info(`Cancelling job id=${id}`, { provingJobId: id });
|
|
222
|
-
await this
|
|
266
|
+
await this.#reportProvingJobError(id, 'Aborted', false);
|
|
223
267
|
}
|
|
224
268
|
}
|
|
225
269
|
|
|
226
|
-
private
|
|
227
|
-
|
|
228
|
-
this.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
this.logger.warn(`Can't cleanup busy proving job: id=${id}`, { provingJobId: id });
|
|
234
|
-
return;
|
|
270
|
+
private cleanUpProvingJobState(ids: ProvingJobId[]) {
|
|
271
|
+
for (const id of ids) {
|
|
272
|
+
this.jobsCache.delete(id);
|
|
273
|
+
this.promises.delete(id);
|
|
274
|
+
this.resultsCache.delete(id);
|
|
275
|
+
this.inProgress.delete(id);
|
|
276
|
+
this.retries.delete(id);
|
|
235
277
|
}
|
|
236
|
-
|
|
237
|
-
this.logger.debug(`Cleaning up state for job id=${id}`, { provingJobId: id });
|
|
238
|
-
await this.database.deleteProvingJobAndResult(id);
|
|
239
|
-
this.jobsCache.delete(id);
|
|
240
|
-
this.promises.delete(id);
|
|
241
|
-
this.resultsCache.delete(id);
|
|
242
|
-
this.inProgress.delete(id);
|
|
243
|
-
this.retries.delete(id);
|
|
244
278
|
}
|
|
245
279
|
|
|
246
|
-
|
|
280
|
+
#getProvingJobStatus(id: ProvingJobId): Promise<ProvingJobStatus> {
|
|
247
281
|
const result = this.resultsCache.get(id);
|
|
248
282
|
if (result) {
|
|
249
283
|
return Promise.resolve(result);
|
|
@@ -252,7 +286,6 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
252
286
|
const item = this.jobsCache.get(id);
|
|
253
287
|
|
|
254
288
|
if (!item) {
|
|
255
|
-
this.logger.warn(`Proving job id=${id} not found`, { provingJobId: id });
|
|
256
289
|
return Promise.resolve({ status: 'not-found' });
|
|
257
290
|
}
|
|
258
291
|
|
|
@@ -260,8 +293,15 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
260
293
|
}
|
|
261
294
|
}
|
|
262
295
|
|
|
296
|
+
#getCompletedJobs(ids: ProvingJobId[]): Promise<ProvingJobId[]> {
|
|
297
|
+
const completedJobs = ids.filter(id => this.resultsCache.has(id));
|
|
298
|
+
const notifications = this.completedJobNotifications;
|
|
299
|
+
this.completedJobNotifications = [];
|
|
300
|
+
return Promise.resolve(notifications.concat(completedJobs));
|
|
301
|
+
}
|
|
302
|
+
|
|
263
303
|
// eslint-disable-next-line require-await
|
|
264
|
-
async getProvingJob(
|
|
304
|
+
async #getProvingJob(
|
|
265
305
|
filter: ProvingJobFilter = { allowList: [] },
|
|
266
306
|
): Promise<{ job: ProvingJob; time: number } | undefined> {
|
|
267
307
|
const allowedProofs: ProvingRequestType[] =
|
|
@@ -299,7 +339,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
299
339
|
return undefined;
|
|
300
340
|
}
|
|
301
341
|
|
|
302
|
-
async reportProvingJobError(id: ProvingJobId, err: string, retry = false): Promise<void> {
|
|
342
|
+
async #reportProvingJobError(id: ProvingJobId, err: string, retry = false): Promise<void> {
|
|
303
343
|
const info = this.inProgress.get(id);
|
|
304
344
|
const item = this.jobsCache.get(id);
|
|
305
345
|
const retries = this.retries.get(id) ?? 0;
|
|
@@ -351,6 +391,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
351
391
|
const result: ProvingJobSettledResult = { status: 'rejected', reason: String(err) };
|
|
352
392
|
this.resultsCache.set(id, result);
|
|
353
393
|
this.promises.get(id)!.resolve(result);
|
|
394
|
+
this.completedJobNotifications.push(id);
|
|
354
395
|
|
|
355
396
|
this.instrumentation.incRejectedJobs(item.type);
|
|
356
397
|
if (info) {
|
|
@@ -369,7 +410,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
369
410
|
}
|
|
370
411
|
}
|
|
371
412
|
|
|
372
|
-
reportProvingJobProgress(
|
|
413
|
+
#reportProvingJobProgress(
|
|
373
414
|
id: ProvingJobId,
|
|
374
415
|
startedAt: number,
|
|
375
416
|
filter?: ProvingJobFilter,
|
|
@@ -377,12 +418,12 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
377
418
|
const job = this.jobsCache.get(id);
|
|
378
419
|
if (!job) {
|
|
379
420
|
this.logger.warn(`Proving job id=${id} does not exist`, { provingJobId: id });
|
|
380
|
-
return filter ? this
|
|
421
|
+
return filter ? this.#getProvingJob(filter) : Promise.resolve(undefined);
|
|
381
422
|
}
|
|
382
423
|
|
|
383
424
|
if (this.resultsCache.has(id)) {
|
|
384
425
|
this.logger.warn(`Proving job id=${id} has already been completed`, { provingJobId: id });
|
|
385
|
-
return filter ? this
|
|
426
|
+
return filter ? this.#getProvingJob(filter) : Promise.resolve(undefined);
|
|
386
427
|
}
|
|
387
428
|
|
|
388
429
|
const metadata = this.inProgress.get(id);
|
|
@@ -420,13 +461,13 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
420
461
|
} already being worked on by another agent. Sending new one`,
|
|
421
462
|
{ provingJobId: id },
|
|
422
463
|
);
|
|
423
|
-
return this
|
|
464
|
+
return this.#getProvingJob(filter);
|
|
424
465
|
} else {
|
|
425
466
|
return Promise.resolve(undefined);
|
|
426
467
|
}
|
|
427
468
|
}
|
|
428
469
|
|
|
429
|
-
async reportProvingJobSuccess(id: ProvingJobId, value: ProofUri): Promise<void> {
|
|
470
|
+
async #reportProvingJobSuccess(id: ProvingJobId, value: ProofUri): Promise<void> {
|
|
430
471
|
const info = this.inProgress.get(id);
|
|
431
472
|
const item = this.jobsCache.get(id);
|
|
432
473
|
const retries = this.retries.get(id) ?? 0;
|
|
@@ -459,6 +500,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
459
500
|
const result: ProvingJobSettledResult = { status: 'fulfilled', value };
|
|
460
501
|
this.resultsCache.set(id, result);
|
|
461
502
|
this.promises.get(id)!.resolve(result);
|
|
503
|
+
this.completedJobNotifications.push(id);
|
|
462
504
|
|
|
463
505
|
this.instrumentation.incResolvedJobs(item.type);
|
|
464
506
|
if (info) {
|
|
@@ -479,30 +521,32 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
479
521
|
|
|
480
522
|
@trackSpan('ProvingBroker.cleanupPass')
|
|
481
523
|
private async cleanupPass() {
|
|
482
|
-
|
|
483
|
-
|
|
524
|
+
this.cleanupStaleJobs();
|
|
525
|
+
this.reEnqueueExpiredJobs();
|
|
526
|
+
const oldestEpochToKeep = this.oldestEpochToKeep();
|
|
527
|
+
if (oldestEpochToKeep > 0) {
|
|
528
|
+
await this.requestQueue.put(() => this.database.deleteAllProvingJobsOlderThanEpoch(oldestEpochToKeep));
|
|
529
|
+
this.logger.trace(`Deleted all epochs older than ${oldestEpochToKeep}`);
|
|
530
|
+
}
|
|
484
531
|
}
|
|
485
532
|
|
|
486
|
-
private
|
|
533
|
+
private cleanupStaleJobs() {
|
|
487
534
|
const jobIds = Array.from(this.jobsCache.keys());
|
|
488
535
|
const jobsToClean: ProvingJobId[] = [];
|
|
489
536
|
for (const id of jobIds) {
|
|
490
537
|
const job = this.jobsCache.get(id)!;
|
|
491
|
-
|
|
492
|
-
if (isComplete && this.isJobStale(job)) {
|
|
538
|
+
if (this.isJobStale(job)) {
|
|
493
539
|
jobsToClean.push(id);
|
|
494
540
|
}
|
|
495
541
|
}
|
|
496
542
|
|
|
497
543
|
if (jobsToClean.length > 0) {
|
|
498
|
-
this.
|
|
499
|
-
|
|
500
|
-
await this.cleanUpProvingJobState(jobId);
|
|
501
|
-
});
|
|
544
|
+
this.cleanUpProvingJobState(jobsToClean);
|
|
545
|
+
this.logger.info(`Cleaned up jobs=${jobsToClean.length}`);
|
|
502
546
|
}
|
|
503
547
|
}
|
|
504
548
|
|
|
505
|
-
private
|
|
549
|
+
private reEnqueueExpiredJobs() {
|
|
506
550
|
const inProgressEntries = Array.from(this.inProgress.entries());
|
|
507
551
|
for (const [id, metadata] of inProgressEntries) {
|
|
508
552
|
const item = this.jobsCache.get(id);
|
|
@@ -515,15 +559,10 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
515
559
|
const now = this.msTimeSource();
|
|
516
560
|
const msSinceLastUpdate = now - metadata.lastUpdatedAt;
|
|
517
561
|
if (msSinceLastUpdate >= this.jobTimeoutMs) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
this.logger.warn(`Proving job id=${id} timed out. Adding it back to the queue.`, { provingJobId: id });
|
|
523
|
-
this.inProgress.delete(id);
|
|
524
|
-
this.enqueueJobInternal(item);
|
|
525
|
-
this.instrumentation.incTimedOutJobs(item.type);
|
|
526
|
-
}
|
|
562
|
+
this.logger.warn(`Proving job id=${id} timed out. Adding it back to the queue.`, { provingJobId: id });
|
|
563
|
+
this.inProgress.delete(id);
|
|
564
|
+
this.enqueueJobInternal(item);
|
|
565
|
+
this.instrumentation.incTimedOutJobs(item.type);
|
|
527
566
|
}
|
|
528
567
|
}
|
|
529
568
|
}
|
|
@@ -541,7 +580,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
|
|
|
541
580
|
}
|
|
542
581
|
|
|
543
582
|
private isJobStale(job: ProvingJob) {
|
|
544
|
-
return job.epochNumber < this.
|
|
583
|
+
return job.epochNumber < this.oldestEpochToKeep();
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
private oldestEpochToKeep() {
|
|
587
|
+
return this.epochHeight - this.maxEpochsToKeepResultsFor;
|
|
545
588
|
}
|
|
546
589
|
}
|
|
547
590
|
|
|
@@ -601,6 +644,7 @@ function proofTypeComparator(a: ProvingRequestType, b: ProvingRequestType): -1 |
|
|
|
601
644
|
*/
|
|
602
645
|
const PROOF_TYPES_IN_PRIORITY_ORDER: ProvingRequestType[] = [
|
|
603
646
|
ProvingRequestType.BLOCK_ROOT_ROLLUP,
|
|
647
|
+
ProvingRequestType.SINGLE_TX_BLOCK_ROOT_ROLLUP,
|
|
604
648
|
ProvingRequestType.BLOCK_MERGE_ROLLUP,
|
|
605
649
|
ProvingRequestType.ROOT_ROLLUP,
|
|
606
650
|
ProvingRequestType.MERGE_ROLLUP,
|
|
@@ -611,5 +655,4 @@ const PROOF_TYPES_IN_PRIORITY_ORDER: ProvingRequestType[] = [
|
|
|
611
655
|
ProvingRequestType.ROOT_PARITY,
|
|
612
656
|
ProvingRequestType.BASE_PARITY,
|
|
613
657
|
ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP,
|
|
614
|
-
ProvingRequestType.PRIVATE_KERNEL_EMPTY,
|
|
615
658
|
];
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
type ProofUri,
|
|
3
|
+
type ProvingJob,
|
|
4
|
+
type ProvingJobId,
|
|
5
|
+
type ProvingJobSettledResult,
|
|
6
|
+
getEpochFromProvingJobId,
|
|
7
|
+
} from '@aztec/circuit-types';
|
|
2
8
|
|
|
3
9
|
import { type ProvingBrokerDatabase } from '../proving_broker_database.js';
|
|
4
10
|
|
|
@@ -29,15 +35,29 @@ export class InMemoryBrokerDatabase implements ProvingBrokerDatabase {
|
|
|
29
35
|
return Promise.resolve();
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
deleteProvingJobs(ids: ProvingJobId[]): Promise<void> {
|
|
39
|
+
for (const id of ids) {
|
|
40
|
+
this.jobs.delete(id);
|
|
41
|
+
this.results.delete(id);
|
|
42
|
+
}
|
|
35
43
|
return Promise.resolve();
|
|
36
44
|
}
|
|
37
45
|
|
|
46
|
+
deleteAllProvingJobsOlderThanEpoch(epochNumber: number): Promise<void> {
|
|
47
|
+
const toDelete = [
|
|
48
|
+
...Array.from(this.jobs.keys()).filter(x => getEpochFromProvingJobId(x) < epochNumber),
|
|
49
|
+
...Array.from(this.results.keys()).filter(x => getEpochFromProvingJobId(x) < epochNumber),
|
|
50
|
+
];
|
|
51
|
+
return this.deleteProvingJobs(toDelete);
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
*allProvingJobs(): Iterable<[ProvingJob, ProvingJobSettledResult | undefined]> {
|
|
39
55
|
for (const item of this.jobs.values()) {
|
|
40
56
|
yield [item, this.results.get(item.id)] as const;
|
|
41
57
|
}
|
|
42
58
|
}
|
|
59
|
+
|
|
60
|
+
close(): Promise<void> {
|
|
61
|
+
return Promise.resolve();
|
|
62
|
+
}
|
|
43
63
|
}
|
|
@@ -1,27 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ProofUri,
|
|
3
|
+
ProvingJob,
|
|
4
|
+
type ProvingJobId,
|
|
5
|
+
ProvingJobSettledResult,
|
|
6
|
+
getEpochFromProvingJobId,
|
|
7
|
+
} from '@aztec/circuit-types';
|
|
2
8
|
import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
|
|
3
|
-
import { type
|
|
9
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
10
|
+
import { type AztecMap } from '@aztec/kv-store';
|
|
11
|
+
import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
|
|
4
12
|
import { Attributes, LmdbMetrics, type TelemetryClient } from '@aztec/telemetry-client';
|
|
5
13
|
|
|
14
|
+
import { mkdir, readdir } from 'fs/promises';
|
|
15
|
+
import { join } from 'path';
|
|
16
|
+
|
|
17
|
+
import { type ProverBrokerConfig } from '../config.js';
|
|
6
18
|
import { type ProvingBrokerDatabase } from '../proving_broker_database.js';
|
|
7
19
|
|
|
8
|
-
|
|
20
|
+
class SingleEpochDatabase {
|
|
9
21
|
private jobs: AztecMap<ProvingJobId, string>;
|
|
10
22
|
private jobResults: AztecMap<ProvingJobId, string>;
|
|
11
|
-
private metrics: LmdbMetrics;
|
|
12
23
|
|
|
13
|
-
constructor(
|
|
14
|
-
this.metrics = new LmdbMetrics(
|
|
15
|
-
client.getMeter('KVBrokerDatabase'),
|
|
16
|
-
{
|
|
17
|
-
[Attributes.DB_DATA_TYPE]: 'prover-broker',
|
|
18
|
-
},
|
|
19
|
-
() => store.estimateSize(),
|
|
20
|
-
);
|
|
24
|
+
constructor(public readonly store: AztecLmdbStore) {
|
|
21
25
|
this.jobs = store.openMap('proving_jobs');
|
|
22
26
|
this.jobResults = store.openMap('proving_job_results');
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
estimateSize() {
|
|
30
|
+
return this.store.estimateSize();
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
async addProvingJob(job: ProvingJob): Promise<void> {
|
|
26
34
|
await this.jobs.set(job.id, jsonStringify(job));
|
|
27
35
|
}
|
|
@@ -35,13 +43,6 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
|
|
|
35
43
|
}
|
|
36
44
|
}
|
|
37
45
|
|
|
38
|
-
deleteProvingJobAndResult(id: ProvingJobId): Promise<void> {
|
|
39
|
-
return this.store.transaction(() => {
|
|
40
|
-
void this.jobs.delete(id);
|
|
41
|
-
void this.jobResults.delete(id);
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
46
|
async setProvingJobError(id: ProvingJobId, reason: string): Promise<void> {
|
|
46
47
|
const result: ProvingJobSettledResult = { status: 'rejected', reason };
|
|
47
48
|
await this.jobResults.set(id, jsonStringify(result));
|
|
@@ -51,4 +52,125 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
|
|
|
51
52
|
const result: ProvingJobSettledResult = { status: 'fulfilled', value };
|
|
52
53
|
await this.jobResults.set(id, jsonStringify(result));
|
|
53
54
|
}
|
|
55
|
+
|
|
56
|
+
delete() {
|
|
57
|
+
return this.store.delete();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
close() {
|
|
61
|
+
return this.store.close();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class KVBrokerDatabase implements ProvingBrokerDatabase {
|
|
66
|
+
private metrics: LmdbMetrics;
|
|
67
|
+
|
|
68
|
+
private constructor(
|
|
69
|
+
private epochs: Map<number, SingleEpochDatabase>,
|
|
70
|
+
private config: ProverBrokerConfig,
|
|
71
|
+
client: TelemetryClient,
|
|
72
|
+
private logger: Logger,
|
|
73
|
+
) {
|
|
74
|
+
this.metrics = new LmdbMetrics(
|
|
75
|
+
client.getMeter('KVBrokerDatabase'),
|
|
76
|
+
{
|
|
77
|
+
[Attributes.DB_DATA_TYPE]: 'prover-broker',
|
|
78
|
+
},
|
|
79
|
+
() => this.estimateSize(),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private estimateSize() {
|
|
84
|
+
const sizes = Array.from(this.epochs.values()).map(x => x.estimateSize());
|
|
85
|
+
return {
|
|
86
|
+
mappingSize: this.config.dataStoreMapSizeKB,
|
|
87
|
+
numItems: sizes.reduce((prev, curr) => prev + curr.numItems, 0),
|
|
88
|
+
actualSize: sizes.reduce((prev, curr) => prev + curr.actualSize, 0),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public static async new(
|
|
93
|
+
config: ProverBrokerConfig,
|
|
94
|
+
client: TelemetryClient,
|
|
95
|
+
logger = createLogger('prover-client:proving-broker-database'),
|
|
96
|
+
) {
|
|
97
|
+
const epochs: Map<number, SingleEpochDatabase> = new Map<number, SingleEpochDatabase>();
|
|
98
|
+
const files = await readdir(config.dataDirectory!, { recursive: false, withFileTypes: true });
|
|
99
|
+
for (const file of files) {
|
|
100
|
+
if (!file.isDirectory()) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const fullDirectory = join(config.dataDirectory!, file.name);
|
|
104
|
+
const epochDirectory = file.name;
|
|
105
|
+
const epochNumber = parseInt(epochDirectory, 10);
|
|
106
|
+
if (!Number.isSafeInteger(epochNumber) || epochNumber < 0) {
|
|
107
|
+
logger.warn(`Found invalid epoch directory ${fullDirectory} when loading epoch databases, ignoring`);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
logger.info(
|
|
111
|
+
`Loading broker database for epoch ${epochNumber} from ${fullDirectory} with map size ${config.dataStoreMapSizeKB}KB`,
|
|
112
|
+
);
|
|
113
|
+
const db = AztecLmdbStore.open(fullDirectory, config.dataStoreMapSizeKB, false);
|
|
114
|
+
const epochDb = new SingleEpochDatabase(db);
|
|
115
|
+
epochs.set(epochNumber, epochDb);
|
|
116
|
+
}
|
|
117
|
+
return new KVBrokerDatabase(epochs, config, client, logger);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async close(): Promise<void> {
|
|
121
|
+
for (const [_, v] of this.epochs) {
|
|
122
|
+
await v.close();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async deleteAllProvingJobsOlderThanEpoch(epochNumber: number): Promise<void> {
|
|
127
|
+
const oldEpochs = Array.from(this.epochs.keys()).filter(e => e < epochNumber);
|
|
128
|
+
for (const old of oldEpochs) {
|
|
129
|
+
const db = this.epochs.get(old);
|
|
130
|
+
if (!db) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
this.logger.info(`Deleting broker database for epoch ${old}`);
|
|
134
|
+
await db.delete();
|
|
135
|
+
this.epochs.delete(old);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async addProvingJob(job: ProvingJob): Promise<void> {
|
|
140
|
+
let epochDb = this.epochs.get(job.epochNumber);
|
|
141
|
+
if (!epochDb) {
|
|
142
|
+
const newEpochDirectory = join(this.config.dataDirectory!, job.epochNumber.toString());
|
|
143
|
+
await mkdir(newEpochDirectory, { recursive: true });
|
|
144
|
+
this.logger.info(
|
|
145
|
+
`Creating broker database for epoch ${job.epochNumber} at ${newEpochDirectory} with map size ${this.config.dataStoreMapSizeKB}`,
|
|
146
|
+
);
|
|
147
|
+
const db = AztecLmdbStore.open(newEpochDirectory, this.config.dataStoreMapSizeKB, false);
|
|
148
|
+
epochDb = new SingleEpochDatabase(db);
|
|
149
|
+
this.epochs.set(job.epochNumber, epochDb);
|
|
150
|
+
}
|
|
151
|
+
await epochDb.addProvingJob(job);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
*allProvingJobs(): Iterable<[ProvingJob, ProvingJobSettledResult | undefined]> {
|
|
155
|
+
const iterators = Array.from(this.epochs.values()).map(x => x.allProvingJobs());
|
|
156
|
+
for (const it of iterators) {
|
|
157
|
+
yield* it;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async setProvingJobError(id: ProvingJobId, reason: string): Promise<void> {
|
|
162
|
+
const epochDb = this.epochs.get(getEpochFromProvingJobId(id));
|
|
163
|
+
if (!epochDb) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
await epochDb.setProvingJobError(id, reason);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async setProvingJobResult(id: ProvingJobId, value: ProofUri): Promise<void> {
|
|
170
|
+
const epochDb = this.epochs.get(getEpochFromProvingJobId(id));
|
|
171
|
+
if (!epochDb) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
await epochDb.setProvingJobResult(id, value);
|
|
175
|
+
}
|
|
54
176
|
}
|
|
@@ -11,10 +11,10 @@ export interface ProvingBrokerDatabase {
|
|
|
11
11
|
addProvingJob(request: ProvingJob): Promise<void>;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
* @param
|
|
14
|
+
* Deletes all proving jobs belonging to epochs older than the given epoch
|
|
15
|
+
* @param epochNumber - The epoch number beyond which jobs should be deleted
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
deleteAllProvingJobsOlderThanEpoch(epochNumber: number): Promise<void>;
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Returns an iterator over all saved proving jobs
|
|
@@ -36,4 +36,9 @@ export interface ProvingBrokerDatabase {
|
|
|
36
36
|
* @param err - The error that occurred while processing the proof request
|
|
37
37
|
*/
|
|
38
38
|
setProvingJobError(id: ProvingJobId, err: string): Promise<void>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Closes the database
|
|
42
|
+
*/
|
|
43
|
+
close(): Promise<void>;
|
|
39
44
|
}
|