@aztec/prover-client 0.0.1-commit.b655e406 → 0.0.1-commit.b8a057fa

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 (178) hide show
  1. package/dest/config.d.ts +2 -2
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +17 -3
  4. package/dest/index.d.ts +1 -1
  5. package/dest/light/index.d.ts +2 -0
  6. package/dest/light/index.d.ts.map +1 -0
  7. package/dest/light/index.js +1 -0
  8. package/dest/light/lightweight_checkpoint_builder.d.ts +52 -0
  9. package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -0
  10. package/dest/light/lightweight_checkpoint_builder.js +233 -0
  11. package/dest/mocks/fixtures.d.ts +1 -4
  12. package/dest/mocks/fixtures.d.ts.map +1 -1
  13. package/dest/mocks/fixtures.js +9 -18
  14. package/dest/mocks/test_context.d.ts +38 -55
  15. package/dest/mocks/test_context.d.ts.map +1 -1
  16. package/dest/mocks/test_context.js +143 -142
  17. package/dest/orchestrator/block-building-helpers.d.ts +18 -20
  18. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  19. package/dest/orchestrator/block-building-helpers.js +90 -115
  20. package/dest/orchestrator/block-proving-state.d.ts +20 -11
  21. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  22. package/dest/orchestrator/block-proving-state.js +87 -19
  23. package/dest/orchestrator/checkpoint-proving-state.d.ts +24 -27
  24. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -1
  25. package/dest/orchestrator/checkpoint-proving-state.js +28 -94
  26. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts +161 -0
  27. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts.map +1 -0
  28. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.js +1066 -0
  29. package/dest/orchestrator/chonk-cache.d.ts +39 -0
  30. package/dest/orchestrator/chonk-cache.d.ts.map +1 -0
  31. package/dest/orchestrator/chonk-cache.js +80 -0
  32. package/dest/orchestrator/index.d.ts +4 -2
  33. package/dest/orchestrator/index.d.ts.map +1 -1
  34. package/dest/orchestrator/index.js +3 -1
  35. package/dest/orchestrator/orchestrator_metrics.d.ts +1 -3
  36. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -1
  37. package/dest/orchestrator/orchestrator_metrics.js +2 -15
  38. package/dest/orchestrator/proving-scheduler.d.ts +81 -0
  39. package/dest/orchestrator/proving-scheduler.d.ts.map +1 -0
  40. package/dest/orchestrator/proving-scheduler.js +120 -0
  41. package/dest/orchestrator/top-tree-orchestrator.d.ts +88 -0
  42. package/dest/orchestrator/top-tree-orchestrator.d.ts.map +1 -0
  43. package/dest/orchestrator/top-tree-orchestrator.js +232 -0
  44. package/dest/orchestrator/top-tree-proving-state.d.ts +61 -0
  45. package/dest/orchestrator/top-tree-proving-state.d.ts.map +1 -0
  46. package/dest/orchestrator/top-tree-proving-state.js +185 -0
  47. package/dest/orchestrator/tx-proving-state.d.ts +7 -6
  48. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  49. package/dest/orchestrator/tx-proving-state.js +7 -16
  50. package/dest/prover-client/factory.d.ts +3 -3
  51. package/dest/prover-client/factory.d.ts.map +1 -1
  52. package/dest/prover-client/index.d.ts +1 -1
  53. package/dest/prover-client/prover-client.d.ts +65 -8
  54. package/dest/prover-client/prover-client.d.ts.map +1 -1
  55. package/dest/prover-client/prover-client.js +66 -14
  56. package/dest/proving_broker/broker_prover_facade.d.ts +26 -24
  57. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  58. package/dest/proving_broker/broker_prover_facade.js +21 -33
  59. package/dest/proving_broker/config.d.ts +14 -62
  60. package/dest/proving_broker/config.d.ts.map +1 -1
  61. package/dest/proving_broker/config.js +29 -6
  62. package/dest/proving_broker/factory.d.ts +1 -1
  63. package/dest/proving_broker/fixtures.d.ts +3 -2
  64. package/dest/proving_broker/fixtures.d.ts.map +1 -1
  65. package/dest/proving_broker/fixtures.js +3 -2
  66. package/dest/proving_broker/index.d.ts +2 -1
  67. package/dest/proving_broker/index.d.ts.map +1 -1
  68. package/dest/proving_broker/index.js +1 -0
  69. package/dest/proving_broker/proof_store/factory.d.ts +2 -5
  70. package/dest/proving_broker/proof_store/factory.d.ts.map +1 -1
  71. package/dest/proving_broker/proof_store/factory.js +7 -30
  72. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts +18 -0
  73. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts.map +1 -0
  74. package/dest/proving_broker/proof_store/file_store_proof_store.js +60 -0
  75. package/dest/proving_broker/proof_store/index.d.ts +2 -2
  76. package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
  77. package/dest/proving_broker/proof_store/index.js +1 -1
  78. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +1 -1
  79. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -1
  80. package/dest/proving_broker/proof_store/proof_store.d.ts +1 -1
  81. package/dest/proving_broker/proving_agent.d.ts +5 -9
  82. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  83. package/dest/proving_broker/proving_agent.js +4 -19
  84. package/dest/proving_broker/proving_broker.d.ts +8 -5
  85. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  86. package/dest/proving_broker/proving_broker.js +74 -22
  87. package/dest/proving_broker/proving_broker_database/memory.d.ts +3 -2
  88. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
  89. package/dest/proving_broker/proving_broker_database/persisted.d.ts +5 -3
  90. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  91. package/dest/proving_broker/proving_broker_database/persisted.js +394 -5
  92. package/dest/proving_broker/proving_broker_database.d.ts +3 -2
  93. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
  94. package/dest/proving_broker/proving_broker_instrumentation.d.ts +3 -1
  95. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
  96. package/dest/proving_broker/proving_broker_instrumentation.js +22 -35
  97. package/dest/proving_broker/proving_job_controller.d.ts +5 -3
  98. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  99. package/dest/proving_broker/proving_job_controller.js +8 -6
  100. package/dest/proving_broker/rpc.d.ts +9 -5
  101. package/dest/proving_broker/rpc.d.ts.map +1 -1
  102. package/dest/proving_broker/rpc.js +87 -23
  103. package/dest/test/epoch_settlement.d.ts +36 -0
  104. package/dest/test/epoch_settlement.d.ts.map +1 -0
  105. package/dest/test/epoch_settlement.js +52 -0
  106. package/dest/test/index.d.ts +2 -0
  107. package/dest/test/index.d.ts.map +1 -0
  108. package/dest/test/index.js +1 -0
  109. package/dest/test/mock_proof_store.d.ts +1 -1
  110. package/dest/test/mock_proof_store.d.ts.map +1 -1
  111. package/dest/test/mock_prover.d.ts +5 -6
  112. package/dest/test/mock_prover.d.ts.map +1 -1
  113. package/dest/test/mock_prover.js +4 -4
  114. package/package.json +25 -23
  115. package/src/config.ts +19 -3
  116. package/src/light/index.ts +1 -0
  117. package/src/light/lightweight_checkpoint_builder.ts +322 -0
  118. package/src/mocks/fixtures.ts +9 -31
  119. package/src/mocks/test_context.ts +182 -217
  120. package/src/orchestrator/block-building-helpers.ts +129 -209
  121. package/src/orchestrator/block-proving-state.ts +109 -22
  122. package/src/orchestrator/checkpoint-proving-state.ts +32 -123
  123. package/src/orchestrator/checkpoint-sub-tree-orchestrator.ts +1044 -0
  124. package/src/orchestrator/chonk-cache.ts +99 -0
  125. package/src/orchestrator/index.ts +8 -1
  126. package/src/orchestrator/orchestrator_metrics.ts +2 -25
  127. package/src/orchestrator/proving-scheduler.ts +160 -0
  128. package/src/orchestrator/top-tree-orchestrator.ts +384 -0
  129. package/src/orchestrator/top-tree-proving-state.ts +219 -0
  130. package/src/orchestrator/tx-proving-state.ts +10 -27
  131. package/src/prover-client/factory.ts +6 -2
  132. package/src/prover-client/prover-client.ts +148 -29
  133. package/src/proving_broker/broker_prover_facade.ts +47 -56
  134. package/src/proving_broker/config.ts +33 -3
  135. package/src/proving_broker/fixtures.ts +8 -3
  136. package/src/proving_broker/index.ts +1 -0
  137. package/src/proving_broker/proof_store/factory.ts +10 -32
  138. package/src/proving_broker/proof_store/file_store_proof_store.ts +78 -0
  139. package/src/proving_broker/proof_store/index.ts +1 -1
  140. package/src/proving_broker/proving_agent.ts +6 -19
  141. package/src/proving_broker/proving_broker.ts +70 -17
  142. package/src/proving_broker/proving_broker_database/memory.ts +2 -1
  143. package/src/proving_broker/proving_broker_database/persisted.ts +22 -7
  144. package/src/proving_broker/proving_broker_database.ts +2 -1
  145. package/src/proving_broker/proving_broker_instrumentation.ts +23 -35
  146. package/src/proving_broker/proving_job_controller.ts +13 -7
  147. package/src/proving_broker/rpc.ts +46 -20
  148. package/src/test/epoch_settlement.ts +82 -0
  149. package/src/test/index.ts +1 -0
  150. package/src/test/mock_prover.ts +3 -15
  151. package/dest/block-factory/index.d.ts +0 -2
  152. package/dest/block-factory/index.d.ts.map +0 -1
  153. package/dest/block-factory/index.js +0 -1
  154. package/dest/block-factory/light.d.ts +0 -38
  155. package/dest/block-factory/light.d.ts.map +0 -1
  156. package/dest/block-factory/light.js +0 -94
  157. package/dest/orchestrator/epoch-proving-state.d.ts +0 -73
  158. package/dest/orchestrator/epoch-proving-state.d.ts.map +0 -1
  159. package/dest/orchestrator/epoch-proving-state.js +0 -233
  160. package/dest/orchestrator/orchestrator.d.ts +0 -113
  161. package/dest/orchestrator/orchestrator.d.ts.map +0 -1
  162. package/dest/orchestrator/orchestrator.js +0 -848
  163. package/dest/prover-client/server-epoch-prover.d.ts +0 -31
  164. package/dest/prover-client/server-epoch-prover.d.ts.map +0 -1
  165. package/dest/prover-client/server-epoch-prover.js +0 -40
  166. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +0 -14
  167. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +0 -1
  168. package/dest/proving_broker/proof_store/gcs_proof_store.js +0 -52
  169. package/dest/proving_broker/proving_agent_instrumentation.d.ts +0 -8
  170. package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +0 -1
  171. package/dest/proving_broker/proving_agent_instrumentation.js +0 -16
  172. package/src/block-factory/index.ts +0 -1
  173. package/src/block-factory/light.ts +0 -140
  174. package/src/orchestrator/epoch-proving-state.ts +0 -328
  175. package/src/orchestrator/orchestrator.ts +0 -1272
  176. package/src/prover-client/server-epoch-prover.ts +0 -70
  177. package/src/proving_broker/proof_store/gcs_proof_store.ts +0 -76
  178. package/src/proving_broker/proving_agent_instrumentation.ts +0 -21
@@ -1,42 +1,20 @@
1
1
  import { createLogger } from '@aztec/foundation/log';
2
+ import { createFileStore } from '@aztec/stdlib/file-store';
2
3
 
3
- import { GoogleCloudStorageProofStore } from './gcs_proof_store.js';
4
+ import { FileStoreProofStore } from './file_store_proof_store.js';
4
5
  import { InlineProofStore } from './inline_proof_store.js';
5
6
  import type { ProofStore } from './proof_store.js';
6
7
 
7
- export function createProofStore(config: string | undefined, logger = createLogger('prover-client:proof-store')) {
8
- if (config === undefined) {
8
+ export async function createProofStore(
9
+ config: string | undefined,
10
+ logger = createLogger('prover-client:proof-store'),
11
+ ): Promise<ProofStore> {
12
+ if (!config) {
9
13
  logger.info('Creating inline proof store');
10
14
  return new InlineProofStore();
11
- } else if (config.startsWith('gs://')) {
12
- try {
13
- const url = new URL(config);
14
- const bucket = url.host;
15
- const path = url.pathname.replace(/^\/+/, '');
16
- logger.info(`Creating google cloud proof store at ${bucket}`, { bucket, path });
17
- return new GoogleCloudStorageProofStore(bucket, path);
18
- } catch {
19
- throw new Error(
20
- `Invalid google cloud proof store definition: '${config}'. Supported values are 'gs://bucket-name/path/to/store'.`,
21
- );
22
- }
23
- } else {
24
- throw new Error(`Unknown proof store config: '${config}'. Supported values are 'gs://bucket-name/path/to/store'.`);
25
15
  }
26
- }
27
16
 
28
- export function createProofStoreForUri(
29
- uri: string,
30
- logger = createLogger('prover-client:proof-store'),
31
- ): Pick<ProofStore, 'getProofInput' | 'getProofOutput'> {
32
- if (uri.startsWith('data://')) {
33
- return createProofStore(undefined, logger);
34
- } else if (uri.startsWith('gs://')) {
35
- const url = new URL(uri);
36
- const basePath = url.pathname.replace(/^\/+/, '').split('/').slice(0, -3);
37
- url.pathname = basePath.join('/');
38
- return createProofStore(uri, logger);
39
- } else {
40
- throw new Error(`Unknown proof store config: '${uri}'. Supported protocols are 'data://' and 'gs://'.`);
41
- }
17
+ const fileStore = await createFileStore(config, logger);
18
+ logger.info(`Creating file store proof store at ${config}`);
19
+ return new FileStoreProofStore(fileStore);
42
20
  }
@@ -0,0 +1,78 @@
1
+ import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
2
+ import type { FileStore } from '@aztec/stdlib/file-store';
3
+ import {
4
+ type ProofUri,
5
+ type ProvingJobId,
6
+ type ProvingJobInputs,
7
+ type ProvingJobInputsMap,
8
+ ProvingJobResult,
9
+ type ProvingJobResultsMap,
10
+ getProvingJobInputClassFor,
11
+ } from '@aztec/stdlib/interfaces/server';
12
+ import { ProvingRequestType } from '@aztec/stdlib/proofs';
13
+
14
+ import type { ProofStore } from './proof_store.js';
15
+
16
+ const INPUTS_PATH = 'inputs';
17
+ const OUTPUTS_PATH = 'outputs';
18
+
19
+ /**
20
+ * A proof store implementation backed by a generic FileStore.
21
+ * Supports any storage backend (GCS, S3, local filesystem) via the FileStore abstraction.
22
+ */
23
+ export class FileStoreProofStore implements ProofStore {
24
+ constructor(private readonly fileStore: FileStore) {}
25
+
26
+ async saveProofInput<T extends ProvingRequestType>(
27
+ id: ProvingJobId,
28
+ type: T,
29
+ inputs: ProvingJobInputsMap[T],
30
+ ): Promise<ProofUri> {
31
+ const path = `${INPUTS_PATH}/${ProvingRequestType[type]}/${id}`;
32
+ const uri = await this.fileStore.save(path, inputs.toBuffer());
33
+ return uri as ProofUri;
34
+ }
35
+
36
+ async saveProofOutput<T extends ProvingRequestType>(
37
+ id: ProvingJobId,
38
+ type: T,
39
+ result: ProvingJobResultsMap[T],
40
+ ): Promise<ProofUri> {
41
+ const jobResult = { type, result } as ProvingJobResult;
42
+ const json = jsonStringify(jobResult);
43
+ const path = `${OUTPUTS_PATH}/${ProvingRequestType[type]}/${id}.json`;
44
+ const uri = await this.fileStore.save(path, Buffer.from(json, 'utf-8'));
45
+ return uri as ProofUri;
46
+ }
47
+
48
+ async getProofInput(uri: ProofUri): Promise<ProvingJobInputs> {
49
+ try {
50
+ const buffer = await this.fileStore.read(uri);
51
+ const type = this.extractTypeFromUri(uri);
52
+ const inputs = getProvingJobInputClassFor(type).fromBuffer(buffer);
53
+ return { inputs, type } as ProvingJobInputs;
54
+ } catch (err) {
55
+ throw new Error(`Error getting proof input at ${uri}: ${err}`);
56
+ }
57
+ }
58
+
59
+ async getProofOutput(uri: ProofUri): Promise<ProvingJobResult> {
60
+ try {
61
+ const buffer = await this.fileStore.read(uri);
62
+ return jsonParseWithSchema(buffer.toString('utf-8'), ProvingJobResult);
63
+ } catch (err) {
64
+ throw new Error(`Error getting proof output at ${uri}: ${err}`);
65
+ }
66
+ }
67
+
68
+ private extractTypeFromUri(uri: string): ProvingRequestType {
69
+ const url = new URL(uri);
70
+ const pathParts = url.pathname.split('/').filter(Boolean);
71
+ const typeString = pathParts.at(-2);
72
+ const type = typeString ? ProvingRequestType[typeString as keyof typeof ProvingRequestType] : undefined;
73
+ if (type === undefined) {
74
+ throw new Error(`Unrecognized proof type ${typeString} in URI ${uri}`);
75
+ }
76
+ return type;
77
+ }
78
+ }
@@ -1,4 +1,4 @@
1
1
  export * from './proof_store.js';
2
2
  export * from './inline_proof_store.js';
3
3
  export * from './factory.js';
4
- export * from './gcs_proof_store.js';
4
+ export * from './file_store_proof_store.js';
@@ -1,5 +1,5 @@
1
1
  import { AbortError } from '@aztec/foundation/error';
2
- import { createLogger } from '@aztec/foundation/log';
2
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
3
3
  import { RunningPromise } from '@aztec/foundation/running-promise';
4
4
  import { truncate } from '@aztec/foundation/string';
5
5
  import { ProvingError } from '@aztec/stdlib/errors';
@@ -13,27 +13,17 @@ import type {
13
13
  ServerCircuitProver,
14
14
  } from '@aztec/stdlib/interfaces/server';
15
15
  import { ProvingRequestType } from '@aztec/stdlib/proofs';
16
- import {
17
- type TelemetryClient,
18
- type Traceable,
19
- type Tracer,
20
- getTelemetryClient,
21
- trackSpan,
22
- } from '@aztec/telemetry-client';
23
16
 
24
17
  import type { ProofStore } from './proof_store/index.js';
25
- import { ProvingAgentInstrumentation } from './proving_agent_instrumentation.js';
26
18
  import { ProvingJobController, ProvingJobControllerStatus } from './proving_job_controller.js';
27
19
 
28
20
  /**
29
21
  * A helper class that encapsulates a circuit prover and connects it to a job source.
30
22
  */
31
- export class ProvingAgent implements Traceable {
23
+ export class ProvingAgent {
32
24
  private currentJobController?: ProvingJobController;
33
25
  private runningPromise: RunningPromise;
34
- private instrumentation: ProvingAgentInstrumentation;
35
-
36
- public readonly tracer: Tracer;
26
+ private log: Logger;
37
27
 
38
28
  constructor(
39
29
  /** The source of proving jobs */
@@ -46,12 +36,9 @@ export class ProvingAgent implements Traceable {
46
36
  private proofAllowList: Array<ProvingRequestType> = [],
47
37
  /** How long to wait between jobs */
48
38
  private pollIntervalMs = 1000,
49
- /** A telemetry client through which to emit metrics */
50
- client: TelemetryClient = getTelemetryClient(),
51
- private log = createLogger('prover-client:proving-agent'),
39
+ bindings?: LoggerBindings,
52
40
  ) {
53
- this.tracer = client.getTracer('ProvingAgent');
54
- this.instrumentation = new ProvingAgentInstrumentation(client);
41
+ this.log = createLogger('prover-client:proving-agent', bindings);
55
42
  this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.pollIntervalMs);
56
43
  }
57
44
 
@@ -85,7 +72,6 @@ export class ProvingAgent implements Traceable {
85
72
  return this.runningPromise.isRunning() ? { status: 'running' } : { status: 'stopped' };
86
73
  }
87
74
 
88
- @trackSpan('ProvingAgent.safeWork')
89
75
  private async work() {
90
76
  // every tick we need to take one of the following actions:
91
77
  // 1. send a hearbeat to the broker that we're working on some job
@@ -175,6 +161,7 @@ export class ProvingAgent implements Traceable {
175
161
  // no need to await this here. The controller will stay alive (in DONE state) until the result is send to the broker
176
162
  void this.runningPromise.trigger();
177
163
  },
164
+ this.log.getBindings(),
178
165
  );
179
166
 
180
167
  if (abortedProofJobId) {
@@ -1,3 +1,4 @@
1
+ import { EpochNumber } from '@aztec/foundation/branded-types';
1
2
  import { createLogger } from '@aztec/foundation/log';
2
3
  import { type PromiseWithResolvers, RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
3
4
  import { PriorityMemoryQueue } from '@aztec/foundation/queue';
@@ -6,6 +7,7 @@ import {
6
7
  type GetProvingJobResponse,
7
8
  type ProofUri,
8
9
  type ProvingJob,
10
+ type ProvingJobBrokerDebug,
9
11
  type ProvingJobConsumer,
10
12
  type ProvingJobFilter,
11
13
  type ProvingJobId,
@@ -15,13 +17,7 @@ import {
15
17
  tryStop,
16
18
  } from '@aztec/stdlib/interfaces/server';
17
19
  import { ProvingRequestType } from '@aztec/stdlib/proofs';
18
- import {
19
- type TelemetryClient,
20
- type Traceable,
21
- type Tracer,
22
- getTelemetryClient,
23
- trackSpan,
24
- } from '@aztec/telemetry-client';
20
+ import { type TelemetryClient, type Traceable, type Tracer, getTelemetryClient } from '@aztec/telemetry-client';
25
21
 
26
22
  import assert from 'assert';
27
23
 
@@ -41,7 +37,7 @@ type EnqueuedProvingJob = Pick<ProvingJob, 'id' | 'epochNumber'>;
41
37
  * A broker that manages proof requests and distributes them to workers based on their priority.
42
38
  * It takes a backend that is responsible for storing and retrieving proof requests and results.
43
39
  */
44
- export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Traceable {
40
+ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, ProvingJobBrokerDebug, Traceable {
45
41
  private queues: ProvingQueues = {
46
42
  [ProvingRequestType.PUBLIC_VM]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
47
43
  [ProvingRequestType.PUBLIC_CHONK_VERIFIER]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
@@ -119,6 +115,8 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
119
115
 
120
116
  private started = false;
121
117
 
118
+ private debugReplayEnabled: boolean;
119
+
122
120
  public constructor(
123
121
  private database: ProvingBrokerDatabase,
124
122
  {
@@ -126,6 +124,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
126
124
  proverBrokerPollIntervalMs,
127
125
  proverBrokerJobMaxRetries,
128
126
  proverBrokerMaxEpochsToKeepResultsFor,
127
+ proverBrokerDebugReplayEnabled,
129
128
  }: Required<
130
129
  Pick<
131
130
  ProverBrokerConfig,
@@ -133,6 +132,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
133
132
  | 'proverBrokerPollIntervalMs'
134
133
  | 'proverBrokerJobMaxRetries'
135
134
  | 'proverBrokerMaxEpochsToKeepResultsFor'
135
+ | 'proverBrokerDebugReplayEnabled'
136
136
  >
137
137
  > = defaultProverBrokerConfig,
138
138
  client: TelemetryClient = getTelemetryClient(),
@@ -144,6 +144,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
144
144
  this.jobTimeoutMs = proverBrokerJobTimeoutMs!;
145
145
  this.maxRetries = proverBrokerJobMaxRetries!;
146
146
  this.maxEpochsToKeepResultsFor = proverBrokerMaxEpochsToKeepResultsFor!;
147
+ this.debugReplayEnabled = proverBrokerDebugReplayEnabled ?? false;
147
148
  }
148
149
 
149
150
  private measureQueueDepth: MonitorCallback = (type: ProvingRequestType) => {
@@ -246,6 +247,29 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
246
247
  return Promise.resolve(this.#reportProvingJobProgress(id, startedAt, filter));
247
248
  }
248
249
 
250
+ public async replayProvingJob(
251
+ jobId: ProvingJobId,
252
+ type: ProvingRequestType,
253
+ epochNumber: EpochNumber,
254
+ inputsUri: ProofUri,
255
+ ): Promise<ProvingJobStatus> {
256
+ if (!this.debugReplayEnabled) {
257
+ throw new Error('Debug replay not enabled. Set PROVER_BROKER_DEBUG_REPLAY_ENABLED=true');
258
+ }
259
+
260
+ this.logger.info(`Replaying proving job`, { provingJobId: jobId, epochNumber, inputsUri });
261
+
262
+ // Clear existing state and enqueue
263
+ this.cleanUpProvingJobState([jobId]);
264
+
265
+ const job: ProvingJob = { id: jobId, type, epochNumber, inputsUri };
266
+ this.jobsCache.set(jobId, job);
267
+ await this.database.addProvingJob(job);
268
+ this.enqueueJobInternal(job);
269
+
270
+ return { status: 'in-queue' };
271
+ }
272
+
249
273
  async #enqueueProvingJob(job: ProvingJob): Promise<ProvingJobStatus> {
250
274
  // We return the job status at the start of this call
251
275
  const jobStatus = this.#getProvingJobStatus(job.id);
@@ -290,18 +314,25 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
290
314
  // notify listeners of the cancellation
291
315
  if (!this.resultsCache.has(id)) {
292
316
  this.logger.info(`Cancelling job id=${id}`, { provingJobId: id });
293
- await this.#reportProvingJobError(id, 'Aborted', false);
317
+ await this.#reportProvingJobError(id, 'Aborted', false, undefined, true);
294
318
  }
295
319
  }
296
320
 
297
321
  private cleanUpProvingJobState(ids: ProvingJobId[]) {
322
+ const idsToClean = new Set(ids);
298
323
  for (const id of ids) {
299
324
  this.jobsCache.delete(id);
325
+ const deferred = this.promises.get(id);
326
+ if (deferred) {
327
+ deferred.resolve({ status: 'rejected', reason: 'Proving job cleaned up' });
328
+ }
300
329
  this.promises.delete(id);
301
330
  this.resultsCache.delete(id);
302
331
  this.inProgress.delete(id);
303
332
  this.retries.delete(id);
333
+ this.enqueuedAt.delete(id);
304
334
  }
335
+ this.completedJobNotifications = this.completedJobNotifications.filter(id => !idsToClean.has(id));
305
336
  }
306
337
 
307
338
  #getProvingJobStatus(id: ProvingJobId): ProvingJobStatus {
@@ -353,6 +384,8 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
353
384
  const enqueuedAt = this.enqueuedAt.get(job.id);
354
385
  if (enqueuedAt) {
355
386
  this.instrumentation.recordJobWait(job.type, enqueuedAt);
387
+ // we can clear this flag now.
388
+ this.enqueuedAt.delete(job.id);
356
389
  }
357
390
 
358
391
  return { job, time };
@@ -368,6 +401,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
368
401
  err: string,
369
402
  retry = false,
370
403
  filter?: ProvingJobFilter,
404
+ aborted = false,
371
405
  ): Promise<GetProvingJobResponse | undefined> {
372
406
  const info = this.inProgress.get(id);
373
407
  const item = this.jobsCache.get(id);
@@ -428,7 +462,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
428
462
  this.promises.get(id)!.resolve(result);
429
463
  this.completedJobNotifications.push(id);
430
464
 
431
- this.instrumentation.incRejectedJobs(item.type);
465
+ if (aborted) {
466
+ this.instrumentation.incAbortedJobs(item.type);
467
+ } else {
468
+ this.instrumentation.incRejectedJobs(item.type);
469
+ }
432
470
  if (info) {
433
471
  const duration = this.msTimeSource() - info.startedAt;
434
472
  this.instrumentation.recordJobDuration(item.type, duration);
@@ -561,23 +599,22 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
561
599
  return this.#getProvingJob(filter);
562
600
  }
563
601
 
564
- @trackSpan('ProvingBroker.cleanupPass')
565
602
  private async cleanupPass() {
566
- this.cleanupStaleJobs();
567
603
  this.reEnqueueExpiredJobs();
568
604
  const oldestEpochToKeep = this.oldestEpochToKeep();
569
605
  if (oldestEpochToKeep > 0) {
570
- await this.database.deleteAllProvingJobsOlderThanEpoch(oldestEpochToKeep);
606
+ this.cleanupJobsOlderThanEpoch(EpochNumber(oldestEpochToKeep));
607
+ await this.database.deleteAllProvingJobsOlderThanEpoch(EpochNumber(oldestEpochToKeep));
571
608
  this.logger.trace(`Deleted all epochs older than ${oldestEpochToKeep}`);
572
609
  }
573
610
  }
574
611
 
575
- private cleanupStaleJobs() {
612
+ private cleanupJobsOlderThanEpoch(epochNumber: EpochNumber) {
576
613
  const jobIds = Array.from(this.jobsCache.keys());
577
614
  const jobsToClean: ProvingJobId[] = [];
578
615
  for (const id of jobIds) {
579
616
  const job = this.jobsCache.get(id)!;
580
- if (this.isJobStale(job)) {
617
+ if (job.epochNumber < epochNumber) {
581
618
  jobsToClean.push(id);
582
619
  }
583
620
  }
@@ -601,10 +638,26 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
601
638
  const now = this.msTimeSource();
602
639
  const msSinceLastUpdate = now - metadata.lastUpdatedAt;
603
640
  if (msSinceLastUpdate >= this.jobTimeoutMs) {
604
- this.logger.warn(`Proving job id=${id} timed out. Adding it back to the queue.`, { provingJobId: id });
605
641
  this.inProgress.delete(id);
606
- this.enqueueJobInternal(item);
607
642
  this.instrumentation.incTimedOutJobs(item.type);
643
+
644
+ const retries = this.retries.get(id) ?? 0;
645
+ if (retries + 1 < this.maxRetries && !this.isJobStale(item)) {
646
+ this.logger.warn(`Proving job id=${id} timed out. Re-enqueueing (retry ${retries + 1}/${this.maxRetries}).`, {
647
+ provingJobId: id,
648
+ });
649
+ this.retries.set(id, retries + 1);
650
+ this.enqueueJobInternal(item);
651
+ } else {
652
+ this.logger.error(`Proving job id=${id} timed out after ${retries + 1} attempts. Marking as failed.`, {
653
+ provingJobId: id,
654
+ });
655
+ const result: ProvingJobSettledResult = { status: 'rejected', reason: 'Timed out' };
656
+ this.resultsCache.set(id, result);
657
+ this.promises.get(id)?.resolve(result);
658
+ this.completedJobNotifications.push(id);
659
+ this.instrumentation.incRejectedJobs(item.type);
660
+ }
608
661
  }
609
662
  }
610
663
  }
@@ -1,3 +1,4 @@
1
+ import { EpochNumber } from '@aztec/foundation/branded-types';
1
2
  import {
2
3
  type ProofUri,
3
4
  type ProvingJob,
@@ -43,7 +44,7 @@ export class InMemoryBrokerDatabase implements ProvingBrokerDatabase {
43
44
  return Promise.resolve();
44
45
  }
45
46
 
46
- deleteAllProvingJobsOlderThanEpoch(epochNumber: number): Promise<void> {
47
+ deleteAllProvingJobsOlderThanEpoch(epochNumber: EpochNumber): Promise<void> {
47
48
  const toDelete = [
48
49
  ...Array.from(this.jobs.keys()).filter(x => getEpochFromProvingJobId(x) < epochNumber),
49
50
  ...Array.from(this.results.keys()).filter(x => getEpochFromProvingJobId(x) < epochNumber),
@@ -1,3 +1,4 @@
1
+ import { EpochNumber } from '@aztec/foundation/branded-types';
1
2
  import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
2
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
3
4
  import { BatchQueue } from '@aztec/foundation/queue';
@@ -10,7 +11,14 @@ import {
10
11
  ProvingJobSettledResult,
11
12
  getEpochFromProvingJobId,
12
13
  } from '@aztec/stdlib/interfaces/server';
13
- import { Attributes, LmdbMetrics, type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
14
+ import {
15
+ Attributes,
16
+ LmdbMetrics,
17
+ type TelemetryClient,
18
+ type Tracer,
19
+ getTelemetryClient,
20
+ trackSpan,
21
+ } from '@aztec/telemetry-client';
14
22
 
15
23
  import { mkdir, readdir } from 'fs/promises';
16
24
  import { join } from 'path';
@@ -77,6 +85,8 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
77
85
 
78
86
  private batchQueue: BatchQueue<ProvingJob | [ProvingJobId, ProvingJobSettledResult], number>;
79
87
 
88
+ public readonly tracer: Tracer;
89
+
80
90
  private constructor(
81
91
  private epochs: Map<number, SingleEpochDatabase>,
82
92
  private config: ProverBrokerConfig,
@@ -91,6 +101,8 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
91
101
  () => this.estimateSize(),
92
102
  );
93
103
 
104
+ this.tracer = client.getTracer('KVBrokerDatabase');
105
+
94
106
  this.batchQueue = new BatchQueue(
95
107
  (items, key) => this.commitWrites(items, key),
96
108
  config.proverBrokerBatchSize,
@@ -104,7 +116,7 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
104
116
  const jobsToAdd = items.filter((item): item is ProvingJob => 'id' in item);
105
117
  const resultsToAdd = items.filter((item): item is [ProvingJobId, ProvingJobSettledResult] => Array.isArray(item));
106
118
 
107
- const db = await this.getEpochDatabase(epochNumber);
119
+ const db = await this.getEpochDatabase(EpochNumber(epochNumber));
108
120
  await db.batchWrite(jobsToAdd, resultsToAdd);
109
121
  }
110
122
 
@@ -142,7 +154,7 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
142
154
  const db = await openVersionedStoreAt(
143
155
  fullDirectory,
144
156
  SingleEpochDatabase.SCHEMA_VERSION,
145
- config.l1Contracts.rollupAddress,
157
+ config.rollupAddress,
146
158
  config.dataStoreMapSizeKb,
147
159
  );
148
160
  const epochDb = new SingleEpochDatabase(db);
@@ -164,8 +176,11 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
164
176
  }
165
177
  }
166
178
 
167
- async deleteAllProvingJobsOlderThanEpoch(epochNumber: number): Promise<void> {
168
- const oldEpochs = Array.from(this.epochs.keys()).filter(e => e < epochNumber);
179
+ @trackSpan('KVBrokerDatabase.deleteAllProvingJobsOlderThanEpoch', epochNumber => ({
180
+ [Attributes.EPOCH_NUMBER]: epochNumber,
181
+ }))
182
+ async deleteAllProvingJobsOlderThanEpoch(epochNumber: EpochNumber): Promise<void> {
183
+ const oldEpochs = Array.from(this.epochs.keys()).filter(e => e < Number(epochNumber));
169
184
  for (const old of oldEpochs) {
170
185
  const db = this.epochs.get(old);
171
186
  if (!db) {
@@ -196,7 +211,7 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
196
211
  return this.batchQueue.put([id, { status: 'fulfilled', value }], getEpochFromProvingJobId(id));
197
212
  }
198
213
 
199
- private async getEpochDatabase(epochNumber: number): Promise<SingleEpochDatabase> {
214
+ private async getEpochDatabase(epochNumber: EpochNumber): Promise<SingleEpochDatabase> {
200
215
  let epochDb = this.epochs.get(epochNumber);
201
216
  if (!epochDb) {
202
217
  const newEpochDirectory = join(this.config.dataDirectory!, epochNumber.toString());
@@ -207,7 +222,7 @@ export class KVBrokerDatabase implements ProvingBrokerDatabase {
207
222
  const db = await openVersionedStoreAt(
208
223
  newEpochDirectory,
209
224
  SingleEpochDatabase.SCHEMA_VERSION,
210
- this.config.l1Contracts.rollupAddress,
225
+ this.config.rollupAddress,
211
226
  this.config.dataStoreMapSizeKb,
212
227
  );
213
228
  epochDb = new SingleEpochDatabase(db);
@@ -1,3 +1,4 @@
1
+ import { EpochNumber } from '@aztec/foundation/branded-types';
1
2
  import type { ProofUri, ProvingJob, ProvingJobId, ProvingJobSettledResult } from '@aztec/stdlib/interfaces/server';
2
3
 
3
4
  /**
@@ -14,7 +15,7 @@ export interface ProvingBrokerDatabase {
14
15
  * Deletes all proving jobs belonging to epochs older than the given epoch
15
16
  * @param epochNumber - The epoch number beyond which jobs should be deleted
16
17
  */
17
- deleteAllProvingJobsOlderThanEpoch(epochNumber: number): Promise<void>;
18
+ deleteAllProvingJobsOlderThanEpoch(epochNumber: EpochNumber): Promise<void>;
18
19
 
19
20
  /**
20
21
  * Returns an iterator over all saved proving jobs
@@ -8,7 +8,7 @@ import {
8
8
  type ObservableResult,
9
9
  type TelemetryClient,
10
10
  type UpDownCounter,
11
- ValueType,
11
+ createUpDownCounterWithDefault,
12
12
  } from '@aztec/telemetry-client';
13
13
 
14
14
  export type MonitorCallback = (proofType: ProvingRequestType) => number;
@@ -18,6 +18,7 @@ export class ProvingBrokerInstrumentation {
18
18
  private activeJobs: ObservableGauge;
19
19
  private resolvedJobs: UpDownCounter;
20
20
  private rejectedJobs: UpDownCounter;
21
+ private abortedJobs: UpDownCounter;
21
22
  private timedOutJobs: UpDownCounter;
22
23
  private cachedJobs: UpDownCounter;
23
24
  private totalJobs: UpDownCounter;
@@ -28,49 +29,30 @@ export class ProvingBrokerInstrumentation {
28
29
  constructor(client: TelemetryClient, name = 'ProvingBroker') {
29
30
  const meter = client.getMeter(name);
30
31
 
31
- this.queueSize = meter.createObservableGauge(Metrics.PROVING_QUEUE_SIZE, {
32
- valueType: ValueType.INT,
33
- });
32
+ this.queueSize = meter.createObservableGauge(Metrics.PROVING_QUEUE_SIZE);
34
33
 
35
- this.activeJobs = meter.createObservableGauge(Metrics.PROVING_QUEUE_ACTIVE_JOBS, {
36
- valueType: ValueType.INT,
37
- });
34
+ this.activeJobs = meter.createObservableGauge(Metrics.PROVING_QUEUE_ACTIVE_JOBS);
38
35
 
39
- this.resolvedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_RESOLVED_JOBS, {
40
- valueType: ValueType.INT,
41
- });
36
+ const provingJobTypes = Object.values(ProvingRequestType).filter(v => typeof v === 'string');
37
+ const provingJobAttrs = { [Attributes.PROVING_JOB_TYPE]: provingJobTypes };
42
38
 
43
- this.rejectedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_REJECTED_JOBS, {
44
- valueType: ValueType.INT,
45
- });
39
+ this.resolvedJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_RESOLVED_JOBS, provingJobAttrs);
46
40
 
47
- this.retriedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_RETRIED_JOBS, {
48
- valueType: ValueType.INT,
49
- });
41
+ this.rejectedJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_REJECTED_JOBS, provingJobAttrs);
50
42
 
51
- this.timedOutJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_TIMED_OUT_JOBS, {
52
- valueType: ValueType.INT,
53
- });
43
+ this.abortedJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_ABORTED_JOBS, provingJobAttrs);
54
44
 
55
- this.cachedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_CACHED_JOBS, {
56
- valueType: ValueType.INT,
57
- });
45
+ this.retriedJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_RETRIED_JOBS, provingJobAttrs);
58
46
 
59
- this.totalJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_TOTAL_JOBS, {
60
- valueType: ValueType.INT,
61
- });
47
+ this.timedOutJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_TIMED_OUT_JOBS, provingJobAttrs);
62
48
 
63
- this.jobWait = meter.createHistogram(Metrics.PROVING_QUEUE_JOB_WAIT, {
64
- description: 'Records how long a job sits in the queue',
65
- unit: 'ms',
66
- valueType: ValueType.INT,
67
- });
49
+ this.cachedJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_CACHED_JOBS, provingJobAttrs);
68
50
 
69
- this.jobDuration = meter.createHistogram(Metrics.PROVING_QUEUE_JOB_DURATION, {
70
- description: 'Records how long a job takes to complete',
71
- unit: 'ms',
72
- valueType: ValueType.INT,
73
- });
51
+ this.totalJobs = createUpDownCounterWithDefault(meter, Metrics.PROVING_QUEUE_TOTAL_JOBS, provingJobAttrs);
52
+
53
+ this.jobWait = meter.createHistogram(Metrics.PROVING_QUEUE_JOB_WAIT);
54
+
55
+ this.jobDuration = meter.createHistogram(Metrics.PROVING_QUEUE_JOB_DURATION);
74
56
  }
75
57
 
76
58
  monitorQueueDepth(fn: MonitorCallback) {
@@ -93,6 +75,12 @@ export class ProvingBrokerInstrumentation {
93
75
  });
94
76
  }
95
77
 
78
+ incAbortedJobs(proofType: ProvingRequestType) {
79
+ this.abortedJobs.add(1, {
80
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
81
+ });
82
+ }
83
+
96
84
  incRetriedJobs(proofType: ProvingRequestType) {
97
85
  this.retriedJobs.add(1, {
98
86
  [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
@@ -1,6 +1,7 @@
1
- import { randomBytes } from '@aztec/foundation/crypto';
1
+ import { EpochNumber } from '@aztec/foundation/branded-types';
2
+ import { randomBytes } from '@aztec/foundation/crypto/random';
2
3
  import { AbortError } from '@aztec/foundation/error';
3
- import { createLogger } from '@aztec/foundation/log';
4
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
4
5
  import type {
5
6
  ProvingJobId,
6
7
  ProvingJobInputs,
@@ -20,16 +21,22 @@ export class ProvingJobController {
20
21
  private promise?: Promise<void>;
21
22
  private abortController = new AbortController();
22
23
  private result?: ProvingJobResultsMap[ProvingRequestType] | Error;
24
+ private log: Logger;
23
25
 
24
26
  constructor(
25
27
  private jobId: ProvingJobId,
26
28
  private inputs: ProvingJobInputs,
27
- private epochNumber: number,
29
+ private epochNumber: EpochNumber,
28
30
  private startedAt: number,
29
31
  private circuitProver: ServerCircuitProver,
30
32
  private onComplete: () => void,
31
- private log = createLogger('prover-client:proving-agent:job-controller-' + randomBytes(4).toString('hex')),
32
- ) {}
33
+ bindings?: LoggerBindings,
34
+ ) {
35
+ this.log = createLogger('prover-client:proving-agent:job-controller', {
36
+ instanceId: randomBytes(4).toString('hex'),
37
+ ...bindings,
38
+ });
39
+ }
33
40
 
34
41
  public start(): void {
35
42
  if (this.status !== ProvingJobControllerStatus.IDLE) {
@@ -124,8 +131,7 @@ export class ProvingJobController {
124
131
  const signal = this.abortController.signal;
125
132
  switch (type) {
126
133
  case ProvingRequestType.PUBLIC_VM: {
127
- // TODO(#14234)[Unconditional PIs validation]: Remove argument "undefined".
128
- return await this.circuitProver.getAvmProof(inputs, undefined, signal, this.epochNumber);
134
+ return await this.circuitProver.getAvmProof(inputs, signal, this.epochNumber);
129
135
  }
130
136
 
131
137
  case ProvingRequestType.PUBLIC_CHONK_VERIFIER: {