@aztec/prover-client 0.0.0-test.0 → 0.0.1-commit.0208eb9

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 +47 -0
  9. package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -0
  10. package/dest/light/lightweight_checkpoint_builder.js +200 -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 +149 -87
  17. package/dest/orchestrator/block-building-helpers.d.ts +37 -30
  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 +70 -48
  21. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  22. package/dest/orchestrator/block-proving-state.js +282 -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 +177 -73
  29. package/dest/orchestrator/index.d.ts +1 -1
  30. package/dest/orchestrator/orchestrator.d.ts +53 -35
  31. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  32. package/dest/orchestrator/orchestrator.js +855 -302
  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 +7 -7
  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 +62 -43
  51. package/dest/proving_broker/config.d.ts +31 -10
  52. package/dest/proving_broker/config.d.ts.map +1 -1
  53. package/dest/proving_broker/config.js +41 -7
  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 +69 -34
  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 +1 -1
  88. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
  89. package/dest/proving_broker/proving_broker_instrumentation.js +15 -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 +33 -31
  103. package/src/config.ts +25 -9
  104. package/src/light/index.ts +1 -0
  105. package/src/light/lightweight_checkpoint_builder.ts +289 -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 +325 -231
  110. package/src/orchestrator/checkpoint-proving-state.ts +349 -0
  111. package/src/orchestrator/epoch-proving-state.ts +237 -111
  112. package/src/orchestrator/orchestrator.ts +653 -343
  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 +47 -37
  117. package/src/prover-client/server-epoch-prover.ts +40 -22
  118. package/src/proving_broker/broker_prover_facade.ts +212 -131
  119. package/src/proving_broker/config.ts +47 -7
  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 +87 -42
  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 +14 -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);
@@ -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 };
@@ -548,13 +588,12 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
548
588
  return this.#getProvingJob(filter);
549
589
  }
550
590
 
551
- @trackSpan('ProvingBroker.cleanupPass')
552
591
  private async cleanupPass() {
553
592
  this.cleanupStaleJobs();
554
593
  this.reEnqueueExpiredJobs();
555
594
  const oldestEpochToKeep = this.oldestEpochToKeep();
556
595
  if (oldestEpochToKeep > 0) {
557
- await this.database.deleteAllProvingJobsOlderThanEpoch(oldestEpochToKeep);
596
+ await this.database.deleteAllProvingJobsOlderThanEpoch(EpochNumber(oldestEpochToKeep));
558
597
  this.logger.trace(`Deleted all epochs older than ${oldestEpochToKeep}`);
559
598
  }
560
599
  }
@@ -571,7 +610,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer, Tr
571
610
 
572
611
  if (jobsToClean.length > 0) {
573
612
  this.cleanUpProvingJobState(jobsToClean);
574
- this.logger.info(`Cleaned up jobs=${jobsToClean.length}`);
613
+ this.logger.verbose(`Cleaned up proving jobs=${jobsToClean.length}`);
575
614
  }
576
615
  }
577
616
 
@@ -671,17 +710,23 @@ function proofTypeComparator(a: ProvingRequestType, b: ProvingRequestType): -1 |
671
710
  * 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
711
  * is to get picked up by agents
673
712
  */
674
- const PROOF_TYPES_IN_PRIORITY_ORDER: ProvingRequestType[] = [
713
+ export const PROOF_TYPES_IN_PRIORITY_ORDER: ProvingRequestType[] = [
714
+ ProvingRequestType.ROOT_ROLLUP,
715
+ ProvingRequestType.BLOCK_ROOT_FIRST_ROLLUP,
716
+ ProvingRequestType.BLOCK_ROOT_SINGLE_TX_FIRST_ROLLUP,
717
+ ProvingRequestType.BLOCK_ROOT_EMPTY_TX_FIRST_ROLLUP,
675
718
  ProvingRequestType.BLOCK_ROOT_ROLLUP,
676
- ProvingRequestType.SINGLE_TX_BLOCK_ROOT_ROLLUP,
719
+ ProvingRequestType.BLOCK_ROOT_SINGLE_TX_ROLLUP,
677
720
  ProvingRequestType.BLOCK_MERGE_ROLLUP,
678
- ProvingRequestType.ROOT_ROLLUP,
679
- ProvingRequestType.MERGE_ROLLUP,
680
- ProvingRequestType.PUBLIC_BASE_ROLLUP,
681
- ProvingRequestType.PRIVATE_BASE_ROLLUP,
721
+ ProvingRequestType.CHECKPOINT_ROOT_ROLLUP,
722
+ ProvingRequestType.CHECKPOINT_ROOT_SINGLE_BLOCK_ROLLUP,
723
+ ProvingRequestType.CHECKPOINT_MERGE_ROLLUP,
724
+ ProvingRequestType.CHECKPOINT_PADDING_ROLLUP,
725
+ ProvingRequestType.TX_MERGE_ROLLUP,
726
+ ProvingRequestType.PUBLIC_TX_BASE_ROLLUP,
727
+ ProvingRequestType.PRIVATE_TX_BASE_ROLLUP,
682
728
  ProvingRequestType.PUBLIC_VM,
683
- ProvingRequestType.TUBE_PROOF,
684
- ProvingRequestType.ROOT_PARITY,
685
- ProvingRequestType.BASE_PARITY,
686
- ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP,
729
+ ProvingRequestType.PUBLIC_CHONK_VERIFIER,
730
+ ProvingRequestType.PARITY_ROOT,
731
+ ProvingRequestType.PARITY_BASE,
687
732
  ];
@@ -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),
@@ -52,7 +53,7 @@ export class InMemoryBrokerDatabase implements ProvingBrokerDatabase {
52
53
  }
53
54
 
54
55
  async *allProvingJobs(): AsyncIterableIterator<[ProvingJob, ProvingJobSettledResult | undefined]> {
55
- for await (const item of this.jobs.values()) {
56
+ for (const item of this.jobs.values()) {
56
57
  yield [item, this.results.get(item.id)] as const;
57
58
  }
58
59
  }