@aztec-labs/prover-client 6.0.0-nightly.20260829

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 (170) hide show
  1. package/README.md +1 -0
  2. package/dest/config.d.ts +17 -0
  3. package/dest/config.d.ts.map +1 -0
  4. package/dest/config.js +63 -0
  5. package/dest/index.d.ts +4 -0
  6. package/dest/index.d.ts.map +1 -0
  7. package/dest/index.js +2 -0
  8. package/dest/light/index.d.ts +2 -0
  9. package/dest/light/index.d.ts.map +1 -0
  10. package/dest/light/index.js +1 -0
  11. package/dest/light/lightweight_checkpoint_builder.d.ts +58 -0
  12. package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -0
  13. package/dest/light/lightweight_checkpoint_builder.js +243 -0
  14. package/dest/mocks/fixtures.d.ts +20 -0
  15. package/dest/mocks/fixtures.d.ts.map +1 -0
  16. package/dest/mocks/fixtures.js +96 -0
  17. package/dest/mocks/test_context.d.ts +93 -0
  18. package/dest/mocks/test_context.d.ts.map +1 -0
  19. package/dest/mocks/test_context.js +354 -0
  20. package/dest/orchestrator/block-building-helpers.d.ts +67 -0
  21. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -0
  22. package/dest/orchestrator/block-building-helpers.js +274 -0
  23. package/dest/orchestrator/block-proving-state.d.ts +107 -0
  24. package/dest/orchestrator/block-proving-state.d.ts.map +1 -0
  25. package/dest/orchestrator/block-proving-state.js +339 -0
  26. package/dest/orchestrator/checkpoint-proving-state.d.ts +67 -0
  27. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -0
  28. package/dest/orchestrator/checkpoint-proving-state.js +175 -0
  29. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts +169 -0
  30. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts.map +1 -0
  31. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.js +1047 -0
  32. package/dest/orchestrator/chonk-cache.d.ts +39 -0
  33. package/dest/orchestrator/chonk-cache.d.ts.map +1 -0
  34. package/dest/orchestrator/chonk-cache.js +80 -0
  35. package/dest/orchestrator/index.d.ts +4 -0
  36. package/dest/orchestrator/index.d.ts.map +1 -0
  37. package/dest/orchestrator/index.js +3 -0
  38. package/dest/orchestrator/orchestrator_metrics.d.ts +8 -0
  39. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -0
  40. package/dest/orchestrator/orchestrator_metrics.js +13 -0
  41. package/dest/orchestrator/proving-scheduler.d.ts +81 -0
  42. package/dest/orchestrator/proving-scheduler.d.ts.map +1 -0
  43. package/dest/orchestrator/proving-scheduler.js +120 -0
  44. package/dest/orchestrator/top-tree-orchestrator.d.ts +89 -0
  45. package/dest/orchestrator/top-tree-orchestrator.d.ts.map +1 -0
  46. package/dest/orchestrator/top-tree-orchestrator.js +233 -0
  47. package/dest/orchestrator/top-tree-proving-state.d.ts +61 -0
  48. package/dest/orchestrator/top-tree-proving-state.d.ts.map +1 -0
  49. package/dest/orchestrator/top-tree-proving-state.js +185 -0
  50. package/dest/orchestrator/tx-proving-state.d.ts +37 -0
  51. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -0
  52. package/dest/orchestrator/tx-proving-state.js +77 -0
  53. package/dest/prover-client/factory.d.ts +6 -0
  54. package/dest/prover-client/factory.d.ts.map +1 -0
  55. package/dest/prover-client/factory.js +5 -0
  56. package/dest/prover-client/index.d.ts +3 -0
  57. package/dest/prover-client/index.d.ts.map +1 -0
  58. package/dest/prover-client/index.js +2 -0
  59. package/dest/prover-client/prover-client.d.ts +99 -0
  60. package/dest/prover-client/prover-client.d.ts.map +1 -0
  61. package/dest/prover-client/prover-client.js +163 -0
  62. package/dest/proving_broker/broker_prover_facade.d.ts +52 -0
  63. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -0
  64. package/dest/proving_broker/broker_prover_facade.js +360 -0
  65. package/dest/proving_broker/config.d.ts +40 -0
  66. package/dest/proving_broker/config.d.ts.map +1 -0
  67. package/dest/proving_broker/config.js +138 -0
  68. package/dest/proving_broker/factory.d.ts +5 -0
  69. package/dest/proving_broker/factory.d.ts.map +1 -0
  70. package/dest/proving_broker/factory.js +13 -0
  71. package/dest/proving_broker/fixtures.d.ts +6 -0
  72. package/dest/proving_broker/fixtures.d.ts.map +1 -0
  73. package/dest/proving_broker/fixtures.js +13 -0
  74. package/dest/proving_broker/index.d.ts +11 -0
  75. package/dest/proving_broker/index.d.ts.map +1 -0
  76. package/dest/proving_broker/index.js +10 -0
  77. package/dest/proving_broker/proof_store/factory.d.ts +3 -0
  78. package/dest/proving_broker/proof_store/factory.d.ts.map +1 -0
  79. package/dest/proving_broker/proof_store/factory.js +13 -0
  80. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts +18 -0
  81. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts.map +1 -0
  82. package/dest/proving_broker/proof_store/file_store_proof_store.js +60 -0
  83. package/dest/proving_broker/proof_store/index.d.ts +5 -0
  84. package/dest/proving_broker/proof_store/index.d.ts.map +1 -0
  85. package/dest/proving_broker/proof_store/index.js +4 -0
  86. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +15 -0
  87. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -0
  88. package/dest/proving_broker/proof_store/inline_proof_store.js +41 -0
  89. package/dest/proving_broker/proof_store/proof_store.d.ts +36 -0
  90. package/dest/proving_broker/proof_store/proof_store.d.ts.map +1 -0
  91. package/dest/proving_broker/proof_store/proof_store.js +3 -0
  92. package/dest/proving_broker/proving_agent.d.ts +42 -0
  93. package/dest/proving_broker/proving_agent.d.ts.map +1 -0
  94. package/dest/proving_broker/proving_agent.js +155 -0
  95. package/dest/proving_broker/proving_broker.d.ts +77 -0
  96. package/dest/proving_broker/proving_broker.d.ts.map +1 -0
  97. package/dest/proving_broker/proving_broker.js +780 -0
  98. package/dest/proving_broker/proving_broker_database/memory.d.ts +20 -0
  99. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -0
  100. package/dest/proving_broker/proving_broker_database/memory.js +67 -0
  101. package/dest/proving_broker/proving_broker_database/persisted.d.ts +40 -0
  102. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -0
  103. package/dest/proving_broker/proving_broker_database/persisted.js +623 -0
  104. package/dest/proving_broker/proving_broker_database.d.ts +66 -0
  105. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -0
  106. package/dest/proving_broker/proving_broker_database.js +3 -0
  107. package/dest/proving_broker/proving_broker_instrumentation.d.ts +31 -0
  108. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -0
  109. package/dest/proving_broker/proving_broker_instrumentation.js +97 -0
  110. package/dest/proving_broker/proving_job_controller.d.ts +34 -0
  111. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -0
  112. package/dest/proving_broker/proving_job_controller.js +184 -0
  113. package/dest/proving_broker/rpc.d.ts +38 -0
  114. package/dest/proving_broker/rpc.d.ts.map +1 -0
  115. package/dest/proving_broker/rpc.js +138 -0
  116. package/dest/test/epoch_settlement.d.ts +36 -0
  117. package/dest/test/epoch_settlement.d.ts.map +1 -0
  118. package/dest/test/epoch_settlement.js +52 -0
  119. package/dest/test/index.d.ts +2 -0
  120. package/dest/test/index.d.ts.map +1 -0
  121. package/dest/test/index.js +1 -0
  122. package/dest/test/mock_proof_store.d.ts +9 -0
  123. package/dest/test/mock_proof_store.d.ts.map +1 -0
  124. package/dest/test/mock_proof_store.js +10 -0
  125. package/dest/test/mock_prover.d.ts +38 -0
  126. package/dest/test/mock_prover.d.ts.map +1 -0
  127. package/dest/test/mock_prover.js +91 -0
  128. package/package.json +113 -0
  129. package/src/config.ts +87 -0
  130. package/src/index.ts +4 -0
  131. package/src/light/index.ts +1 -0
  132. package/src/light/lightweight_checkpoint_builder.ts +342 -0
  133. package/src/mocks/fixtures.ts +120 -0
  134. package/src/mocks/test_context.ts +477 -0
  135. package/src/orchestrator/block-building-helpers.ts +486 -0
  136. package/src/orchestrator/block-proving-state.ts +457 -0
  137. package/src/orchestrator/checkpoint-proving-state.ts +247 -0
  138. package/src/orchestrator/checkpoint-sub-tree-orchestrator.ts +1010 -0
  139. package/src/orchestrator/chonk-cache.ts +99 -0
  140. package/src/orchestrator/index.ts +12 -0
  141. package/src/orchestrator/orchestrator_metrics.ts +18 -0
  142. package/src/orchestrator/proving-scheduler.ts +160 -0
  143. package/src/orchestrator/top-tree-orchestrator.ts +394 -0
  144. package/src/orchestrator/top-tree-proving-state.ts +219 -0
  145. package/src/orchestrator/tx-proving-state.ts +121 -0
  146. package/src/prover-client/factory.ts +18 -0
  147. package/src/prover-client/index.ts +2 -0
  148. package/src/prover-client/prover-client.ts +286 -0
  149. package/src/proving_broker/broker_prover_facade.ts +626 -0
  150. package/src/proving_broker/config.ts +178 -0
  151. package/src/proving_broker/factory.ts +19 -0
  152. package/src/proving_broker/fixtures.ts +20 -0
  153. package/src/proving_broker/index.ts +10 -0
  154. package/src/proving_broker/proof_store/factory.ts +20 -0
  155. package/src/proving_broker/proof_store/file_store_proof_store.ts +78 -0
  156. package/src/proving_broker/proof_store/index.ts +4 -0
  157. package/src/proving_broker/proof_store/inline_proof_store.ts +63 -0
  158. package/src/proving_broker/proof_store/proof_store.ts +54 -0
  159. package/src/proving_broker/proving_agent.ts +210 -0
  160. package/src/proving_broker/proving_broker.ts +888 -0
  161. package/src/proving_broker/proving_broker_database/memory.ts +78 -0
  162. package/src/proving_broker/proving_broker_database/persisted.ts +296 -0
  163. package/src/proving_broker/proving_broker_database.ts +75 -0
  164. package/src/proving_broker/proving_broker_instrumentation.ts +133 -0
  165. package/src/proving_broker/proving_job_controller.ts +199 -0
  166. package/src/proving_broker/rpc.ts +131 -0
  167. package/src/test/epoch_settlement.ts +82 -0
  168. package/src/test/index.ts +1 -0
  169. package/src/test/mock_proof_store.ts +14 -0
  170. package/src/test/mock_prover.ts +304 -0
@@ -0,0 +1,178 @@
1
+ import { type L1ReaderConfig, l1ReaderConfigMappings } from '@aztec-labs/ethereum/l1-reader';
2
+ import {
3
+ type ConfigMappingsType,
4
+ booleanConfigHelper,
5
+ getDefaultConfig,
6
+ numberConfigHelper,
7
+ optionalNumberConfigHelper,
8
+ } from '@aztec-labs/foundation/config';
9
+ import { pickConfigMappings } from '@aztec-labs/foundation/config';
10
+ import { type ChainConfig, chainConfigMappings } from '@aztec-labs/stdlib/config';
11
+ import { type DataStoreConfig, dataConfigMappings } from '@aztec-labs/stdlib/kv-store';
12
+ import { ProvingRequestType } from '@aztec-labs/stdlib/proofs';
13
+ import { z } from 'zod';
14
+
15
+ export const ProverBrokerConfig = z.object({
16
+ /** If starting a prover broker locally, the max number of retries per proving job */
17
+ proverBrokerJobMaxRetries: z.number().int().nonnegative(),
18
+ /** If starting a prover broker locally, the time after which a job times out and gets assigned to a different agent */
19
+ proverBrokerJobTimeoutMs: z.number().int().nonnegative(),
20
+ /** If starting a prover broker locally, the interval the broker checks for timed out jobs */
21
+ proverBrokerPollIntervalMs: z.number().int().nonnegative(),
22
+ /** If starting a prover broker locally, the directory to store broker data */
23
+ dataDirectory: z.string().optional(),
24
+ /** The size of the data store map */
25
+ dataStoreMapSizeKb: z.number().int().nonnegative(),
26
+ /** The size of the prover broker's database. Will override the dataStoreMapSizeKb if set. */
27
+ proverBrokerStoreMapSizeKb: z.number().int().nonnegative().optional(),
28
+ /** The prover broker may batch jobs together before writing to the database */
29
+ proverBrokerBatchSize: z.number().int().nonnegative(),
30
+ /** How often the job batches get flushed */
31
+ proverBrokerBatchIntervalMs: z.number().int().nonnegative(),
32
+ /** The maximum number of epochs to keep results for */
33
+ proverBrokerMaxEpochsToKeepResultsFor: z.number().int().nonnegative(),
34
+ /** Enable debug replay mode for replaying proving jobs from stored inputs */
35
+ proverBrokerDebugReplayEnabled: z.boolean(),
36
+ });
37
+
38
+ export type ProverBrokerConfig = z.infer<typeof ProverBrokerConfig> &
39
+ Pick<DataStoreConfig, 'dataStoreMapSizeKb' | 'dataDirectory'> &
40
+ L1ReaderConfig &
41
+ Pick<ChainConfig, 'rollupVersion'>;
42
+
43
+ export const proverBrokerConfigMappings: ConfigMappingsType<ProverBrokerConfig> = {
44
+ proverBrokerJobTimeoutMs: {
45
+ env: 'PROVER_BROKER_JOB_TIMEOUT_MS',
46
+ description: 'Jobs are retried if not kept alive for this long',
47
+ ...numberConfigHelper(30_000),
48
+ },
49
+ proverBrokerPollIntervalMs: {
50
+ env: 'PROVER_BROKER_POLL_INTERVAL_MS',
51
+ description: 'The interval to check job health status',
52
+ ...numberConfigHelper(1_000),
53
+ },
54
+ proverBrokerJobMaxRetries: {
55
+ env: 'PROVER_BROKER_JOB_MAX_RETRIES',
56
+ description: 'If starting a prover broker locally, the max number of retries per proving job',
57
+ ...numberConfigHelper(3),
58
+ },
59
+ proverBrokerBatchSize: {
60
+ env: 'PROVER_BROKER_BATCH_SIZE',
61
+ description: 'The prover broker writes jobs to disk in batches',
62
+ ...numberConfigHelper(100),
63
+ },
64
+ proverBrokerBatchIntervalMs: {
65
+ env: 'PROVER_BROKER_BATCH_INTERVAL_MS',
66
+ description: 'How often to flush batches to disk',
67
+ ...numberConfigHelper(50),
68
+ },
69
+ proverBrokerMaxEpochsToKeepResultsFor: {
70
+ env: 'PROVER_BROKER_MAX_EPOCHS_TO_KEEP_RESULTS_FOR',
71
+ description: 'The maximum number of epochs to keep results for',
72
+ ...numberConfigHelper(1),
73
+ },
74
+ proverBrokerStoreMapSizeKb: {
75
+ env: 'PROVER_BROKER_STORE_MAP_SIZE_KB',
76
+ ...optionalNumberConfigHelper(),
77
+ description: "The size of the prover broker's database. Will override the dataStoreMapSizeKb if set.",
78
+ },
79
+ proverBrokerDebugReplayEnabled: {
80
+ env: 'PROVER_BROKER_DEBUG_REPLAY_ENABLED',
81
+ description: 'Enable debug replay mode for replaying proving jobs from stored inputs',
82
+ ...booleanConfigHelper(false),
83
+ },
84
+ ...dataConfigMappings,
85
+ ...l1ReaderConfigMappings,
86
+ ...pickConfigMappings(chainConfigMappings, ['rollupVersion']),
87
+ };
88
+
89
+ export const defaultProverBrokerConfig: ProverBrokerConfig = getDefaultConfig(proverBrokerConfigMappings);
90
+
91
+ export const ProverAgentConfig = z.object({
92
+ /** The number of prover agents to start */
93
+ proverAgentCount: z.number(),
94
+ /** The types of proofs the prover agent can generate */
95
+ proverAgentProofTypes: z.array(z.nativeEnum(ProvingRequestType)),
96
+ /** How often the prover agents poll for jobs */
97
+ proverAgentPollIntervalMs: z.number(),
98
+ /** The URL where this agent takes jobs from */
99
+ proverBrokerUrl: z.string().optional(),
100
+ /** Whether to construct real proofs */
101
+ realProofs: z.boolean(),
102
+ /** The type of artificial delay to introduce */
103
+ proverTestDelayType: z.enum(['fixed', 'realistic']),
104
+ /** If using fixed delay, the time each operation takes. */
105
+ proverTestDelayMs: z.number(),
106
+ /** If using realistic delays, what percentage of realistic times to apply. */
107
+ proverTestDelayFactor: z.number(),
108
+ /** The delay (ms) to inject during fake proof verification */
109
+ proverTestVerificationDelayMs: z.number().optional(),
110
+ /** Whether to abort pending proving jobs when the orchestrator is cancelled */
111
+ cancelJobsOnStop: z.boolean(),
112
+ /** Where to store proving results. Must be accessible to both prover node and agents. If not set will inline-encode the parameters */
113
+ proofStore: z.string().optional(),
114
+ });
115
+
116
+ export type ProverAgentConfig = z.infer<typeof ProverAgentConfig>;
117
+
118
+ export const proverAgentConfigMappings: ConfigMappingsType<ProverAgentConfig> = {
119
+ proverAgentCount: {
120
+ env: 'PROVER_AGENT_COUNT',
121
+ description: 'Whether this prover has a local prover agent',
122
+ ...numberConfigHelper(1),
123
+ },
124
+ proverAgentPollIntervalMs: {
125
+ env: 'PROVER_AGENT_POLL_INTERVAL_MS',
126
+ description: 'The interval agents poll for jobs at',
127
+ ...numberConfigHelper(1000),
128
+ },
129
+ proverAgentProofTypes: {
130
+ env: 'PROVER_AGENT_PROOF_TYPES',
131
+ description: 'The types of proofs the prover agent can generate',
132
+ parseEnv: (val: string) =>
133
+ val
134
+ .split(',')
135
+ .map(v => ProvingRequestType[v as any])
136
+ .filter(v => typeof v === 'number'),
137
+ },
138
+ proverBrokerUrl: {
139
+ env: 'PROVER_BROKER_HOST',
140
+ description: 'The URL where this agent takes jobs from',
141
+ },
142
+ realProofs: {
143
+ env: 'PROVER_REAL_PROOFS',
144
+ description: 'Whether to construct real proofs',
145
+ ...booleanConfigHelper(true),
146
+ },
147
+ proverTestDelayType: {
148
+ env: 'PROVER_TEST_DELAY_TYPE',
149
+ description: 'The type of artificial delay to introduce',
150
+ defaultValue: 'fixed',
151
+ },
152
+ proverTestDelayMs: {
153
+ env: 'PROVER_TEST_DELAY_MS',
154
+ description: 'Artificial delay to introduce to all operations to the test prover.',
155
+ ...numberConfigHelper(0),
156
+ },
157
+ proverTestDelayFactor: {
158
+ env: 'PROVER_TEST_DELAY_FACTOR',
159
+ description: 'If using realistic delays, what percentage of realistic times to apply.',
160
+ ...numberConfigHelper(1),
161
+ },
162
+ proverTestVerificationDelayMs: {
163
+ env: 'PROVER_TEST_VERIFICATION_DELAY_MS',
164
+ description: 'The delay (ms) to inject during fake proof verification',
165
+ ...numberConfigHelper(10),
166
+ },
167
+ cancelJobsOnStop: {
168
+ env: 'PROVER_CANCEL_JOBS_ON_STOP',
169
+ description:
170
+ 'Whether to abort pending proving jobs when the orchestrator is cancelled. ' +
171
+ 'When false (default), jobs remain in the broker queue and can be reused on restart/reorg.',
172
+ ...booleanConfigHelper(false),
173
+ },
174
+ proofStore: {
175
+ env: 'PROVER_PROOF_STORE',
176
+ description: 'Optional proof input store for the prover',
177
+ },
178
+ };
@@ -0,0 +1,19 @@
1
+ import type { TelemetryClient } from '@aztec-labs/telemetry-client';
2
+
3
+ import type { ProverBrokerConfig } from './config.js';
4
+ import { ProvingBroker } from './proving_broker.js';
5
+ import { InMemoryBrokerDatabase } from './proving_broker_database/memory.js';
6
+ import { KVBrokerDatabase } from './proving_broker_database/persisted.js';
7
+
8
+ export async function createAndStartProvingBroker(
9
+ _config: ProverBrokerConfig,
10
+ client: TelemetryClient,
11
+ ): Promise<ProvingBroker> {
12
+ const config = { ..._config, dataStoreMapSizeKb: _config.proverBrokerStoreMapSizeKb ?? _config.dataStoreMapSizeKb };
13
+ const database = config.dataDirectory ? await KVBrokerDatabase.new(config, client) : new InMemoryBrokerDatabase();
14
+
15
+ const broker = new ProvingBroker(database, config, client);
16
+
17
+ await broker.start();
18
+ return broker;
19
+ }
@@ -0,0 +1,20 @@
1
+ import { EpochNumber } from '@aztec-labs/foundation/branded-types';
2
+ import { randomBytes } from '@aztec-labs/foundation/crypto/random';
3
+ import { type ProofUri, type ProvingJobId, makeProvingJobId } from '@aztec-labs/stdlib/interfaces/server';
4
+ import { ProvingRequestType } from '@aztec-labs/stdlib/proofs';
5
+
6
+ export function makeRandomProvingJobId(epochNumber?: EpochNumber): ProvingJobId {
7
+ return makeProvingJobId(
8
+ epochNumber ?? EpochNumber(1),
9
+ ProvingRequestType.INBOX_PARITY,
10
+ randomBytes(8).toString('hex'),
11
+ );
12
+ }
13
+
14
+ export function makeInputsUri(): ProofUri {
15
+ return randomBytes(8).toString('hex') as ProofUri;
16
+ }
17
+
18
+ export function makeOutputsUri(): ProofUri {
19
+ return randomBytes(8).toString('hex') as ProofUri;
20
+ }
@@ -0,0 +1,10 @@
1
+ export * from './proving_agent.js';
2
+ export * from './proving_broker.js';
3
+ export * from './rpc.js';
4
+ export * from './proving_broker_database.js';
5
+ export * from './proving_broker_database/memory.js';
6
+ export * from './proving_broker_database/persisted.js';
7
+ export * from './proof_store/index.js';
8
+ export * from './factory.js';
9
+ export * from './config.js';
10
+ export { BrokerCircuitProverFacade } from './broker_prover_facade.js';
@@ -0,0 +1,20 @@
1
+ import { createLogger } from '@aztec-labs/foundation/log';
2
+ import { createFileStore } from '@aztec-labs/stdlib/file-store';
3
+
4
+ import { FileStoreProofStore } from './file_store_proof_store.js';
5
+ import { InlineProofStore } from './inline_proof_store.js';
6
+ import type { ProofStore } from './proof_store.js';
7
+
8
+ export async function createProofStore(
9
+ config: string | undefined,
10
+ logger = createLogger('prover-client:proof-store'),
11
+ ): Promise<ProofStore> {
12
+ if (!config) {
13
+ logger.info('Creating inline proof store');
14
+ return new InlineProofStore();
15
+ }
16
+
17
+ const fileStore = await createFileStore(config, logger);
18
+ logger.info(`Creating file store proof store at ${config}`);
19
+ return new FileStoreProofStore(fileStore);
20
+ }
@@ -0,0 +1,78 @@
1
+ import { jsonParseWithSchema, jsonStringify } from '@aztec-labs/foundation/json-rpc';
2
+ import type { FileStore } from '@aztec-labs/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-labs/stdlib/interfaces/server';
12
+ import { ProvingRequestType } from '@aztec-labs/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
+ }
@@ -0,0 +1,4 @@
1
+ export * from './proof_store.js';
2
+ export * from './inline_proof_store.js';
3
+ export * from './factory.js';
4
+ export * from './file_store_proof_store.js';
@@ -0,0 +1,63 @@
1
+ import { jsonParseWithSchema, jsonStringify } from '@aztec-labs/foundation/json-rpc';
2
+ import {
3
+ type ProofUri,
4
+ type ProvingJobId,
5
+ ProvingJobInputs,
6
+ type ProvingJobInputsMap,
7
+ ProvingJobResult,
8
+ type ProvingJobResultsMap,
9
+ } from '@aztec-labs/stdlib/interfaces/server';
10
+ import type { ProvingRequestType } from '@aztec-labs/stdlib/proofs';
11
+ import type { ZodFor } from '@aztec-labs/stdlib/schemas';
12
+
13
+ import type { ProofStore } from './proof_store.js';
14
+
15
+ // use an ASCII encoded data uri https://datatracker.ietf.org/doc/html/rfc2397#section-2
16
+ // we do this to avoid double encoding to base64 (since the inputs already serialize to a base64 string)
17
+ const PREFIX = 'data:application/json;charset=utf-8';
18
+ const SEPARATOR = ',';
19
+
20
+ /**
21
+ * An implementation of a proof input/output database that stores data inline in the URI.
22
+ */
23
+ export class InlineProofStore implements ProofStore {
24
+ saveProofInput<T extends ProvingRequestType>(
25
+ _id: ProvingJobId,
26
+ type: T,
27
+ inputs: ProvingJobInputsMap[T],
28
+ ): Promise<ProofUri> {
29
+ const jobInputs = { type, inputs } as ProvingJobInputs;
30
+ return Promise.resolve(this.encode(jobInputs));
31
+ }
32
+
33
+ saveProofOutput<T extends ProvingRequestType>(
34
+ _id: ProvingJobId,
35
+ type: T,
36
+ result: ProvingJobResultsMap[T],
37
+ ): Promise<ProofUri> {
38
+ const jobResult = { type, result } as ProvingJobResult;
39
+ return Promise.resolve(this.encode(jobResult));
40
+ }
41
+
42
+ getProofInput(uri: ProofUri): Promise<ProvingJobInputs> {
43
+ return Promise.resolve(this.decode(uri, ProvingJobInputs));
44
+ }
45
+
46
+ getProofOutput(uri: ProofUri): Promise<ProvingJobResult> {
47
+ return Promise.resolve(this.decode(uri, ProvingJobResult));
48
+ }
49
+
50
+ private encode(obj: object): ProofUri {
51
+ const encoded = encodeURIComponent(jsonStringify(obj));
52
+ return (PREFIX + SEPARATOR + encoded) as ProofUri;
53
+ }
54
+
55
+ private decode<T>(uri: ProofUri, schema: ZodFor<T>): T {
56
+ const [prefix, data] = uri.split(SEPARATOR);
57
+ if (prefix !== PREFIX) {
58
+ throw new Error('Invalid proof input URI: ' + prefix);
59
+ }
60
+
61
+ return jsonParseWithSchema(decodeURIComponent(data), schema);
62
+ }
63
+ }
@@ -0,0 +1,54 @@
1
+ import type {
2
+ ProofUri,
3
+ ProvingJobId,
4
+ ProvingJobInputs,
5
+ ProvingJobInputsMap,
6
+ ProvingJobResult,
7
+ ProvingJobResultsMap,
8
+ } from '@aztec-labs/stdlib/interfaces/server';
9
+ import type { ProvingRequestType } from '@aztec-labs/stdlib/proofs';
10
+
11
+ /**
12
+ * A database for storing proof inputs and outputs.
13
+ */
14
+ export interface ProofStore {
15
+ /**
16
+ * Save a proof input to the database.
17
+ * @param jobId - The ID of the job the proof input is associated with.
18
+ * @param type - The type of the proving request.
19
+ * @param inputs - The proof input to save.
20
+ * @returns The URI of the saved proof input.
21
+ */
22
+ saveProofInput<T extends ProvingRequestType>(
23
+ jobId: ProvingJobId,
24
+ type: T,
25
+ inputs: ProvingJobInputsMap[T],
26
+ ): Promise<ProofUri>;
27
+
28
+ /**
29
+ * Save a proof output to the database.
30
+ * @param jobId - The ID of the job the proof input is associated with.
31
+ * @param type - The type of the proving request.
32
+ * @param result - The proof output to save.
33
+ * @returns The URI of the saved proof output.
34
+ */
35
+ saveProofOutput<T extends ProvingRequestType>(
36
+ id: ProvingJobId,
37
+ type: T,
38
+ result: ProvingJobResultsMap[T],
39
+ ): Promise<ProofUri>;
40
+
41
+ /**
42
+ * Retrieve a proof input from the database.
43
+ * @param uri - The URI of the proof input to retrieve.
44
+ * @returns The proof input.
45
+ */
46
+ getProofInput(uri: ProofUri): Promise<ProvingJobInputs>;
47
+
48
+ /**
49
+ * Retrieve a proof output from the database.
50
+ * @param uri - The URI of the proof output to retrieve.
51
+ * @returns The proof output.
52
+ */
53
+ getProofOutput(uri: ProofUri): Promise<ProvingJobResult>;
54
+ }
@@ -0,0 +1,210 @@
1
+ import { AbortError } from '@aztec-labs/foundation/error';
2
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec-labs/foundation/log';
3
+ import { RunningPromise } from '@aztec-labs/foundation/running-promise';
4
+ import { truncate } from '@aztec-labs/foundation/string';
5
+ import { ProvingError } from '@aztec-labs/stdlib/errors';
6
+ import type {
7
+ GetProvingJobResponse,
8
+ ProverAgentStatus,
9
+ ProvingJobConsumer,
10
+ ProvingJobId,
11
+ ProvingJobInputs,
12
+ ProvingJobResultsMap,
13
+ ServerCircuitProver,
14
+ } from '@aztec-labs/stdlib/interfaces/server';
15
+ import { ProvingRequestType } from '@aztec-labs/stdlib/proofs';
16
+
17
+ import type { ProofStore } from './proof_store/index.js';
18
+ import { ProvingJobController, ProvingJobControllerStatus } from './proving_job_controller.js';
19
+
20
+ /**
21
+ * A helper class that encapsulates a circuit prover and connects it to a job source.
22
+ */
23
+ export class ProvingAgent {
24
+ private currentJobController?: ProvingJobController;
25
+ private runningPromise: RunningPromise;
26
+ private log: Logger;
27
+
28
+ constructor(
29
+ /** The source of proving jobs */
30
+ private broker: ProvingJobConsumer,
31
+ /** Database holding proof inputs and outputs */
32
+ private proofStore: ProofStore,
33
+ /** The prover implementation to defer jobs to */
34
+ private circuitProver: ServerCircuitProver,
35
+ /** Optional list of allowed proof types to build */
36
+ private proofAllowList: Array<ProvingRequestType> = [],
37
+ /** How long to wait between jobs */
38
+ private pollIntervalMs = 1000,
39
+ bindings?: LoggerBindings,
40
+ ) {
41
+ this.log = createLogger('prover-client:proving-agent', bindings);
42
+ this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.pollIntervalMs);
43
+ }
44
+
45
+ public setCircuitProver(circuitProver: ServerCircuitProver): void {
46
+ this.circuitProver = circuitProver;
47
+ }
48
+
49
+ public isRunning(): boolean {
50
+ return this.runningPromise?.isRunning() ?? false;
51
+ }
52
+
53
+ public start(): void {
54
+ this.runningPromise.start();
55
+ }
56
+
57
+ public async stop(): Promise<void> {
58
+ this.currentJobController?.abort();
59
+ await this.runningPromise.stop();
60
+ }
61
+
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
+
75
+ private async work() {
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
+ }
119
+ } else {
120
+ maybeJob = await this.broker.getProvingJob({ allowList: this.proofAllowList });
121
+ }
122
+
123
+ if (maybeJob) {
124
+ await this.startJob(maybeJob);
125
+ }
126
+ }
127
+
128
+ private async startJob({ job, time: startedAt }: GetProvingJobResponse): Promise<void> {
129
+ let abortedProofJobId: string | undefined;
130
+ let abortedProofName: string | undefined;
131
+
132
+ if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.RUNNING) {
133
+ abortedProofJobId = this.currentJobController.getJobId();
134
+ abortedProofName = this.currentJobController.getProofTypeName();
135
+ this.currentJobController?.abort();
136
+ }
137
+
138
+ let inputs: ProvingJobInputs;
139
+ try {
140
+ inputs = await this.proofStore.getProofInput(job.inputsUri);
141
+ } catch {
142
+ const maybeJob = await this.broker.reportProvingJobError(job.id, 'Failed to load proof inputs', true, {
143
+ allowList: this.proofAllowList,
144
+ });
145
+
146
+ if (maybeJob) {
147
+ return this.startJob(maybeJob);
148
+ }
149
+
150
+ return;
151
+ }
152
+
153
+ this.currentJobController = new ProvingJobController(
154
+ job.id,
155
+ inputs,
156
+ job.epochNumber,
157
+ startedAt,
158
+ this.circuitProver,
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(),
165
+ );
166
+
167
+ if (abortedProofJobId) {
168
+ this.log.info(
169
+ `Aborting job id=${abortedProofJobId} type=${abortedProofName} to start new job id=${this.currentJobController.getJobId()} type=${this.currentJobController.getProofTypeName()} inputsUri=${truncate(
170
+ job.inputsUri,
171
+ )}`,
172
+ );
173
+ } else {
174
+ this.log.info(
175
+ `Starting job id=${this.currentJobController.getJobId()} type=${this.currentJobController.getProofTypeName()} inputsUri=${truncate(
176
+ job.inputsUri,
177
+ )}`,
178
+ );
179
+ }
180
+
181
+ this.currentJobController.start();
182
+ }
183
+
184
+ private async reportResult<T extends ProvingRequestType>(
185
+ jobId: ProvingJobId,
186
+ type: T,
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 {
203
+ const outputUri = await this.proofStore.saveProofOutput(jobId, type, result);
204
+ this.log.info(`Job id=${jobId} type=${ProvingRequestType[type]} completed outputUri=${truncate(outputUri)}`);
205
+ maybeJob = await this.broker.reportProvingJobSuccess(jobId, outputUri, { allowList: this.proofAllowList });
206
+ }
207
+
208
+ return maybeJob;
209
+ }
210
+ }