@aztec/prover-client 0.0.0-test.0 → 0.0.1-commit.001888fc

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 (155) hide show
  1. package/dest/config.d.ts +8 -8
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +12 -2
  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 +223 -0
  11. package/dest/mocks/fixtures.d.ts +8 -8
  12. package/dest/mocks/fixtures.d.ts.map +1 -1
  13. package/dest/mocks/fixtures.js +36 -17
  14. package/dest/mocks/test_context.d.ts +43 -32
  15. package/dest/mocks/test_context.d.ts.map +1 -1
  16. package/dest/mocks/test_context.js +152 -87
  17. package/dest/orchestrator/block-building-helpers.d.ts +36 -29
  18. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  19. package/dest/orchestrator/block-building-helpers.js +170 -189
  20. package/dest/orchestrator/block-proving-state.d.ts +73 -48
  21. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  22. package/dest/orchestrator/block-proving-state.js +289 -177
  23. package/dest/orchestrator/checkpoint-proving-state.d.ts +76 -0
  24. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -0
  25. package/dest/orchestrator/checkpoint-proving-state.js +243 -0
  26. package/dest/orchestrator/epoch-proving-state.d.ts +43 -28
  27. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  28. package/dest/orchestrator/epoch-proving-state.js +179 -73
  29. package/dest/orchestrator/index.d.ts +1 -1
  30. package/dest/orchestrator/orchestrator.d.ts +55 -35
  31. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  32. package/dest/orchestrator/orchestrator.js +874 -314
  33. package/dest/orchestrator/orchestrator_metrics.d.ts +1 -1
  34. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -1
  35. package/dest/orchestrator/orchestrator_metrics.js +2 -6
  36. package/dest/orchestrator/tx-proving-state.d.ts +15 -12
  37. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  38. package/dest/orchestrator/tx-proving-state.js +27 -44
  39. package/dest/prover-client/factory.d.ts +3 -3
  40. package/dest/prover-client/factory.d.ts.map +1 -1
  41. package/dest/prover-client/index.d.ts +1 -1
  42. package/dest/prover-client/prover-client.d.ts +8 -8
  43. package/dest/prover-client/prover-client.d.ts.map +1 -1
  44. package/dest/prover-client/prover-client.js +19 -13
  45. package/dest/prover-client/server-epoch-prover.d.ts +16 -12
  46. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
  47. package/dest/prover-client/server-epoch-prover.js +11 -11
  48. package/dest/proving_broker/broker_prover_facade.d.ts +28 -19
  49. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  50. package/dest/proving_broker/broker_prover_facade.js +64 -45
  51. package/dest/proving_broker/config.d.ts +32 -11
  52. package/dest/proving_broker/config.d.ts.map +1 -1
  53. package/dest/proving_broker/config.js +42 -8
  54. package/dest/proving_broker/factory.d.ts +2 -2
  55. package/dest/proving_broker/factory.d.ts.map +1 -1
  56. package/dest/proving_broker/factory.js +5 -1
  57. package/dest/proving_broker/fixtures.d.ts +3 -2
  58. package/dest/proving_broker/fixtures.d.ts.map +1 -1
  59. package/dest/proving_broker/fixtures.js +3 -2
  60. package/dest/proving_broker/index.d.ts +1 -1
  61. package/dest/proving_broker/proof_store/factory.d.ts +2 -5
  62. package/dest/proving_broker/proof_store/factory.d.ts.map +1 -1
  63. package/dest/proving_broker/proof_store/factory.js +7 -30
  64. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts +18 -0
  65. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts.map +1 -0
  66. package/dest/proving_broker/proof_store/file_store_proof_store.js +60 -0
  67. package/dest/proving_broker/proof_store/index.d.ts +2 -1
  68. package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
  69. package/dest/proving_broker/proof_store/index.js +1 -0
  70. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +1 -1
  71. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -1
  72. package/dest/proving_broker/proof_store/proof_store.d.ts +1 -1
  73. package/dest/proving_broker/proving_agent.d.ts +8 -12
  74. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  75. package/dest/proving_broker/proving_agent.js +86 -65
  76. package/dest/proving_broker/proving_broker.d.ts +17 -5
  77. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  78. package/dest/proving_broker/proving_broker.js +76 -37
  79. package/dest/proving_broker/proving_broker_database/memory.d.ts +3 -2
  80. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
  81. package/dest/proving_broker/proving_broker_database/memory.js +1 -1
  82. package/dest/proving_broker/proving_broker_database/persisted.d.ts +5 -3
  83. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  84. package/dest/proving_broker/proving_broker_database/persisted.js +401 -11
  85. package/dest/proving_broker/proving_broker_database.d.ts +3 -2
  86. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
  87. package/dest/proving_broker/proving_broker_instrumentation.d.ts +3 -1
  88. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
  89. package/dest/proving_broker/proving_broker_instrumentation.js +22 -35
  90. package/dest/proving_broker/proving_job_controller.d.ts +11 -10
  91. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  92. package/dest/proving_broker/proving_job_controller.js +92 -62
  93. package/dest/proving_broker/rpc.d.ts +7 -7
  94. package/dest/proving_broker/rpc.d.ts.map +1 -1
  95. package/dest/proving_broker/rpc.js +9 -4
  96. package/dest/test/mock_proof_store.d.ts +9 -0
  97. package/dest/test/mock_proof_store.d.ts.map +1 -0
  98. package/dest/test/mock_proof_store.js +10 -0
  99. package/dest/test/mock_prover.d.ts +23 -17
  100. package/dest/test/mock_prover.d.ts.map +1 -1
  101. package/dest/test/mock_prover.js +38 -20
  102. package/package.json +34 -33
  103. package/src/config.ts +25 -9
  104. package/src/light/index.ts +1 -0
  105. package/src/light/lightweight_checkpoint_builder.ts +312 -0
  106. package/src/mocks/fixtures.ts +46 -40
  107. package/src/mocks/test_context.ts +223 -116
  108. package/src/orchestrator/block-building-helpers.ts +258 -334
  109. package/src/orchestrator/block-proving-state.ts +334 -231
  110. package/src/orchestrator/checkpoint-proving-state.ts +349 -0
  111. package/src/orchestrator/epoch-proving-state.ts +239 -111
  112. package/src/orchestrator/orchestrator.ts +674 -355
  113. package/src/orchestrator/orchestrator_metrics.ts +2 -6
  114. package/src/orchestrator/tx-proving-state.ts +48 -66
  115. package/src/prover-client/factory.ts +6 -2
  116. package/src/prover-client/prover-client.ts +49 -38
  117. package/src/prover-client/server-epoch-prover.ts +40 -22
  118. package/src/proving_broker/broker_prover_facade.ts +219 -133
  119. package/src/proving_broker/config.ts +48 -8
  120. package/src/proving_broker/factory.ts +2 -1
  121. package/src/proving_broker/fixtures.ts +8 -3
  122. package/src/proving_broker/proof_store/factory.ts +10 -32
  123. package/src/proving_broker/proof_store/file_store_proof_store.ts +78 -0
  124. package/src/proving_broker/proof_store/index.ts +1 -0
  125. package/src/proving_broker/proof_store/inline_proof_store.ts +1 -1
  126. package/src/proving_broker/proving_agent.ts +95 -66
  127. package/src/proving_broker/proving_broker.ts +94 -44
  128. package/src/proving_broker/proving_broker_database/memory.ts +3 -2
  129. package/src/proving_broker/proving_broker_database/persisted.ts +29 -13
  130. package/src/proving_broker/proving_broker_database.ts +2 -1
  131. package/src/proving_broker/proving_broker_instrumentation.ts +23 -35
  132. package/src/proving_broker/proving_job_controller.ts +100 -83
  133. package/src/proving_broker/rpc.ts +14 -5
  134. package/src/test/mock_proof_store.ts +14 -0
  135. package/src/test/mock_prover.ts +156 -64
  136. package/dest/bin/get-proof-inputs.d.ts +0 -2
  137. package/dest/bin/get-proof-inputs.d.ts.map +0 -1
  138. package/dest/bin/get-proof-inputs.js +0 -51
  139. package/dest/block_builder/index.d.ts +0 -6
  140. package/dest/block_builder/index.d.ts.map +0 -1
  141. package/dest/block_builder/index.js +0 -1
  142. package/dest/block_builder/light.d.ts +0 -33
  143. package/dest/block_builder/light.d.ts.map +0 -1
  144. package/dest/block_builder/light.js +0 -82
  145. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +0 -14
  146. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +0 -1
  147. package/dest/proving_broker/proof_store/gcs_proof_store.js +0 -51
  148. package/dest/proving_broker/proving_agent_instrumentation.d.ts +0 -8
  149. package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +0 -1
  150. package/dest/proving_broker/proving_agent_instrumentation.js +0 -16
  151. package/src/bin/get-proof-inputs.ts +0 -59
  152. package/src/block_builder/index.ts +0 -6
  153. package/src/block_builder/light.ts +0 -101
  154. package/src/proving_broker/proof_store/gcs_proof_store.ts +0 -72
  155. 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 (err) {
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,3 +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 './file_store_proof_store.js';
@@ -52,7 +52,7 @@ export class InlineProofStore implements ProofStore {
52
52
  return (PREFIX + SEPARATOR + encoded) as ProofUri;
53
53
  }
54
54
 
55
- private decode<T>(uri: ProofUri, schema: ZodFor<T>): Promise<T> {
55
+ private decode<T>(uri: ProofUri, schema: ZodFor<T>): T {
56
56
  const [prefix, data] = uri.split(SEPARATOR);
57
57
  if (prefix !== PREFIX) {
58
58
  throw new Error('Invalid proof input URI: ' + prefix);
@@ -1,10 +1,11 @@
1
- import { createLogger } from '@aztec/foundation/log';
1
+ import { AbortError } from '@aztec/foundation/error';
2
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
2
3
  import { RunningPromise } from '@aztec/foundation/running-promise';
3
4
  import { truncate } from '@aztec/foundation/string';
4
- import { Timer } from '@aztec/foundation/timer';
5
5
  import { ProvingError } from '@aztec/stdlib/errors';
6
6
  import type {
7
- ProvingJob,
7
+ GetProvingJobResponse,
8
+ ProverAgentStatus,
8
9
  ProvingJobConsumer,
9
10
  ProvingJobId,
10
11
  ProvingJobInputs,
@@ -12,28 +13,17 @@ import type {
12
13
  ServerCircuitProver,
13
14
  } from '@aztec/stdlib/interfaces/server';
14
15
  import { ProvingRequestType } from '@aztec/stdlib/proofs';
15
- import {
16
- type TelemetryClient,
17
- type Traceable,
18
- type Tracer,
19
- getTelemetryClient,
20
- trackSpan,
21
- } from '@aztec/telemetry-client';
22
16
 
23
17
  import type { ProofStore } from './proof_store/index.js';
24
- import { ProvingAgentInstrumentation } from './proving_agent_instrumentation.js';
25
18
  import { ProvingJobController, ProvingJobControllerStatus } from './proving_job_controller.js';
26
19
 
27
20
  /**
28
21
  * A helper class that encapsulates a circuit prover and connects it to a job source.
29
22
  */
30
- export class ProvingAgent implements Traceable {
23
+ export class ProvingAgent {
31
24
  private currentJobController?: ProvingJobController;
32
25
  private runningPromise: RunningPromise;
33
- private instrumentation: ProvingAgentInstrumentation;
34
- private idleTimer: Timer | undefined;
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
 
@@ -64,7 +51,6 @@ export class ProvingAgent implements Traceable {
64
51
  }
65
52
 
66
53
  public start(): void {
67
- this.idleTimer = new Timer();
68
54
  this.runningPromise.start();
69
55
  }
70
56
 
@@ -73,41 +59,77 @@ export class ProvingAgent implements Traceable {
73
59
  await this.runningPromise.stop();
74
60
  }
75
61
 
76
- @trackSpan('ProvingAgent.safeWork')
62
+ public getStatus(): ProverAgentStatus {
63
+ if (this.currentJobController) {
64
+ return {
65
+ status: 'proving',
66
+ jobId: this.currentJobController.getJobId(),
67
+ proofType: this.currentJobController.getProofType(),
68
+ startedAtISO: new Date(this.currentJobController.getStartedAt()).toISOString(),
69
+ };
70
+ }
71
+
72
+ return this.runningPromise.isRunning() ? { status: 'running' } : { status: 'stopped' };
73
+ }
74
+
77
75
  private async work() {
78
- // every tick we need to
79
- // (1) either do a heartbeat, telling the broker that we're working
80
- // (2) get a new job
81
- // If during (1) the broker returns a new job that means we can cancel the current job and start the new one
82
- let maybeJob: { job: ProvingJob; time: number } | undefined;
83
- if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.PROVING) {
84
- maybeJob = await this.broker.reportProvingJobProgress(
85
- this.currentJobController.getJobId(),
86
- this.currentJobController.getStartedAt(),
87
- { allowList: this.proofAllowList },
88
- );
76
+ // every tick we need to take one of the following actions:
77
+ // 1. send a hearbeat to the broker that we're working on some job
78
+ // 2. if the job is complete, send its result to the broker
79
+ // 3. get a job from the broker
80
+ // Any one of these actions could give us a new job to work on. If that happens we abort the current job.
81
+ //
82
+ // This loop gets triggered in one of two ways:
83
+ // - either on a timer (see pollIntervalMs)
84
+ // - or when a proof completes
85
+ let maybeJob: GetProvingJobResponse | undefined;
86
+
87
+ if (this.currentJobController) {
88
+ const status = this.currentJobController.getStatus();
89
+ const jobId = this.currentJobController.getJobId();
90
+ const proofType = this.currentJobController.getProofType();
91
+ const startedAt = this.currentJobController.getStartedAt();
92
+ const result = this.currentJobController.getResult();
93
+
94
+ if (status === ProvingJobControllerStatus.RUNNING) {
95
+ maybeJob = await this.broker.reportProvingJobProgress(jobId, startedAt, { allowList: this.proofAllowList });
96
+ } else if (status === ProvingJobControllerStatus.DONE) {
97
+ if (result) {
98
+ maybeJob = await this.reportResult(jobId, proofType, result);
99
+ } else {
100
+ this.log.warn(
101
+ `Job controller for job ${this.currentJobController.getJobId()} is done but doesn't have a result`,
102
+ { jobId },
103
+ );
104
+ maybeJob = await this.reportResult(
105
+ jobId,
106
+ proofType,
107
+ new ProvingError('No result found after proving', undefined, /* retry */ true),
108
+ );
109
+ }
110
+
111
+ this.currentJobController = undefined;
112
+ } else {
113
+ // IDLE status should not be seen because a job is started as soon as it is created
114
+ this.log.warn(`Idle job controller for job: ${this.currentJobController.getJobId()}. Skipping main loop work`, {
115
+ jobId: this.currentJobController.getJobId(),
116
+ });
117
+ return;
118
+ }
89
119
  } else {
90
120
  maybeJob = await this.broker.getProvingJob({ allowList: this.proofAllowList });
91
121
  }
92
122
 
93
- if (!maybeJob) {
94
- return;
95
- }
96
-
97
- if (this.idleTimer) {
98
- this.instrumentation.recordIdleTime(this.idleTimer);
123
+ if (maybeJob) {
124
+ await this.startJob(maybeJob);
99
125
  }
100
- this.idleTimer = undefined;
101
-
102
- const { job, time } = maybeJob;
103
- await this.startJob(job, time);
104
126
  }
105
127
 
106
- private async startJob(job: ProvingJob, startedAt: number): Promise<void> {
128
+ private async startJob({ job, time: startedAt }: GetProvingJobResponse): Promise<void> {
107
129
  let abortedProofJobId: string | undefined;
108
130
  let abortedProofName: string | undefined;
109
131
 
110
- if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.PROVING) {
132
+ if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.RUNNING) {
111
133
  abortedProofJobId = this.currentJobController.getJobId();
112
134
  abortedProofName = this.currentJobController.getProofTypeName();
113
135
  this.currentJobController?.abort();
@@ -116,13 +138,13 @@ export class ProvingAgent implements Traceable {
116
138
  let inputs: ProvingJobInputs;
117
139
  try {
118
140
  inputs = await this.proofStore.getProofInput(job.inputsUri);
119
- } catch (err) {
141
+ } catch {
120
142
  const maybeJob = await this.broker.reportProvingJobError(job.id, 'Failed to load proof inputs', true, {
121
143
  allowList: this.proofAllowList,
122
144
  });
123
145
 
124
146
  if (maybeJob) {
125
- return this.startJob(maybeJob.job, maybeJob.time);
147
+ return this.startJob(maybeJob);
126
148
  }
127
149
 
128
150
  return;
@@ -134,7 +156,12 @@ export class ProvingAgent implements Traceable {
134
156
  job.epochNumber,
135
157
  startedAt,
136
158
  this.circuitProver,
137
- this.handleJobResult,
159
+ () => {
160
+ // trigger a run of the main work loop when proving completes
161
+ // no need to await this here. The controller will stay alive (in DONE state) until the result is send to the broker
162
+ void this.runningPromise.trigger();
163
+ },
164
+ this.log.getBindings(),
138
165
  );
139
166
 
140
167
  if (abortedProofJobId) {
@@ -154,28 +181,30 @@ export class ProvingAgent implements Traceable {
154
181
  this.currentJobController.start();
155
182
  }
156
183
 
157
- handleJobResult = async <T extends ProvingRequestType>(
184
+ private async reportResult<T extends ProvingRequestType>(
158
185
  jobId: ProvingJobId,
159
186
  type: T,
160
- err: Error | undefined,
161
- result: ProvingJobResultsMap[T] | undefined,
162
- ) => {
163
- let maybeJob: { job: ProvingJob; time: number } | undefined;
164
- if (err) {
165
- const retry = err.name === ProvingError.NAME ? (err as ProvingError).retry : false;
166
- this.log.error(`Job id=${jobId} type=${ProvingRequestType[type]} failed err=${err.message} retry=${retry}`, err);
167
- maybeJob = await this.broker.reportProvingJobError(jobId, err.message, retry, { allowList: this.proofAllowList });
168
- } else if (result) {
187
+ result: ProvingJobResultsMap[T] | Error,
188
+ ): Promise<GetProvingJobResponse | undefined> {
189
+ let maybeJob: GetProvingJobResponse | undefined;
190
+ if (result instanceof AbortError) {
191
+ // no-op
192
+ this.log.warn(`Job id=${jobId} was aborted. Not reporting result back to broker`, result);
193
+ } else if (result instanceof Error) {
194
+ const retry = result.name === ProvingError.NAME ? (result as ProvingError).retry : false;
195
+ this.log.error(
196
+ `Job id=${jobId} type=${ProvingRequestType[type]} failed err=${result.message} retry=${retry}`,
197
+ result,
198
+ );
199
+ maybeJob = await this.broker.reportProvingJobError(jobId, result.message, retry, {
200
+ allowList: this.proofAllowList,
201
+ });
202
+ } else {
169
203
  const outputUri = await this.proofStore.saveProofOutput(jobId, type, result);
170
204
  this.log.info(`Job id=${jobId} type=${ProvingRequestType[type]} completed outputUri=${truncate(outputUri)}`);
171
205
  maybeJob = await this.broker.reportProvingJobSuccess(jobId, outputUri, { allowList: this.proofAllowList });
172
206
  }
173
207
 
174
- if (maybeJob) {
175
- const { job, time } = maybeJob;
176
- await this.startJob(job, time);
177
- } else {
178
- this.idleTimer = new Timer();
179
- }
180
- };
208
+ return maybeJob;
209
+ }
181
210
  }
@@ -1,26 +1,23 @@
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';
4
5
  import { Timer } from '@aztec/foundation/timer';
5
- import type {
6
- GetProvingJobResponse,
7
- ProofUri,
8
- ProvingJob,
9
- ProvingJobConsumer,
10
- ProvingJobFilter,
11
- ProvingJobId,
12
- ProvingJobProducer,
13
- ProvingJobSettledResult,
14
- ProvingJobStatus,
6
+ import {
7
+ type GetProvingJobResponse,
8
+ type ProofUri,
9
+ type ProvingJob,
10
+ type ProvingJobBrokerDebug,
11
+ type ProvingJobConsumer,
12
+ type ProvingJobFilter,
13
+ type ProvingJobId,
14
+ type ProvingJobProducer,
15
+ type ProvingJobSettledResult,
16
+ type ProvingJobStatus,
17
+ tryStop,
15
18
  } from '@aztec/stdlib/interfaces/server';
16
19
  import { ProvingRequestType } from '@aztec/stdlib/proofs';
17
- import {
18
- type TelemetryClient,
19
- type Traceable,
20
- type Tracer,
21
- getTelemetryClient,
22
- trackSpan,
23
- } from '@aztec/telemetry-client';
20
+ import { type TelemetryClient, type Traceable, type Tracer, getTelemetryClient } from '@aztec/telemetry-client';
24
21
 
25
22
  import assert from 'assert';
26
23
 
@@ -40,23 +37,36 @@ type EnqueuedProvingJob = Pick<ProvingJob, 'id' | 'epochNumber'>;
40
37
  * A broker that manages proof requests and distributes them to workers based on their priority.
41
38
  * It takes a backend that is responsible for storing and retrieving proof requests and results.
42
39
  */
43
- export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Traceable {
40
+ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, ProvingJobBrokerDebug, Traceable {
44
41
  private queues: ProvingQueues = {
45
42
  [ProvingRequestType.PUBLIC_VM]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
46
- [ProvingRequestType.TUBE_PROOF]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
43
+ [ProvingRequestType.PUBLIC_CHONK_VERIFIER]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
47
44
 
48
- [ProvingRequestType.PRIVATE_BASE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
49
- [ProvingRequestType.PUBLIC_BASE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
50
- [ProvingRequestType.MERGE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
45
+ [ProvingRequestType.PRIVATE_TX_BASE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
46
+ [ProvingRequestType.PUBLIC_TX_BASE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
47
+ [ProvingRequestType.TX_MERGE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
51
48
  [ProvingRequestType.ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
52
49
 
53
50
  [ProvingRequestType.BLOCK_MERGE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
51
+ [ProvingRequestType.BLOCK_ROOT_FIRST_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
52
+ [ProvingRequestType.BLOCK_ROOT_SINGLE_TX_FIRST_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(
53
+ provingJobComparator,
54
+ ),
55
+ [ProvingRequestType.BLOCK_ROOT_EMPTY_TX_FIRST_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(
56
+ provingJobComparator,
57
+ ),
54
58
  [ProvingRequestType.BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
55
- [ProvingRequestType.SINGLE_TX_BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
56
- [ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
59
+ [ProvingRequestType.BLOCK_ROOT_SINGLE_TX_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
57
60
 
58
- [ProvingRequestType.BASE_PARITY]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
59
- [ProvingRequestType.ROOT_PARITY]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
61
+ [ProvingRequestType.CHECKPOINT_ROOT_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
62
+ [ProvingRequestType.CHECKPOINT_ROOT_SINGLE_BLOCK_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(
63
+ provingJobComparator,
64
+ ),
65
+ [ProvingRequestType.CHECKPOINT_MERGE_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
66
+ [ProvingRequestType.CHECKPOINT_PADDING_ROLLUP]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
67
+
68
+ [ProvingRequestType.PARITY_BASE]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
69
+ [ProvingRequestType.PARITY_ROOT]: new PriorityMemoryQueue<EnqueuedProvingJob>(provingJobComparator),
60
70
  };
61
71
 
62
72
  // holds a copy of the database in memory in order to quickly fulfill requests
@@ -93,7 +103,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
93
103
  /**
94
104
  * The broker keeps track of the highest epoch its seen.
95
105
  * This information is used for garbage collection: once it reaches the next epoch, it can start pruning the database of old state.
96
- * It is important that this value is initialised to zero. This ensures that we don't delete any old jobs until the current
106
+ * It is important that this value is initialized to zero. This ensures that we don't delete any old jobs until the current
97
107
  * process instance receives a job request informing it of the actual current highest epoch
98
108
  * Example:
99
109
  * proving epoch 11 - the broker will wipe all jobs for epochs 9 and lower
@@ -105,6 +115,8 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
105
115
 
106
116
  private started = false;
107
117
 
118
+ private debugReplayEnabled: boolean;
119
+
108
120
  public constructor(
109
121
  private database: ProvingBrokerDatabase,
110
122
  {
@@ -112,6 +124,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
112
124
  proverBrokerPollIntervalMs,
113
125
  proverBrokerJobMaxRetries,
114
126
  proverBrokerMaxEpochsToKeepResultsFor,
127
+ proverBrokerDebugReplayEnabled,
115
128
  }: Required<
116
129
  Pick<
117
130
  ProverBrokerConfig,
@@ -119,6 +132,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
119
132
  | 'proverBrokerPollIntervalMs'
120
133
  | 'proverBrokerJobMaxRetries'
121
134
  | 'proverBrokerMaxEpochsToKeepResultsFor'
135
+ | 'proverBrokerDebugReplayEnabled'
122
136
  >
123
137
  > = defaultProverBrokerConfig,
124
138
  client: TelemetryClient = getTelemetryClient(),
@@ -130,6 +144,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
130
144
  this.jobTimeoutMs = proverBrokerJobTimeoutMs!;
131
145
  this.maxRetries = proverBrokerJobMaxRetries!;
132
146
  this.maxEpochsToKeepResultsFor = proverBrokerMaxEpochsToKeepResultsFor!;
147
+ this.debugReplayEnabled = proverBrokerDebugReplayEnabled ?? false;
133
148
  }
134
149
 
135
150
  private measureQueueDepth: MonitorCallback = (type: ProvingRequestType) => {
@@ -184,7 +199,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
184
199
  this.logger.warn('ProvingBroker not started');
185
200
  return Promise.resolve();
186
201
  }
187
- await this.cleanupPromise.stop();
202
+ await tryStop(this.cleanupPromise);
188
203
  }
189
204
 
190
205
  public enqueueProvingJob(job: ProvingJob): Promise<ProvingJobStatus> {
@@ -232,6 +247,29 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
232
247
  return Promise.resolve(this.#reportProvingJobProgress(id, startedAt, filter));
233
248
  }
234
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
+
235
273
  async #enqueueProvingJob(job: ProvingJob): Promise<ProvingJobStatus> {
236
274
  // We return the job status at the start of this call
237
275
  const jobStatus = this.#getProvingJobStatus(job.id);
@@ -276,7 +314,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
276
314
  // notify listeners of the cancellation
277
315
  if (!this.resultsCache.has(id)) {
278
316
  this.logger.info(`Cancelling job id=${id}`, { provingJobId: id });
279
- await this.#reportProvingJobError(id, 'Aborted', false);
317
+ await this.#reportProvingJobError(id, 'Aborted', false, undefined, true);
280
318
  }
281
319
  }
282
320
 
@@ -287,6 +325,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
287
325
  this.resultsCache.delete(id);
288
326
  this.inProgress.delete(id);
289
327
  this.retries.delete(id);
328
+ this.enqueuedAt.delete(id);
290
329
  }
291
330
  }
292
331
 
@@ -313,7 +352,6 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
313
352
  return Promise.resolve(notifications.concat(completedJobs));
314
353
  }
315
354
 
316
- // eslint-disable-next-line require-await
317
355
  #getProvingJob(filter: ProvingJobFilter = { allowList: [] }): { job: ProvingJob; time: number } | undefined {
318
356
  const allowedProofs: ProvingRequestType[] =
319
357
  Array.isArray(filter.allowList) && filter.allowList.length > 0
@@ -340,6 +378,8 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
340
378
  const enqueuedAt = this.enqueuedAt.get(job.id);
341
379
  if (enqueuedAt) {
342
380
  this.instrumentation.recordJobWait(job.type, enqueuedAt);
381
+ // we can clear this flag now.
382
+ this.enqueuedAt.delete(job.id);
343
383
  }
344
384
 
345
385
  return { job, time };
@@ -355,6 +395,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
355
395
  err: string,
356
396
  retry = false,
357
397
  filter?: ProvingJobFilter,
398
+ aborted = false,
358
399
  ): Promise<GetProvingJobResponse | undefined> {
359
400
  const info = this.inProgress.get(id);
360
401
  const item = this.jobsCache.get(id);
@@ -415,7 +456,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
415
456
  this.promises.get(id)!.resolve(result);
416
457
  this.completedJobNotifications.push(id);
417
458
 
418
- this.instrumentation.incRejectedJobs(item.type);
459
+ if (aborted) {
460
+ this.instrumentation.incAbortedJobs(item.type);
461
+ } else {
462
+ this.instrumentation.incRejectedJobs(item.type);
463
+ }
419
464
  if (info) {
420
465
  const duration = this.msTimeSource() - info.startedAt;
421
466
  this.instrumentation.recordJobDuration(item.type, duration);
@@ -548,13 +593,12 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
548
593
  return this.#getProvingJob(filter);
549
594
  }
550
595
 
551
- @trackSpan('ProvingBroker.cleanupPass')
552
596
  private async cleanupPass() {
553
597
  this.cleanupStaleJobs();
554
598
  this.reEnqueueExpiredJobs();
555
599
  const oldestEpochToKeep = this.oldestEpochToKeep();
556
600
  if (oldestEpochToKeep > 0) {
557
- await this.database.deleteAllProvingJobsOlderThanEpoch(oldestEpochToKeep);
601
+ await this.database.deleteAllProvingJobsOlderThanEpoch(EpochNumber(oldestEpochToKeep));
558
602
  this.logger.trace(`Deleted all epochs older than ${oldestEpochToKeep}`);
559
603
  }
560
604
  }
@@ -571,7 +615,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
571
615
 
572
616
  if (jobsToClean.length > 0) {
573
617
  this.cleanUpProvingJobState(jobsToClean);
574
- this.logger.info(`Cleaned up jobs=${jobsToClean.length}`);
618
+ this.logger.verbose(`Cleaned up proving jobs=${jobsToClean.length}`);
575
619
  }
576
620
  }
577
621
 
@@ -671,17 +715,23 @@ function proofTypeComparator(a: ProvingRequestType, b: ProvingRequestType): -1 |
671
715
  * The aim is that this will speed up block proving as the closer we get to a block's root proof the more likely it
672
716
  * is to get picked up by agents
673
717
  */
674
- const PROOF_TYPES_IN_PRIORITY_ORDER: ProvingRequestType[] = [
718
+ export const PROOF_TYPES_IN_PRIORITY_ORDER: ProvingRequestType[] = [
719
+ ProvingRequestType.ROOT_ROLLUP,
720
+ ProvingRequestType.BLOCK_ROOT_FIRST_ROLLUP,
721
+ ProvingRequestType.BLOCK_ROOT_SINGLE_TX_FIRST_ROLLUP,
722
+ ProvingRequestType.BLOCK_ROOT_EMPTY_TX_FIRST_ROLLUP,
675
723
  ProvingRequestType.BLOCK_ROOT_ROLLUP,
676
- ProvingRequestType.SINGLE_TX_BLOCK_ROOT_ROLLUP,
724
+ ProvingRequestType.BLOCK_ROOT_SINGLE_TX_ROLLUP,
677
725
  ProvingRequestType.BLOCK_MERGE_ROLLUP,
678
- ProvingRequestType.ROOT_ROLLUP,
679
- ProvingRequestType.MERGE_ROLLUP,
680
- ProvingRequestType.PUBLIC_BASE_ROLLUP,
681
- ProvingRequestType.PRIVATE_BASE_ROLLUP,
726
+ ProvingRequestType.CHECKPOINT_ROOT_ROLLUP,
727
+ ProvingRequestType.CHECKPOINT_ROOT_SINGLE_BLOCK_ROLLUP,
728
+ ProvingRequestType.CHECKPOINT_MERGE_ROLLUP,
729
+ ProvingRequestType.CHECKPOINT_PADDING_ROLLUP,
730
+ ProvingRequestType.TX_MERGE_ROLLUP,
731
+ ProvingRequestType.PUBLIC_TX_BASE_ROLLUP,
732
+ ProvingRequestType.PRIVATE_TX_BASE_ROLLUP,
682
733
  ProvingRequestType.PUBLIC_VM,
683
- ProvingRequestType.TUBE_PROOF,
684
- ProvingRequestType.ROOT_PARITY,
685
- ProvingRequestType.BASE_PARITY,
686
- ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP,
734
+ ProvingRequestType.PUBLIC_CHONK_VERIFIER,
735
+ ProvingRequestType.PARITY_ROOT,
736
+ ProvingRequestType.PARITY_BASE,
687
737
  ];