@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.
Files changed (144) hide show
  1. package/dest/block_builder/index.d.ts +6 -0
  2. package/dest/block_builder/index.d.ts.map +1 -0
  3. package/dest/block_builder/index.js +2 -0
  4. package/dest/block_builder/light.d.ts +32 -0
  5. package/dest/block_builder/light.d.ts.map +1 -0
  6. package/dest/block_builder/light.js +71 -0
  7. package/dest/config.d.ts +4 -10
  8. package/dest/config.d.ts.map +1 -1
  9. package/dest/config.js +8 -7
  10. package/dest/index.d.ts +2 -2
  11. package/dest/index.d.ts.map +1 -1
  12. package/dest/index.js +3 -3
  13. package/dest/mocks/fixtures.d.ts +1 -2
  14. package/dest/mocks/fixtures.d.ts.map +1 -1
  15. package/dest/mocks/fixtures.js +3 -7
  16. package/dest/mocks/test_context.d.ts +28 -10
  17. package/dest/mocks/test_context.d.ts.map +1 -1
  18. package/dest/mocks/test_context.js +59 -21
  19. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  20. package/dest/orchestrator/block-building-helpers.js +10 -18
  21. package/dest/orchestrator/block-proving-state.js +2 -2
  22. package/dest/orchestrator/epoch-proving-state.d.ts +5 -6
  23. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  24. package/dest/orchestrator/epoch-proving-state.js +10 -12
  25. package/dest/orchestrator/orchestrator.d.ts +8 -6
  26. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  27. package/dest/orchestrator/orchestrator.js +83 -72
  28. package/dest/orchestrator/tx-proving-state.d.ts +0 -1
  29. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  30. package/dest/orchestrator/tx-proving-state.js +2 -34
  31. package/dest/prover-agent/memory-proving-queue.d.ts +10 -8
  32. package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
  33. package/dest/prover-agent/memory-proving-queue.js +35 -35
  34. package/dest/prover-agent/prover-agent.d.ts +1 -0
  35. package/dest/prover-agent/prover-agent.d.ts.map +1 -1
  36. package/dest/prover-agent/prover-agent.js +12 -9
  37. package/dest/prover-client/factory.d.ts +6 -0
  38. package/dest/prover-client/factory.d.ts.map +1 -0
  39. package/dest/prover-client/factory.js +6 -0
  40. package/dest/prover-client/index.d.ts +3 -0
  41. package/dest/prover-client/index.d.ts.map +1 -0
  42. package/dest/prover-client/index.js +3 -0
  43. package/dest/prover-client/prover-client.d.ts +41 -0
  44. package/dest/prover-client/prover-client.d.ts.map +1 -0
  45. package/dest/prover-client/prover-client.js +107 -0
  46. package/dest/proving_broker/caching_broker_facade.d.ts +30 -0
  47. package/dest/proving_broker/caching_broker_facade.d.ts.map +1 -0
  48. package/dest/proving_broker/caching_broker_facade.js +150 -0
  49. package/dest/proving_broker/factory.d.ts +5 -0
  50. package/dest/proving_broker/factory.d.ts.map +1 -0
  51. package/dest/proving_broker/factory.js +17 -0
  52. package/dest/proving_broker/index.d.ts +9 -0
  53. package/dest/proving_broker/index.d.ts.map +1 -0
  54. package/dest/proving_broker/index.js +9 -0
  55. package/dest/proving_broker/proof_store.d.ts +46 -0
  56. package/dest/proving_broker/proof_store.d.ts.map +1 -0
  57. package/dest/proving_broker/proof_store.js +37 -0
  58. package/dest/proving_broker/prover_cache/memory.d.ts +9 -0
  59. package/dest/proving_broker/prover_cache/memory.d.ts.map +1 -0
  60. package/dest/proving_broker/prover_cache/memory.js +16 -0
  61. package/dest/proving_broker/proving_agent.d.ts +16 -6
  62. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  63. package/dest/proving_broker/proving_agent.js +59 -20
  64. package/dest/proving_broker/proving_agent_instrumentation.d.ts +8 -0
  65. package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +1 -0
  66. package/dest/proving_broker/proving_agent_instrumentation.js +16 -0
  67. package/dest/proving_broker/proving_broker.d.ts +22 -16
  68. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  69. package/dest/proving_broker/proving_broker.js +79 -25
  70. package/dest/proving_broker/proving_broker_database/memory.d.ts +14 -0
  71. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -0
  72. package/dest/proving_broker/proving_broker_database/memory.js +35 -0
  73. package/dest/proving_broker/proving_broker_database/persisted.d.ts +17 -0
  74. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -0
  75. package/dest/proving_broker/proving_broker_database/persisted.js +43 -0
  76. package/dest/proving_broker/{proving_job_database.d.ts → proving_broker_database.d.ts} +8 -8
  77. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -0
  78. package/dest/proving_broker/proving_broker_database.js +2 -0
  79. package/dest/proving_broker/proving_broker_instrumentation.d.ts +25 -0
  80. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -0
  81. package/dest/proving_broker/proving_broker_instrumentation.js +91 -0
  82. package/dest/proving_broker/proving_job_controller.d.ts +13 -8
  83. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  84. package/dest/proving_broker/proving_job_controller.js +43 -43
  85. package/dest/proving_broker/rpc.d.ts +11 -0
  86. package/dest/proving_broker/rpc.d.ts.map +1 -0
  87. package/dest/proving_broker/rpc.js +44 -0
  88. package/dest/test/mock_prover.d.ts +16 -2
  89. package/dest/test/mock_prover.d.ts.map +1 -1
  90. package/dest/test/mock_prover.js +37 -1
  91. package/package.json +17 -14
  92. package/src/block_builder/index.ts +6 -0
  93. package/src/block_builder/light.ts +117 -0
  94. package/src/config.ts +17 -16
  95. package/src/index.ts +2 -2
  96. package/src/mocks/fixtures.ts +2 -14
  97. package/src/mocks/test_context.ts +81 -25
  98. package/src/orchestrator/block-building-helpers.ts +22 -33
  99. package/src/orchestrator/block-proving-state.ts +1 -1
  100. package/src/orchestrator/epoch-proving-state.ts +10 -13
  101. package/src/orchestrator/orchestrator.ts +97 -77
  102. package/src/orchestrator/tx-proving-state.ts +1 -56
  103. package/src/prover-agent/memory-proving-queue.ts +43 -44
  104. package/src/prover-agent/prover-agent.ts +16 -20
  105. package/src/prover-client/factory.ts +15 -0
  106. package/src/prover-client/index.ts +2 -0
  107. package/src/prover-client/prover-client.ts +172 -0
  108. package/src/proving_broker/caching_broker_facade.ts +312 -0
  109. package/src/proving_broker/factory.ts +25 -0
  110. package/src/proving_broker/index.ts +8 -0
  111. package/src/proving_broker/proof_store.ts +106 -0
  112. package/src/proving_broker/prover_cache/memory.ts +20 -0
  113. package/src/proving_broker/proving_agent.ts +90 -20
  114. package/src/proving_broker/proving_agent_instrumentation.ts +21 -0
  115. package/src/proving_broker/proving_broker.ts +143 -67
  116. package/src/proving_broker/proving_broker_database/memory.ts +43 -0
  117. package/src/proving_broker/proving_broker_database/persisted.ts +60 -0
  118. package/src/proving_broker/{proving_job_database.ts → proving_broker_database.ts} +7 -12
  119. package/src/proving_broker/proving_broker_instrumentation.ts +130 -0
  120. package/src/proving_broker/proving_job_controller.ts +54 -46
  121. package/src/proving_broker/rpc.ts +64 -0
  122. package/src/test/mock_prover.ts +52 -0
  123. package/dest/proving_broker/proving_broker_interface.d.ts +0 -61
  124. package/dest/proving_broker/proving_broker_interface.d.ts.map +0 -1
  125. package/dest/proving_broker/proving_broker_interface.js +0 -2
  126. package/dest/proving_broker/proving_job_database/memory.d.ts +0 -14
  127. package/dest/proving_broker/proving_job_database/memory.d.ts.map +0 -1
  128. package/dest/proving_broker/proving_job_database/memory.js +0 -35
  129. package/dest/proving_broker/proving_job_database/persisted.d.ts +0 -15
  130. package/dest/proving_broker/proving_job_database/persisted.d.ts.map +0 -1
  131. package/dest/proving_broker/proving_job_database/persisted.js +0 -35
  132. package/dest/proving_broker/proving_job_database.d.ts.map +0 -1
  133. package/dest/proving_broker/proving_job_database.js +0 -2
  134. package/dest/tx-prover/factory.d.ts +0 -5
  135. package/dest/tx-prover/factory.d.ts.map +0 -1
  136. package/dest/tx-prover/factory.js +0 -6
  137. package/dest/tx-prover/tx-prover.d.ts +0 -38
  138. package/dest/tx-prover/tx-prover.d.ts.map +0 -1
  139. package/dest/tx-prover/tx-prover.js +0 -93
  140. package/src/proving_broker/proving_broker_interface.ts +0 -74
  141. package/src/proving_broker/proving_job_database/memory.ts +0 -43
  142. package/src/proving_broker/proving_job_database/persisted.ts +0 -45
  143. package/src/tx-prover/factory.ts +0 -9
  144. package/src/tx-prover/tx-prover.ts +0 -130
@@ -1,29 +1,34 @@
1
1
  import {
2
+ type ProofUri,
3
+ type ProvingJob,
4
+ type ProvingJobConsumer,
5
+ type ProvingJobFilter,
6
+ type ProvingJobId,
7
+ type ProvingJobProducer,
8
+ type ProvingJobSettledResult,
9
+ type ProvingJobStatus,
2
10
  ProvingRequestType,
3
- type V2ProofOutput,
4
- type V2ProvingJob,
5
- type V2ProvingJobId,
6
- type V2ProvingJobResult,
7
- type V2ProvingJobStatus,
8
11
  } from '@aztec/circuit-types';
9
12
  import { createDebugLogger } from '@aztec/foundation/log';
10
- import { RunningPromise } from '@aztec/foundation/promise';
13
+ import { type PromiseWithResolvers, RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
11
14
  import { PriorityMemoryQueue } from '@aztec/foundation/queue';
15
+ import { Timer } from '@aztec/foundation/timer';
16
+ import { type TelemetryClient } from '@aztec/telemetry-client';
12
17
 
13
18
  import assert from 'assert';
14
19
 
15
- import type { ProvingJobConsumer, ProvingJobFilter, ProvingJobProducer } from './proving_broker_interface.js';
16
- import { type ProvingJobDatabase } from './proving_job_database.js';
20
+ import { type ProvingBrokerDatabase } from './proving_broker_database.js';
21
+ import { type MonitorCallback, ProvingBrokerInstrumentation } from './proving_broker_instrumentation.js';
17
22
 
18
23
  type InProgressMetadata = {
19
- id: V2ProvingJobId;
24
+ id: ProvingJobId;
20
25
  startedAt: number;
21
26
  lastUpdatedAt: number;
22
27
  };
23
28
 
24
29
  type ProofRequestBrokerConfig = {
25
- timeoutIntervalSec?: number;
26
- jobTimeoutSec?: number;
30
+ timeoutIntervalMs?: number;
31
+ jobTimeoutMs?: number;
27
32
  maxRetries?: number;
28
33
  };
29
34
 
@@ -33,60 +38,88 @@ type ProofRequestBrokerConfig = {
33
38
  */
34
39
  export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
35
40
  private queues: ProvingQueues = {
36
- [ProvingRequestType.PUBLIC_VM]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
37
- [ProvingRequestType.TUBE_PROOF]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
38
- [ProvingRequestType.PRIVATE_KERNEL_EMPTY]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
41
+ [ProvingRequestType.PUBLIC_VM]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
42
+ [ProvingRequestType.TUBE_PROOF]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
43
+ [ProvingRequestType.PRIVATE_KERNEL_EMPTY]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
39
44
 
40
- [ProvingRequestType.PRIVATE_BASE_ROLLUP]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
41
- [ProvingRequestType.PUBLIC_BASE_ROLLUP]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
42
- [ProvingRequestType.MERGE_ROLLUP]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
43
- [ProvingRequestType.ROOT_ROLLUP]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
45
+ [ProvingRequestType.PRIVATE_BASE_ROLLUP]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
46
+ [ProvingRequestType.PUBLIC_BASE_ROLLUP]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
47
+ [ProvingRequestType.MERGE_ROLLUP]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
48
+ [ProvingRequestType.ROOT_ROLLUP]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
44
49
 
45
- [ProvingRequestType.BLOCK_MERGE_ROLLUP]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
46
- [ProvingRequestType.BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
47
- [ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
50
+ [ProvingRequestType.BLOCK_MERGE_ROLLUP]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
51
+ [ProvingRequestType.BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
52
+ [ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
48
53
 
49
- [ProvingRequestType.BASE_PARITY]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
50
- [ProvingRequestType.ROOT_PARITY]: new PriorityMemoryQueue<V2ProvingJob>(provingJobComparator),
54
+ [ProvingRequestType.BASE_PARITY]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
55
+ [ProvingRequestType.ROOT_PARITY]: new PriorityMemoryQueue<ProvingJob>(provingJobComparator),
51
56
  };
52
57
 
53
58
  // holds a copy of the database in memory in order to quickly fulfill requests
54
59
  // this is fine because this broker is the only one that can modify the database
55
- private jobsCache = new Map<V2ProvingJobId, V2ProvingJob>();
60
+ private jobsCache = new Map<ProvingJobId, ProvingJob>();
56
61
  // as above, but for results
57
- private resultsCache = new Map<V2ProvingJobId, V2ProvingJobResult>();
62
+ private resultsCache = new Map<ProvingJobId, ProvingJobSettledResult>();
63
+
64
+ // tracks when each job was enqueued
65
+ private enqueuedAt = new Map<ProvingJobId, Timer>();
58
66
 
59
67
  // keeps track of which jobs are currently being processed
60
68
  // in the event of a crash this information is lost, but that's ok
61
69
  // the next time the broker starts it will recreate jobsCache and still
62
70
  // accept results from the workers
63
- private inProgress = new Map<V2ProvingJobId, InProgressMetadata>();
71
+ private inProgress = new Map<ProvingJobId, InProgressMetadata>();
64
72
 
65
73
  // keep track of which proving job has been retried
66
- private retries = new Map<V2ProvingJobId, number>();
74
+ private retries = new Map<ProvingJobId, number>();
75
+
76
+ // a map of promises that will be resolved when a job is settled
77
+ private promises = new Map<ProvingJobId, PromiseWithResolvers<ProvingJobSettledResult>>();
67
78
 
68
79
  private timeoutPromise: RunningPromise;
69
80
  private timeSource = () => Math.floor(Date.now() / 1000);
70
- private jobTimeoutSec: number;
81
+ private jobTimeoutMs: number;
71
82
  private maxRetries: number;
72
83
 
84
+ private instrumentation: ProvingBrokerInstrumentation;
85
+
73
86
  public constructor(
74
- private database: ProvingJobDatabase,
75
- { jobTimeoutSec = 30, timeoutIntervalSec = 10, maxRetries = 3 }: ProofRequestBrokerConfig = {},
76
- private logger = createDebugLogger('aztec:prover-client:proof-request-broker'),
87
+ private database: ProvingBrokerDatabase,
88
+ client: TelemetryClient,
89
+ { jobTimeoutMs = 30_000, timeoutIntervalMs = 10_000, maxRetries = 3 }: ProofRequestBrokerConfig = {},
90
+ private logger = createDebugLogger('aztec:prover-client:proving-broker'),
77
91
  ) {
78
- this.timeoutPromise = new RunningPromise(this.timeoutCheck, timeoutIntervalSec * 1000);
79
- this.jobTimeoutSec = jobTimeoutSec;
92
+ this.instrumentation = new ProvingBrokerInstrumentation(client);
93
+ this.timeoutPromise = new RunningPromise(this.timeoutCheck, timeoutIntervalMs);
94
+ this.jobTimeoutMs = jobTimeoutMs;
80
95
  this.maxRetries = maxRetries;
81
96
  }
82
97
 
83
- // eslint-disable-next-line require-await
84
- public async start(): Promise<void> {
98
+ private measureQueueDepth: MonitorCallback = (type: ProvingRequestType) => {
99
+ return this.queues[type].length();
100
+ };
101
+
102
+ private countActiveJobs: MonitorCallback = (type: ProvingRequestType) => {
103
+ let count = 0;
104
+ for (const { id } of this.inProgress.values()) {
105
+ const job = this.jobsCache.get(id);
106
+ if (job?.type === type) {
107
+ count++;
108
+ }
109
+ }
110
+
111
+ return count;
112
+ };
113
+
114
+ public start(): Promise<void> {
85
115
  for (const [item, result] of this.database.allProvingJobs()) {
86
116
  this.logger.info(`Restoring proving job id=${item.id} settled=${!!result}`);
87
117
 
88
118
  this.jobsCache.set(item.id, item);
119
+ this.promises.set(item.id, promiseWithResolvers());
120
+
89
121
  if (result) {
122
+ this.promises.get(item.id)!.resolve(result);
90
123
  this.resultsCache.set(item.id, result);
91
124
  } else {
92
125
  this.logger.debug(`Re-enqueuing proving job id=${item.id}`);
@@ -95,13 +128,18 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
95
128
  }
96
129
 
97
130
  this.timeoutPromise.start();
131
+
132
+ this.instrumentation.monitorQueueDepth(this.measureQueueDepth);
133
+ this.instrumentation.monitorActiveJobs(this.countActiveJobs);
134
+
135
+ return Promise.resolve();
98
136
  }
99
137
 
100
138
  public stop(): Promise<void> {
101
139
  return this.timeoutPromise.stop();
102
140
  }
103
141
 
104
- public async enqueueProvingJob(job: V2ProvingJob): Promise<void> {
142
+ public async enqueueProvingJob(job: ProvingJob): Promise<void> {
105
143
  if (this.jobsCache.has(job.id)) {
106
144
  const existing = this.jobsCache.get(job.id);
107
145
  assert.deepStrictEqual(job, existing, 'Duplicate proving job ID');
@@ -113,20 +151,35 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
113
151
  this.enqueueJobInternal(job);
114
152
  }
115
153
 
116
- public async removeAndCancelProvingJob(id: V2ProvingJobId): Promise<void> {
154
+ public waitForJobToSettle(id: ProvingJobId): Promise<ProvingJobSettledResult> {
155
+ const promiseWithResolvers = this.promises.get(id);
156
+ if (!promiseWithResolvers) {
157
+ return Promise.resolve({ status: 'rejected', reason: `Job ${id} not found` });
158
+ }
159
+ return promiseWithResolvers.promise;
160
+ }
161
+
162
+ public async removeAndCancelProvingJob(id: ProvingJobId): Promise<void> {
117
163
  this.logger.info(`Cancelling job id=${id}`);
118
164
  await this.database.deleteProvingJobAndResult(id);
119
165
 
166
+ // notify listeners of the cancellation
167
+ if (!this.resultsCache.has(id)) {
168
+ this.promises.get(id)?.resolve({ status: 'rejected', reason: 'Aborted' });
169
+ }
170
+
120
171
  this.jobsCache.delete(id);
172
+ this.promises.delete(id);
121
173
  this.resultsCache.delete(id);
122
174
  this.inProgress.delete(id);
123
175
  this.retries.delete(id);
124
176
  }
125
177
 
126
- // eslint-disable-next-line require-await
127
- public async getProvingJobStatus(id: V2ProvingJobId): Promise<V2ProvingJobStatus> {
178
+ public getProvingJobStatus(id: ProvingJobId): Promise<ProvingJobStatus> {
128
179
  const result = this.resultsCache.get(id);
129
- if (!result) {
180
+ if (result) {
181
+ return Promise.resolve(result);
182
+ } else {
130
183
  // no result yet, check if we know the item
131
184
  const item = this.jobsCache.get(id);
132
185
 
@@ -136,29 +189,26 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
136
189
  }
137
190
 
138
191
  return Promise.resolve({ status: this.inProgress.has(id) ? 'in-progress' : 'in-queue' });
139
- } else if ('value' in result) {
140
- return Promise.resolve({ status: 'resolved', value: result.value });
141
- } else {
142
- return Promise.resolve({ status: 'rejected', error: result.error });
143
192
  }
144
193
  }
145
194
 
146
195
  // eslint-disable-next-line require-await
147
- async getProvingJob<T extends ProvingRequestType[]>(
148
- filter: ProvingJobFilter<T> = {},
149
- ): Promise<{ job: V2ProvingJob; time: number } | undefined> {
150
- const allowedProofs: ProvingRequestType[] = filter.allowList
151
- ? [...filter.allowList]
152
- : Object.values(ProvingRequestType).filter((x): x is ProvingRequestType => typeof x === 'number');
196
+ async getProvingJob(
197
+ filter: ProvingJobFilter = { allowList: [] },
198
+ ): Promise<{ job: ProvingJob; time: number } | undefined> {
199
+ const allowedProofs: ProvingRequestType[] =
200
+ Array.isArray(filter.allowList) && filter.allowList.length > 0
201
+ ? [...filter.allowList]
202
+ : Object.values(ProvingRequestType).filter((x): x is ProvingRequestType => typeof x === 'number');
153
203
  allowedProofs.sort(proofTypeComparator);
154
204
 
155
205
  for (const proofType of allowedProofs) {
156
206
  const queue = this.queues[proofType];
157
- let job: V2ProvingJob | undefined;
207
+ let job: ProvingJob | undefined;
158
208
  // exhaust the queue and make sure we're not sending a job that's already in progress
159
209
  // or has already been completed
160
210
  // this can happen if the broker crashes and restarts
161
- // it's possible agents will report progress or results for jobs that are no longer in the queue
211
+ // it's possible agents will report progress or results for jobs that are in the queue (after the restart)
162
212
  while ((job = queue.getImmediate())) {
163
213
  if (!this.inProgress.has(job.id) && !this.resultsCache.has(job.id)) {
164
214
  const time = this.timeSource();
@@ -167,6 +217,10 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
167
217
  startedAt: time,
168
218
  lastUpdatedAt: time,
169
219
  });
220
+ const enqueuedAt = this.enqueuedAt.get(job.id);
221
+ if (enqueuedAt) {
222
+ this.instrumentation.recordJobWait(job.type, enqueuedAt);
223
+ }
170
224
 
171
225
  return { job, time };
172
226
  }
@@ -176,7 +230,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
176
230
  return undefined;
177
231
  }
178
232
 
179
- async reportProvingJobError(id: V2ProvingJobId, err: Error, retry = false): Promise<void> {
233
+ async reportProvingJobError(id: ProvingJobId, err: string, retry = false): Promise<void> {
180
234
  const info = this.inProgress.get(id);
181
235
  const item = this.jobsCache.get(id);
182
236
  const retries = this.retries.get(id) ?? 0;
@@ -196,21 +250,31 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
196
250
  this.logger.info(`Retrying proving job id=${id} type=${ProvingRequestType[item.type]} retry=${retries + 1}`);
197
251
  this.retries.set(id, retries + 1);
198
252
  this.enqueueJobInternal(item);
253
+ this.instrumentation.incRetriedJobs(item.type);
199
254
  return;
200
255
  }
201
256
 
202
257
  this.logger.debug(
203
258
  `Marking proving job id=${id} type=${ProvingRequestType[item.type]} totalAttempts=${retries + 1} as failed`,
204
259
  );
260
+
205
261
  await this.database.setProvingJobError(id, err);
206
- this.resultsCache.set(id, { error: String(err) });
262
+
263
+ const result: ProvingJobSettledResult = { status: 'rejected', reason: String(err) };
264
+ this.resultsCache.set(id, result);
265
+ this.promises.get(id)!.resolve(result);
266
+ this.instrumentation.incRejectedJobs(item.type);
267
+ if (info) {
268
+ const duration = this.timeSource() - info.startedAt;
269
+ this.instrumentation.recordJobDuration(item.type, duration * 1000);
270
+ }
207
271
  }
208
272
 
209
- reportProvingJobProgress<F extends ProvingRequestType[]>(
210
- id: V2ProvingJobId,
273
+ reportProvingJobProgress(
274
+ id: ProvingJobId,
211
275
  startedAt: number,
212
- filter?: ProvingJobFilter<F>,
213
- ): Promise<{ job: V2ProvingJob; time: number } | undefined> {
276
+ filter?: ProvingJobFilter,
277
+ ): Promise<{ job: ProvingJob; time: number } | undefined> {
214
278
  const job = this.jobsCache.get(id);
215
279
  if (!job) {
216
280
  this.logger.warn(`Proving job id=${id} does not exist`);
@@ -255,7 +319,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
255
319
  }
256
320
  }
257
321
 
258
- async reportProvingJobSuccess(id: V2ProvingJobId, value: V2ProofOutput): Promise<void> {
322
+ async reportProvingJobSuccess(id: ProvingJobId, value: ProofUri): Promise<void> {
259
323
  const info = this.inProgress.get(id);
260
324
  const item = this.jobsCache.get(id);
261
325
  const retries = this.retries.get(id) ?? 0;
@@ -273,8 +337,13 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
273
337
  this.logger.debug(
274
338
  `Proving job complete id=${id} type=${ProvingRequestType[item.type]} totalAttempts=${retries + 1}`,
275
339
  );
340
+
276
341
  await this.database.setProvingJobResult(id, value);
277
- this.resultsCache.set(id, { value });
342
+
343
+ const result: ProvingJobSettledResult = { status: 'fulfilled', value };
344
+ this.resultsCache.set(id, result);
345
+ this.promises.get(id)!.resolve(result);
346
+ this.instrumentation.incResolvedJobs(item.type);
278
347
  }
279
348
 
280
349
  private timeoutCheck = () => {
@@ -287,23 +356,28 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
287
356
  continue;
288
357
  }
289
358
 
290
- const secondsSinceLastUpdate = this.timeSource() - metadata.lastUpdatedAt;
291
- if (secondsSinceLastUpdate >= this.jobTimeoutSec) {
359
+ const msSinceLastUpdate = (this.timeSource() - metadata.lastUpdatedAt) * 1000;
360
+ if (msSinceLastUpdate >= this.jobTimeoutMs) {
292
361
  this.logger.warn(`Proving job id=${id} timed out. Adding it back to the queue.`);
293
362
  this.inProgress.delete(id);
294
363
  this.enqueueJobInternal(item);
364
+ this.instrumentation.incTimedOutJobs(item.type);
295
365
  }
296
366
  }
297
367
  };
298
368
 
299
- private enqueueJobInternal(job: V2ProvingJob): void {
369
+ private enqueueJobInternal(job: ProvingJob): void {
370
+ if (!this.promises.has(job.id)) {
371
+ this.promises.set(job.id, promiseWithResolvers());
372
+ }
300
373
  this.queues[job.type].put(job);
374
+ this.enqueuedAt.set(job.id, new Timer());
301
375
  this.logger.debug(`Enqueued new proving job id=${job.id}`);
302
376
  }
303
377
  }
304
378
 
305
379
  type ProvingQueues = {
306
- [K in ProvingRequestType]: PriorityMemoryQueue<V2ProvingJob>;
380
+ [K in ProvingRequestType]: PriorityMemoryQueue<ProvingJob>;
307
381
  };
308
382
 
309
383
  /**
@@ -312,10 +386,12 @@ type ProvingQueues = {
312
386
  * @param b - Another proving job
313
387
  * @returns A number indicating the relative priority of the two proving jobs
314
388
  */
315
- function provingJobComparator(a: V2ProvingJob, b: V2ProvingJob): -1 | 0 | 1 {
316
- if (a.blockNumber < b.blockNumber) {
389
+ function provingJobComparator(a: ProvingJob, b: ProvingJob): -1 | 0 | 1 {
390
+ const aBlockNumber = a.blockNumber ?? 0;
391
+ const bBlockNumber = b.blockNumber ?? 0;
392
+ if (aBlockNumber < bBlockNumber) {
317
393
  return -1;
318
- } else if (a.blockNumber > b.blockNumber) {
394
+ } else if (aBlockNumber > bBlockNumber) {
319
395
  return 1;
320
396
  } else {
321
397
  return 0;
@@ -0,0 +1,43 @@
1
+ import type { ProofUri, ProvingJob, ProvingJobId, ProvingJobSettledResult } from '@aztec/circuit-types';
2
+
3
+ import { type ProvingBrokerDatabase } from '../proving_broker_database.js';
4
+
5
+ export class InMemoryBrokerDatabase implements ProvingBrokerDatabase {
6
+ private jobs = new Map<ProvingJobId, ProvingJob>();
7
+ private results = new Map<ProvingJobId, ProvingJobSettledResult>();
8
+
9
+ getProvingJob(id: ProvingJobId): ProvingJob | undefined {
10
+ return this.jobs.get(id);
11
+ }
12
+
13
+ getProvingJobResult(id: ProvingJobId): ProvingJobSettledResult | undefined {
14
+ return this.results.get(id);
15
+ }
16
+
17
+ addProvingJob(request: ProvingJob): Promise<void> {
18
+ this.jobs.set(request.id, request);
19
+ return Promise.resolve();
20
+ }
21
+
22
+ setProvingJobResult(id: ProvingJobId, value: ProofUri): Promise<void> {
23
+ this.results.set(id, { status: 'fulfilled', value });
24
+ return Promise.resolve();
25
+ }
26
+
27
+ setProvingJobError(id: ProvingJobId, reason: string): Promise<void> {
28
+ this.results.set(id, { status: 'rejected', reason });
29
+ return Promise.resolve();
30
+ }
31
+
32
+ deleteProvingJobAndResult(id: ProvingJobId): Promise<void> {
33
+ this.jobs.delete(id);
34
+ this.results.delete(id);
35
+ return Promise.resolve();
36
+ }
37
+
38
+ *allProvingJobs(): Iterable<[ProvingJob, ProvingJobSettledResult | undefined]> {
39
+ for (const item of this.jobs.values()) {
40
+ yield [item, this.results.get(item.id)] as const;
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,60 @@
1
+ import { type ProofUri, ProvingJob, type ProvingJobId, ProvingJobSettledResult } from '@aztec/circuit-types';
2
+ import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
3
+ import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
4
+ import { LmdbMetrics, Metrics, type TelemetryClient } from '@aztec/telemetry-client';
5
+
6
+ import { type ProvingBrokerDatabase } from '../proving_broker_database.js';
7
+
8
+ export class KVBrokerDatabase implements ProvingBrokerDatabase {
9
+ private jobs: AztecMap<ProvingJobId, string>;
10
+ private jobResults: AztecMap<ProvingJobId, string>;
11
+ private metrics: LmdbMetrics;
12
+
13
+ constructor(private store: AztecKVStore, client: TelemetryClient) {
14
+ this.metrics = new LmdbMetrics(
15
+ client.getMeter('KVBrokerDatabase'),
16
+ {
17
+ name: Metrics.PROVING_QUEUE_DB_MAP_SIZE,
18
+ description: 'Database map size for the proving broker',
19
+ },
20
+ {
21
+ name: Metrics.PROVING_QUEUE_DB_USED_SIZE,
22
+ description: 'Database used size for the proving broker',
23
+ },
24
+ { name: Metrics.PROVING_QUEUE_DB_NUM_ITEMS, description: 'Number of items in the broker database' },
25
+ () => store.estimateSize(),
26
+ );
27
+ this.jobs = store.openMap('proving_jobs');
28
+ this.jobResults = store.openMap('proving_job_results');
29
+ }
30
+
31
+ async addProvingJob(job: ProvingJob): Promise<void> {
32
+ await this.jobs.set(job.id, jsonStringify(job));
33
+ }
34
+
35
+ *allProvingJobs(): Iterable<[ProvingJob, ProvingJobSettledResult | undefined]> {
36
+ for (const jobStr of this.jobs.values()) {
37
+ const job = jsonParseWithSchema(jobStr, ProvingJob);
38
+ const resultStr = this.jobResults.get(job.id);
39
+ const result = resultStr ? jsonParseWithSchema(resultStr, ProvingJobSettledResult) : undefined;
40
+ yield [job, result];
41
+ }
42
+ }
43
+
44
+ deleteProvingJobAndResult(id: ProvingJobId): Promise<void> {
45
+ return this.store.transaction(() => {
46
+ void this.jobs.delete(id);
47
+ void this.jobResults.delete(id);
48
+ });
49
+ }
50
+
51
+ async setProvingJobError(id: ProvingJobId, reason: string): Promise<void> {
52
+ const result: ProvingJobSettledResult = { status: 'rejected', reason };
53
+ await this.jobResults.set(id, jsonStringify(result));
54
+ }
55
+
56
+ async setProvingJobResult(id: ProvingJobId, value: ProofUri): Promise<void> {
57
+ const result: ProvingJobSettledResult = { status: 'fulfilled', value };
58
+ await this.jobResults.set(id, jsonStringify(result));
59
+ }
60
+ }
@@ -1,30 +1,25 @@
1
- import {
2
- type V2ProofOutput,
3
- type V2ProvingJob,
4
- type V2ProvingJobId,
5
- type V2ProvingJobResult,
6
- } from '@aztec/circuit-types';
1
+ import { type ProofUri, type ProvingJob, type ProvingJobId, type ProvingJobSettledResult } from '@aztec/circuit-types';
7
2
 
8
3
  /**
9
4
  * A database for storing proof requests and their results
10
5
  */
11
- export interface ProvingJobDatabase {
6
+ export interface ProvingBrokerDatabase {
12
7
  /**
13
8
  * Saves a proof request so it can be retrieved later
14
9
  * @param request - The proof request to save
15
10
  */
16
- addProvingJob(request: V2ProvingJob): Promise<void>;
11
+ addProvingJob(request: ProvingJob): Promise<void>;
17
12
 
18
13
  /**
19
14
  * Removes a proof request from the backend
20
15
  * @param id - The ID of the proof request to remove
21
16
  */
22
- deleteProvingJobAndResult(id: V2ProvingJobId): Promise<void>;
17
+ deleteProvingJobAndResult(id: ProvingJobId): Promise<void>;
23
18
 
24
19
  /**
25
20
  * Returns an iterator over all saved proving jobs
26
21
  */
27
- allProvingJobs(): Iterable<[V2ProvingJob, V2ProvingJobResult | undefined]>;
22
+ allProvingJobs(): Iterable<[ProvingJob, ProvingJobSettledResult | undefined]>;
28
23
 
29
24
  /**
30
25
  * Saves the result of a proof request
@@ -32,7 +27,7 @@ export interface ProvingJobDatabase {
32
27
  * @param ProvingRequestType - The type of proof that was requested
33
28
  * @param value - The result of the proof request
34
29
  */
35
- setProvingJobResult(id: V2ProvingJobId, value: V2ProofOutput): Promise<void>;
30
+ setProvingJobResult(id: ProvingJobId, value: ProofUri): Promise<void>;
36
31
 
37
32
  /**
38
33
  * Saves an error that occurred while processing a proof request
@@ -40,5 +35,5 @@ export interface ProvingJobDatabase {
40
35
  * @param ProvingRequestType - The type of proof that was requested
41
36
  * @param err - The error that occurred while processing the proof request
42
37
  */
43
- setProvingJobError(id: V2ProvingJobId, err: Error): Promise<void>;
38
+ setProvingJobError(id: ProvingJobId, err: string): Promise<void>;
44
39
  }
@@ -0,0 +1,130 @@
1
+ import { ProvingRequestType } from '@aztec/circuit-types';
2
+ import { type Timer } from '@aztec/foundation/timer';
3
+ import {
4
+ Attributes,
5
+ type Histogram,
6
+ Metrics,
7
+ type ObservableGauge,
8
+ type ObservableResult,
9
+ type TelemetryClient,
10
+ type UpDownCounter,
11
+ ValueType,
12
+ millisecondBuckets,
13
+ } from '@aztec/telemetry-client';
14
+
15
+ export type MonitorCallback = (proofType: ProvingRequestType) => number;
16
+
17
+ export class ProvingBrokerInstrumentation {
18
+ private queueSize: ObservableGauge;
19
+ private activeJobs: ObservableGauge;
20
+ private resolvedJobs: UpDownCounter;
21
+ private rejectedJobs: UpDownCounter;
22
+ private timedOutJobs: UpDownCounter;
23
+ private jobWait: Histogram;
24
+ private jobDuration: Histogram;
25
+ private retriedJobs: UpDownCounter;
26
+
27
+ constructor(client: TelemetryClient, name = 'ProvingBroker') {
28
+ const meter = client.getMeter(name);
29
+
30
+ this.queueSize = meter.createObservableGauge(Metrics.PROVING_QUEUE_SIZE, {
31
+ valueType: ValueType.INT,
32
+ });
33
+
34
+ this.activeJobs = meter.createObservableGauge(Metrics.PROVING_QUEUE_ACTIVE_JOBS, {
35
+ valueType: ValueType.INT,
36
+ });
37
+
38
+ this.resolvedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_RESOLVED_JOBS, {
39
+ valueType: ValueType.INT,
40
+ });
41
+
42
+ this.rejectedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_REJECTED_JOBS, {
43
+ valueType: ValueType.INT,
44
+ });
45
+
46
+ this.retriedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_RETRIED_JOBS, {
47
+ valueType: ValueType.INT,
48
+ });
49
+
50
+ this.timedOutJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_TIMED_OUT_JOBS, {
51
+ valueType: ValueType.INT,
52
+ });
53
+
54
+ this.jobWait = meter.createHistogram(Metrics.PROVING_QUEUE_JOB_WAIT, {
55
+ description: 'Records how long a job sits in the queue',
56
+ unit: 'ms',
57
+ valueType: ValueType.INT,
58
+ advice: {
59
+ explicitBucketBoundaries: millisecondBuckets(1), // 10ms -> ~327s
60
+ },
61
+ });
62
+
63
+ this.jobDuration = meter.createHistogram(Metrics.PROVING_QUEUE_JOB_DURATION, {
64
+ description: 'Records how long a job takes to complete',
65
+ unit: 'ms',
66
+ valueType: ValueType.INT,
67
+ advice: {
68
+ explicitBucketBoundaries: millisecondBuckets(1), // 10ms -> ~327s
69
+ },
70
+ });
71
+ }
72
+
73
+ monitorQueueDepth(fn: MonitorCallback) {
74
+ this.queueSize.addCallback(obs => this.observe(obs, fn));
75
+ }
76
+
77
+ monitorActiveJobs(fn: MonitorCallback) {
78
+ this.activeJobs.addCallback(obs => this.observe(obs, fn));
79
+ }
80
+
81
+ incResolvedJobs(proofType: ProvingRequestType) {
82
+ this.resolvedJobs.add(1, {
83
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
84
+ });
85
+ }
86
+
87
+ incRejectedJobs(proofType: ProvingRequestType) {
88
+ this.rejectedJobs.add(1, {
89
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
90
+ });
91
+ }
92
+
93
+ incRetriedJobs(proofType: ProvingRequestType) {
94
+ this.retriedJobs.add(1, {
95
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
96
+ });
97
+ }
98
+
99
+ incTimedOutJobs(proofType: ProvingRequestType) {
100
+ this.timedOutJobs.add(1, {
101
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
102
+ });
103
+ }
104
+
105
+ recordJobWait(proofType: ProvingRequestType, msOrTimer: Timer | number) {
106
+ const duration = typeof msOrTimer === 'number' ? msOrTimer : Math.floor(msOrTimer.ms());
107
+ this.jobWait.record(duration, {
108
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
109
+ });
110
+ }
111
+
112
+ recordJobDuration(proofType: ProvingRequestType, msOrTimer: Timer | number) {
113
+ const duration = typeof msOrTimer === 'number' ? msOrTimer : Math.floor(msOrTimer.ms());
114
+ this.jobDuration.record(duration, {
115
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
116
+ });
117
+ }
118
+
119
+ private observe(obs: ObservableResult, fn: MonitorCallback) {
120
+ for (const proofType of Object.values(ProvingRequestType)) {
121
+ // a type predicate for TypeScript to recognize that we're only iterating over enum values
122
+ if (typeof proofType !== 'number') {
123
+ continue;
124
+ }
125
+ obs.observe(fn(proofType), {
126
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
127
+ });
128
+ }
129
+ }
130
+ }