@aztec/prover-client 0.69.1 → 0.71.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.
Files changed (130) hide show
  1. package/dest/bin/get-proof-inputs.d.ts +2 -0
  2. package/dest/bin/get-proof-inputs.d.ts.map +1 -0
  3. package/dest/bin/get-proof-inputs.js +50 -0
  4. package/dest/block_builder/light.d.ts +3 -5
  5. package/dest/block_builder/light.d.ts.map +1 -1
  6. package/dest/block_builder/light.js +9 -22
  7. package/dest/config.d.ts +2 -1
  8. package/dest/config.d.ts.map +1 -1
  9. package/dest/config.js +3 -2
  10. package/dest/mocks/fixtures.d.ts +1 -1
  11. package/dest/mocks/fixtures.d.ts.map +1 -1
  12. package/dest/mocks/fixtures.js +2 -2
  13. package/dest/mocks/test_context.d.ts +1 -1
  14. package/dest/mocks/test_context.d.ts.map +1 -1
  15. package/dest/mocks/test_context.js +11 -12
  16. package/dest/orchestrator/block-building-helpers.d.ts +15 -29
  17. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  18. package/dest/orchestrator/block-building-helpers.js +51 -58
  19. package/dest/orchestrator/block-proving-state.d.ts +40 -44
  20. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  21. package/dest/orchestrator/block-proving-state.js +149 -85
  22. package/dest/orchestrator/epoch-proving-state.d.ts +23 -30
  23. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  24. package/dest/orchestrator/epoch-proving-state.js +92 -65
  25. package/dest/orchestrator/orchestrator.d.ts +17 -48
  26. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  27. package/dest/orchestrator/orchestrator.js +208 -351
  28. package/dest/orchestrator/tx-proving-state.d.ts +10 -6
  29. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  30. package/dest/orchestrator/tx-proving-state.js +57 -46
  31. package/dest/prover-agent/memory-proving-queue.d.ts +4 -4
  32. package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
  33. package/dest/prover-agent/memory-proving-queue.js +5 -5
  34. package/dest/prover-agent/prover-agent.d.ts +0 -2
  35. package/dest/prover-agent/prover-agent.d.ts.map +1 -1
  36. package/dest/prover-agent/prover-agent.js +7 -9
  37. package/dest/prover-client/factory.d.ts.map +1 -1
  38. package/dest/prover-client/factory.js +3 -3
  39. package/dest/prover-client/prover-client.d.ts +4 -2
  40. package/dest/prover-client/prover-client.d.ts.map +1 -1
  41. package/dest/prover-client/prover-client.js +16 -15
  42. package/dest/prover-client/server-epoch-prover.d.ts +25 -0
  43. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -0
  44. package/dest/prover-client/server-epoch-prover.js +40 -0
  45. package/dest/proving_broker/broker_prover_facade.d.ts +19 -7
  46. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  47. package/dest/proving_broker/broker_prover_facade.js +271 -49
  48. package/dest/proving_broker/config.d.ts +61 -0
  49. package/dest/proving_broker/config.d.ts.map +1 -0
  50. package/dest/proving_broker/config.js +83 -0
  51. package/dest/proving_broker/factory.d.ts +1 -1
  52. package/dest/proving_broker/factory.d.ts.map +1 -1
  53. package/dest/proving_broker/factory.js +4 -7
  54. package/dest/proving_broker/fixtures.d.ts +5 -0
  55. package/dest/proving_broker/fixtures.d.ts.map +1 -0
  56. package/dest/proving_broker/fixtures.js +12 -0
  57. package/dest/proving_broker/index.d.ts +2 -1
  58. package/dest/proving_broker/index.d.ts.map +1 -1
  59. package/dest/proving_broker/index.js +3 -2
  60. package/dest/proving_broker/proof_store/factory.d.ts +6 -0
  61. package/dest/proving_broker/proof_store/factory.d.ts.map +1 -0
  62. package/dest/proving_broker/proof_store/factory.js +39 -0
  63. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +13 -0
  64. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +1 -0
  65. package/dest/proving_broker/proof_store/gcs_proof_store.js +46 -0
  66. package/dest/proving_broker/proof_store/index.d.ts +4 -0
  67. package/dest/proving_broker/proof_store/index.d.ts.map +1 -0
  68. package/dest/proving_broker/proof_store/index.js +4 -0
  69. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +14 -0
  70. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -0
  71. package/dest/proving_broker/proof_store/inline_proof_store.js +37 -0
  72. package/dest/proving_broker/{proof_store.d.ts → proof_store/proof_store.d.ts} +1 -12
  73. package/dest/proving_broker/proof_store/proof_store.d.ts.map +1 -0
  74. package/dest/proving_broker/proof_store/proof_store.js +2 -0
  75. package/dest/proving_broker/proving_agent.d.ts +4 -4
  76. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  77. package/dest/proving_broker/proving_agent.js +5 -5
  78. package/dest/proving_broker/proving_broker.d.ts +16 -12
  79. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  80. package/dest/proving_broker/proving_broker.js +307 -274
  81. package/dest/proving_broker/proving_broker_database/memory.d.ts +4 -2
  82. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
  83. package/dest/proving_broker/proving_broker_database/memory.js +17 -4
  84. package/dest/proving_broker/proving_broker_database/persisted.d.ts +10 -6
  85. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  86. package/dest/proving_broker/proving_broker_database/persisted.js +106 -14
  87. package/dest/proving_broker/proving_broker_database.d.ts +7 -3
  88. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
  89. package/dest/proving_broker/proving_job_controller.js +4 -4
  90. package/dest/proving_broker/rpc.d.ts.map +1 -1
  91. package/dest/proving_broker/rpc.js +4 -4
  92. package/dest/test/mock_prover.d.ts +8 -8
  93. package/dest/test/mock_prover.d.ts.map +1 -1
  94. package/dest/test/mock_prover.js +9 -10
  95. package/package.json +14 -12
  96. package/src/bin/get-proof-inputs.ts +60 -0
  97. package/src/block_builder/light.ts +7 -31
  98. package/src/config.ts +4 -4
  99. package/src/mocks/fixtures.ts +1 -1
  100. package/src/mocks/test_context.ts +9 -11
  101. package/src/orchestrator/block-building-helpers.ts +360 -402
  102. package/src/orchestrator/block-proving-state.ts +251 -121
  103. package/src/orchestrator/epoch-proving-state.ts +159 -88
  104. package/src/orchestrator/orchestrator.ts +262 -542
  105. package/src/orchestrator/tx-proving-state.ts +30 -18
  106. package/src/prover-agent/memory-proving-queue.ts +12 -16
  107. package/src/prover-agent/prover-agent.ts +14 -8
  108. package/src/prover-client/factory.ts +2 -3
  109. package/src/prover-client/prover-client.ts +17 -20
  110. package/src/prover-client/server-epoch-prover.ts +44 -0
  111. package/src/proving_broker/broker_prover_facade.ts +347 -67
  112. package/src/proving_broker/config.ts +93 -0
  113. package/src/proving_broker/factory.ts +11 -10
  114. package/src/proving_broker/fixtures.ts +14 -0
  115. package/src/proving_broker/index.ts +2 -1
  116. package/src/proving_broker/proof_store/factory.ts +42 -0
  117. package/src/proving_broker/proof_store/gcs_proof_store.ts +72 -0
  118. package/src/proving_broker/proof_store/index.ts +3 -0
  119. package/src/proving_broker/{proof_store.ts → proof_store/inline_proof_store.ts} +1 -44
  120. package/src/proving_broker/proof_store/proof_store.ts +54 -0
  121. package/src/proving_broker/proving_agent.ts +11 -5
  122. package/src/proving_broker/proving_broker.ts +122 -73
  123. package/src/proving_broker/proving_broker_database/memory.ts +24 -4
  124. package/src/proving_broker/proving_broker_database/persisted.ts +142 -20
  125. package/src/proving_broker/proving_broker_database.ts +8 -3
  126. package/src/proving_broker/proving_job_controller.ts +5 -5
  127. package/src/proving_broker/rpc.ts +2 -3
  128. package/src/test/mock_prover.ts +12 -18
  129. package/dest/proving_broker/proof_store.d.ts.map +0 -1
  130. package/dest/proving_broker/proof_store.js +0 -37
@@ -9,12 +9,17 @@ 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
- import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
16
+ import {
17
+ type TelemetryClient,
18
+ type Traceable,
19
+ type Tracer,
20
+ getTelemetryClient,
21
+ trackSpan,
22
+ } from '@aztec/telemetry-client';
18
23
 
19
24
  import assert from 'assert';
20
25
 
@@ -45,7 +50,6 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
45
50
  private queues: ProvingQueues = {
46
51
  [ProvingRequestType.PUBLIC_VM]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
47
52
  [ProvingRequestType.TUBE_PROOF]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
48
- [ProvingRequestType.PRIVATE_KERNEL_EMPTY]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
49
53
 
50
54
  [ProvingRequestType.PRIVATE_BASE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
51
55
  [ProvingRequestType.PUBLIC_BASE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
@@ -54,6 +58,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
54
58
 
55
59
  [ProvingRequestType.BLOCK_MERGE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
56
60
  [ProvingRequestType.BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
61
+ [ProvingRequestType.SINGLE_TX_BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
57
62
  [ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
58
63
 
59
64
  [ProvingRequestType.BASE_PARITY]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
@@ -89,31 +94,33 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
89
94
  private instrumentation: ProvingBrokerInstrumentation;
90
95
  public readonly tracer: Tracer;
91
96
 
92
- private maxParallelCleanUps: number;
97
+ private completedJobNotifications: ProvingJobId[] = [];
93
98
 
94
99
  /**
95
100
  * The broker keeps track of the highest epoch its seen.
96
101
  * This information is used for garbage collection: once it reaches the next epoch, it can start pruning the database of old state.
97
- * This clean up pass is only done against _settled_ jobs. This pass will not cancel jobs that are in-progress or in-queue.
98
- * It is a client responsibility to cancel jobs if they are no longer necessary.
102
+ * It is important that this value is initialised to zero. This ensures that we don't delete any old jobs until the current
103
+ * process instance receives a job request informing it of the actual current highest epoch
99
104
  * Example:
100
- * proving epoch 11 - the broker will wipe all setlled jobs for epochs 9 and lower
101
- * finished proving epoch 11 and got first job for epoch 12 -> the broker will wipe all setlled jobs for epochs 10 and lower
102
- * reorged back to end of epoch 10 -> epoch 11 is skipped and epoch 12 starts -> the broker will wipe all setlled jobs for epochs 10 and lower
105
+ * proving epoch 11 - the broker will wipe all jobs for epochs 9 and lower
106
+ * finished proving epoch 11 and got first job for epoch 12 -> the broker will wipe all settled jobs for epochs 10 and lower
107
+ * 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
108
  */
104
109
  private epochHeight = 0;
105
110
  private maxEpochsToKeepResultsFor = 1;
106
111
 
112
+ private requestQueue: SerialQueue = new SerialQueue();
113
+ private started = false;
114
+
107
115
  public constructor(
108
116
  private database: ProvingBrokerDatabase,
109
- client: TelemetryClient,
110
117
  {
111
118
  jobTimeoutMs = 30_000,
112
119
  timeoutIntervalMs = 10_000,
113
120
  maxRetries = 3,
114
121
  maxEpochsToKeepResultsFor = 1,
115
- maxParallelCleanUps = 20,
116
122
  }: ProofRequestBrokerConfig = {},
123
+ client: TelemetryClient = getTelemetryClient(),
117
124
  private logger = createLogger('prover-client:proving-broker'),
118
125
  ) {
119
126
  this.tracer = client.getTracer('ProvingBroker');
@@ -122,7 +129,6 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
122
129
  this.jobTimeoutMs = jobTimeoutMs;
123
130
  this.maxRetries = maxRetries;
124
131
  this.maxEpochsToKeepResultsFor = maxEpochsToKeepResultsFor;
125
- this.maxParallelCleanUps = maxParallelCleanUps;
126
132
  }
127
133
 
128
134
  private measureQueueDepth: MonitorCallback = (type: ProvingRequestType) => {
@@ -142,6 +148,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
142
148
  };
143
149
 
144
150
  public start(): Promise<void> {
151
+ if (this.started) {
152
+ this.logger.info('Proving Broker already started');
153
+ return Promise.resolve();
154
+ }
155
+ this.logger.info('Proving Broker started');
145
156
  for (const [item, result] of this.database.allProvingJobs()) {
146
157
  this.logger.info(`Restoring proving job id=${item.id} settled=${!!result}`, {
147
158
  provingJobId: item.id,
@@ -161,24 +172,71 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
161
172
 
162
173
  this.cleanupPromise.start();
163
174
 
175
+ this.requestQueue.start();
176
+
164
177
  this.instrumentation.monitorQueueDepth(this.measureQueueDepth);
165
178
  this.instrumentation.monitorActiveJobs(this.countActiveJobs);
166
179
 
180
+ this.started = true;
181
+
167
182
  return Promise.resolve();
168
183
  }
169
184
 
170
185
  public async stop(): Promise<void> {
186
+ if (!this.started) {
187
+ this.logger.warn('ProvingBroker not started');
188
+ return Promise.resolve();
189
+ }
190
+ await this.requestQueue.cancel();
171
191
  await this.cleanupPromise.stop();
172
192
  }
173
193
 
174
- public async enqueueProvingJob(job: ProvingJob): Promise<void> {
194
+ public enqueueProvingJob(job: ProvingJob): Promise<ProvingJobStatus> {
195
+ return this.requestQueue.put(() => this.#enqueueProvingJob(job));
196
+ }
197
+
198
+ public cancelProvingJob(id: ProvingJobId): Promise<void> {
199
+ return this.requestQueue.put(() => this.#cancelProvingJob(id));
200
+ }
201
+
202
+ public getProvingJobStatus(id: ProvingJobId): Promise<ProvingJobStatus> {
203
+ return this.requestQueue.put(() => this.#getProvingJobStatus(id));
204
+ }
205
+
206
+ public getCompletedJobs(ids: ProvingJobId[]): Promise<ProvingJobId[]> {
207
+ return this.requestQueue.put(() => this.#getCompletedJobs(ids));
208
+ }
209
+
210
+ public getProvingJob(filter?: ProvingJobFilter): Promise<{ job: ProvingJob; time: number } | undefined> {
211
+ return this.requestQueue.put(() => this.#getProvingJob(filter));
212
+ }
213
+
214
+ public reportProvingJobSuccess(id: ProvingJobId, value: ProofUri): Promise<void> {
215
+ return this.requestQueue.put(() => this.#reportProvingJobSuccess(id, value));
216
+ }
217
+
218
+ public reportProvingJobError(id: ProvingJobId, err: string, retry = false): Promise<void> {
219
+ return this.requestQueue.put(() => this.#reportProvingJobError(id, err, retry));
220
+ }
221
+
222
+ public reportProvingJobProgress(
223
+ id: ProvingJobId,
224
+ startedAt: number,
225
+ filter?: ProvingJobFilter,
226
+ ): Promise<{ job: ProvingJob; time: number } | undefined> {
227
+ return this.requestQueue.put(() => this.#reportProvingJobProgress(id, startedAt, filter));
228
+ }
229
+
230
+ async #enqueueProvingJob(job: ProvingJob): Promise<ProvingJobStatus> {
231
+ // We return the job status at the start of this call
232
+ const jobStatus = await this.#getProvingJobStatus(job.id);
175
233
  if (this.jobsCache.has(job.id)) {
176
234
  const existing = this.jobsCache.get(job.id);
177
235
  assert.deepStrictEqual(job, existing, 'Duplicate proving job ID');
178
236
  this.logger.debug(`Duplicate proving job id=${job.id} epochNumber=${job.epochNumber}. Ignoring`, {
179
237
  provingJobId: job.id,
180
238
  });
181
- return;
239
+ return jobStatus;
182
240
  }
183
241
 
184
242
  if (this.isJobStale(job)) {
@@ -199,18 +257,10 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
199
257
  this.jobsCache.delete(job.id);
200
258
  throw err;
201
259
  }
260
+ return jobStatus;
202
261
  }
203
262
 
204
- public waitForJobToSettle(id: ProvingJobId): Promise<ProvingJobSettledResult> {
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> {
263
+ async #cancelProvingJob(id: ProvingJobId): Promise<void> {
214
264
  if (!this.jobsCache.has(id)) {
215
265
  this.logger.warn(`Can't cancel a job that doesn't exist id=${id}`, { provingJobId: id });
216
266
  return;
@@ -219,31 +269,21 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
219
269
  // notify listeners of the cancellation
220
270
  if (!this.resultsCache.has(id)) {
221
271
  this.logger.info(`Cancelling job id=${id}`, { provingJobId: id });
222
- await this.reportProvingJobError(id, 'Aborted', false);
272
+ await this.#reportProvingJobError(id, 'Aborted', false);
223
273
  }
224
274
  }
225
275
 
226
- private async cleanUpProvingJobState(id: ProvingJobId): Promise<void> {
227
- if (!this.jobsCache.has(id)) {
228
- this.logger.warn(`Can't clean up a job that doesn't exist id=${id}`, { provingJobId: id });
229
- return;
230
- }
231
-
232
- if (!this.resultsCache.has(id)) {
233
- this.logger.warn(`Can't cleanup busy proving job: id=${id}`, { provingJobId: id });
234
- return;
276
+ private cleanUpProvingJobState(ids: ProvingJobId[]) {
277
+ for (const id of ids) {
278
+ this.jobsCache.delete(id);
279
+ this.promises.delete(id);
280
+ this.resultsCache.delete(id);
281
+ this.inProgress.delete(id);
282
+ this.retries.delete(id);
235
283
  }
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
284
  }
245
285
 
246
- public getProvingJobStatus(id: ProvingJobId): Promise<ProvingJobStatus> {
286
+ #getProvingJobStatus(id: ProvingJobId): Promise<ProvingJobStatus> {
247
287
  const result = this.resultsCache.get(id);
248
288
  if (result) {
249
289
  return Promise.resolve(result);
@@ -252,7 +292,6 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
252
292
  const item = this.jobsCache.get(id);
253
293
 
254
294
  if (!item) {
255
- this.logger.warn(`Proving job id=${id} not found`, { provingJobId: id });
256
295
  return Promise.resolve({ status: 'not-found' });
257
296
  }
258
297
 
@@ -260,8 +299,15 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
260
299
  }
261
300
  }
262
301
 
302
+ #getCompletedJobs(ids: ProvingJobId[]): Promise<ProvingJobId[]> {
303
+ const completedJobs = ids.filter(id => this.resultsCache.has(id));
304
+ const notifications = this.completedJobNotifications;
305
+ this.completedJobNotifications = [];
306
+ return Promise.resolve(notifications.concat(completedJobs));
307
+ }
308
+
263
309
  // eslint-disable-next-line require-await
264
- async getProvingJob(
310
+ async #getProvingJob(
265
311
  filter: ProvingJobFilter = { allowList: [] },
266
312
  ): Promise<{ job: ProvingJob; time: number } | undefined> {
267
313
  const allowedProofs: ProvingRequestType[] =
@@ -299,7 +345,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
299
345
  return undefined;
300
346
  }
301
347
 
302
- async reportProvingJobError(id: ProvingJobId, err: string, retry = false): Promise<void> {
348
+ async #reportProvingJobError(id: ProvingJobId, err: string, retry = false): Promise<void> {
303
349
  const info = this.inProgress.get(id);
304
350
  const item = this.jobsCache.get(id);
305
351
  const retries = this.retries.get(id) ?? 0;
@@ -351,6 +397,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
351
397
  const result: ProvingJobSettledResult = { status: 'rejected', reason: String(err) };
352
398
  this.resultsCache.set(id, result);
353
399
  this.promises.get(id)!.resolve(result);
400
+ this.completedJobNotifications.push(id);
354
401
 
355
402
  this.instrumentation.incRejectedJobs(item.type);
356
403
  if (info) {
@@ -369,7 +416,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
369
416
  }
370
417
  }
371
418
 
372
- reportProvingJobProgress(
419
+ #reportProvingJobProgress(
373
420
  id: ProvingJobId,
374
421
  startedAt: number,
375
422
  filter?: ProvingJobFilter,
@@ -377,12 +424,12 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
377
424
  const job = this.jobsCache.get(id);
378
425
  if (!job) {
379
426
  this.logger.warn(`Proving job id=${id} does not exist`, { provingJobId: id });
380
- return filter ? this.getProvingJob(filter) : Promise.resolve(undefined);
427
+ return filter ? this.#getProvingJob(filter) : Promise.resolve(undefined);
381
428
  }
382
429
 
383
430
  if (this.resultsCache.has(id)) {
384
431
  this.logger.warn(`Proving job id=${id} has already been completed`, { provingJobId: id });
385
- return filter ? this.getProvingJob(filter) : Promise.resolve(undefined);
432
+ return filter ? this.#getProvingJob(filter) : Promise.resolve(undefined);
386
433
  }
387
434
 
388
435
  const metadata = this.inProgress.get(id);
@@ -420,13 +467,13 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
420
467
  } already being worked on by another agent. Sending new one`,
421
468
  { provingJobId: id },
422
469
  );
423
- return this.getProvingJob(filter);
470
+ return this.#getProvingJob(filter);
424
471
  } else {
425
472
  return Promise.resolve(undefined);
426
473
  }
427
474
  }
428
475
 
429
- async reportProvingJobSuccess(id: ProvingJobId, value: ProofUri): Promise<void> {
476
+ async #reportProvingJobSuccess(id: ProvingJobId, value: ProofUri): Promise<void> {
430
477
  const info = this.inProgress.get(id);
431
478
  const item = this.jobsCache.get(id);
432
479
  const retries = this.retries.get(id) ?? 0;
@@ -459,6 +506,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
459
506
  const result: ProvingJobSettledResult = { status: 'fulfilled', value };
460
507
  this.resultsCache.set(id, result);
461
508
  this.promises.get(id)!.resolve(result);
509
+ this.completedJobNotifications.push(id);
462
510
 
463
511
  this.instrumentation.incResolvedJobs(item.type);
464
512
  if (info) {
@@ -479,30 +527,32 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
479
527
 
480
528
  @trackSpan('ProvingBroker.cleanupPass')
481
529
  private async cleanupPass() {
482
- await this.cleanupStaleJobs();
483
- await this.reEnqueueExpiredJobs();
530
+ this.cleanupStaleJobs();
531
+ this.reEnqueueExpiredJobs();
532
+ const oldestEpochToKeep = this.oldestEpochToKeep();
533
+ if (oldestEpochToKeep > 0) {
534
+ await this.requestQueue.put(() => this.database.deleteAllProvingJobsOlderThanEpoch(oldestEpochToKeep));
535
+ this.logger.trace(`Deleted all epochs older than ${oldestEpochToKeep}`);
536
+ }
484
537
  }
485
538
 
486
- private async cleanupStaleJobs() {
539
+ private cleanupStaleJobs() {
487
540
  const jobIds = Array.from(this.jobsCache.keys());
488
541
  const jobsToClean: ProvingJobId[] = [];
489
542
  for (const id of jobIds) {
490
543
  const job = this.jobsCache.get(id)!;
491
- const isComplete = this.resultsCache.has(id);
492
- if (isComplete && this.isJobStale(job)) {
544
+ if (this.isJobStale(job)) {
493
545
  jobsToClean.push(id);
494
546
  }
495
547
  }
496
548
 
497
549
  if (jobsToClean.length > 0) {
498
- this.logger.info(`Cleaning up jobs=${jobsToClean.length}`);
499
- await asyncPool(this.maxParallelCleanUps, jobsToClean, async jobId => {
500
- await this.cleanUpProvingJobState(jobId);
501
- });
550
+ this.cleanUpProvingJobState(jobsToClean);
551
+ this.logger.info(`Cleaned up jobs=${jobsToClean.length}`);
502
552
  }
503
553
  }
504
554
 
505
- private async reEnqueueExpiredJobs() {
555
+ private reEnqueueExpiredJobs() {
506
556
  const inProgressEntries = Array.from(this.inProgress.entries());
507
557
  for (const [id, metadata] of inProgressEntries) {
508
558
  const item = this.jobsCache.get(id);
@@ -515,15 +565,10 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
515
565
  const now = this.msTimeSource();
516
566
  const msSinceLastUpdate = now - metadata.lastUpdatedAt;
517
567
  if (msSinceLastUpdate >= this.jobTimeoutMs) {
518
- if (this.isJobStale(item)) {
519
- // the job has timed out and it's also old, just cancel and move on
520
- await this.cancelProvingJob(item.id);
521
- } else {
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
- }
568
+ this.logger.warn(`Proving job id=${id} timed out. Adding it back to the queue.`, { provingJobId: id });
569
+ this.inProgress.delete(id);
570
+ this.enqueueJobInternal(item);
571
+ this.instrumentation.incTimedOutJobs(item.type);
527
572
  }
528
573
  }
529
574
  }
@@ -541,7 +586,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
541
586
  }
542
587
 
543
588
  private isJobStale(job: ProvingJob) {
544
- return job.epochNumber < this.epochHeight - this.maxEpochsToKeepResultsFor;
589
+ return job.epochNumber < this.oldestEpochToKeep();
590
+ }
591
+
592
+ private oldestEpochToKeep() {
593
+ return this.epochHeight - this.maxEpochsToKeepResultsFor;
545
594
  }
546
595
  }
547
596
 
@@ -601,6 +650,7 @@ function proofTypeComparator(a: ProvingRequestType, b: ProvingRequestType): -1 |
601
650
  */
602
651
  const PROOF_TYPES_IN_PRIORITY_ORDER: ProvingRequestType[] = [
603
652
  ProvingRequestType.BLOCK_ROOT_ROLLUP,
653
+ ProvingRequestType.SINGLE_TX_BLOCK_ROOT_ROLLUP,
604
654
  ProvingRequestType.BLOCK_MERGE_ROLLUP,
605
655
  ProvingRequestType.ROOT_ROLLUP,
606
656
  ProvingRequestType.MERGE_ROLLUP,
@@ -611,5 +661,4 @@ const PROOF_TYPES_IN_PRIORITY_ORDER: ProvingRequestType[] = [
611
661
  ProvingRequestType.ROOT_PARITY,
612
662
  ProvingRequestType.BASE_PARITY,
613
663
  ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP,
614
- ProvingRequestType.PRIVATE_KERNEL_EMPTY,
615
664
  ];
@@ -1,4 +1,10 @@
1
- import type { ProofUri, ProvingJob, ProvingJobId, ProvingJobSettledResult } from '@aztec/circuit-types';
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
- deleteProvingJobAndResult(id: ProvingJobId): Promise<void> {
33
- this.jobs.delete(id);
34
- this.results.delete(id);
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 { type ProofUri, ProvingJob, type ProvingJobId, ProvingJobSettledResult } from '@aztec/circuit-types';
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 AztecKVStore, type AztecMap } from '@aztec/kv-store';
4
- import { Attributes, LmdbMetrics, type TelemetryClient } from '@aztec/telemetry-client';
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';
12
+ import { Attributes, LmdbMetrics, type TelemetryClient, getTelemetryClient } 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
- export class KVBrokerDatabase implements ProvingBrokerDatabase {
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(private store: AztecKVStore, client: TelemetryClient) {
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 = getTelemetryClient(),
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 = getTelemetryClient(),
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
- * Removes a proof request from the backend
15
- * @param id - The ID of the proof request to remove
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
- deleteProvingJobAndResult(id: ProvingJobId): Promise<void>;
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
  }