@aztec/prover-client 0.65.2 → 0.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dest/block_builder/index.d.ts +6 -0
  2. package/dest/block_builder/index.d.ts.map +1 -0
  3. package/dest/block_builder/index.js +2 -0
  4. package/dest/block_builder/light.d.ts +32 -0
  5. package/dest/block_builder/light.d.ts.map +1 -0
  6. package/dest/block_builder/light.js +71 -0
  7. package/dest/index.d.ts +1 -2
  8. package/dest/index.d.ts.map +1 -1
  9. package/dest/index.js +2 -3
  10. package/dest/mocks/fixtures.d.ts +1 -2
  11. package/dest/mocks/fixtures.d.ts.map +1 -1
  12. package/dest/mocks/fixtures.js +3 -7
  13. package/dest/mocks/test_context.d.ts +28 -10
  14. package/dest/mocks/test_context.d.ts.map +1 -1
  15. package/dest/mocks/test_context.js +58 -21
  16. package/dest/orchestrator/epoch-proving-state.d.ts +5 -6
  17. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  18. package/dest/orchestrator/epoch-proving-state.js +10 -12
  19. package/dest/orchestrator/orchestrator.d.ts +8 -6
  20. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  21. package/dest/orchestrator/orchestrator.js +83 -72
  22. package/dest/orchestrator/tx-proving-state.d.ts +0 -1
  23. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  24. package/dest/orchestrator/tx-proving-state.js +2 -34
  25. package/dest/prover-client/factory.d.ts +6 -0
  26. package/dest/prover-client/factory.d.ts.map +1 -0
  27. package/dest/prover-client/factory.js +6 -0
  28. package/dest/prover-client/index.d.ts +3 -0
  29. package/dest/prover-client/index.d.ts.map +1 -0
  30. package/dest/prover-client/index.js +3 -0
  31. package/dest/{tx-prover/tx-prover.d.ts → prover-client/prover-client.d.ts} +8 -11
  32. package/dest/prover-client/prover-client.d.ts.map +1 -0
  33. package/dest/prover-client/prover-client.js +107 -0
  34. package/dest/proving_broker/factory.d.ts +2 -1
  35. package/dest/proving_broker/factory.d.ts.map +1 -1
  36. package/dest/proving_broker/factory.js +4 -4
  37. package/dest/proving_broker/proving_agent.d.ts +5 -0
  38. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  39. package/dest/proving_broker/proving_agent.js +13 -2
  40. package/dest/proving_broker/proving_agent_instrumentation.d.ts +8 -0
  41. package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +1 -0
  42. package/dest/proving_broker/proving_agent_instrumentation.js +16 -0
  43. package/dest/proving_broker/proving_broker.d.ts +6 -1
  44. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  45. package/dest/proving_broker/proving_broker.js +37 -4
  46. package/dest/proving_broker/proving_broker_database/persisted.d.ts +3 -1
  47. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  48. package/dest/proving_broker/proving_broker_database/persisted.js +10 -2
  49. package/dest/proving_broker/proving_broker_instrumentation.d.ts +25 -0
  50. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -0
  51. package/dest/proving_broker/proving_broker_instrumentation.js +91 -0
  52. package/dest/test/mock_prover.d.ts +1 -1
  53. package/dest/test/mock_prover.d.ts.map +1 -1
  54. package/dest/test/mock_prover.js +4 -3
  55. package/package.json +14 -13
  56. package/src/block_builder/index.ts +6 -0
  57. package/src/block_builder/light.ts +117 -0
  58. package/src/index.ts +1 -2
  59. package/src/mocks/fixtures.ts +2 -14
  60. package/src/mocks/test_context.ts +80 -24
  61. package/src/orchestrator/epoch-proving-state.ts +10 -13
  62. package/src/orchestrator/orchestrator.ts +97 -77
  63. package/src/orchestrator/tx-proving-state.ts +1 -56
  64. package/src/{tx-prover → prover-client}/factory.ts +4 -3
  65. package/src/prover-client/index.ts +2 -0
  66. package/src/{tx-prover/tx-prover.ts → prover-client/prover-client.ts} +23 -13
  67. package/src/proving_broker/factory.ts +7 -3
  68. package/src/proving_broker/proving_agent.ts +16 -1
  69. package/src/proving_broker/proving_agent_instrumentation.ts +21 -0
  70. package/src/proving_broker/proving_broker.ts +46 -3
  71. package/src/proving_broker/proving_broker_database/persisted.ts +17 -2
  72. package/src/proving_broker/proving_broker_instrumentation.ts +130 -0
  73. package/src/test/mock_prover.ts +3 -2
  74. package/dest/tx-prover/factory.d.ts +0 -6
  75. package/dest/tx-prover/factory.d.ts.map +0 -1
  76. package/dest/tx-prover/factory.js +0 -6
  77. package/dest/tx-prover/tx-prover.d.ts.map +0 -1
  78. package/dest/tx-prover/tx-prover.js +0 -110
@@ -1,18 +1,10 @@
1
- import {
2
- EncryptedNoteTxL2Logs,
3
- EncryptedTxL2Logs,
4
- type MerkleTreeId,
5
- type ProcessedTx,
6
- type ProofAndVerificationKey,
7
- UnencryptedTxL2Logs,
8
- } from '@aztec/circuit-types';
1
+ import { type MerkleTreeId, type ProcessedTx, type ProofAndVerificationKey } from '@aztec/circuit-types';
9
2
  import {
10
3
  type AVM_PROOF_LENGTH_IN_FIELDS,
11
4
  AVM_VK_INDEX,
12
5
  type AppendOnlyTreeSnapshot,
13
6
  AvmProofData,
14
7
  type BaseRollupHints,
15
- Fr,
16
8
  PrivateBaseRollupHints,
17
9
  PrivateBaseRollupInputs,
18
10
  PrivateTubeData,
@@ -112,53 +104,6 @@ export class TxProvingState {
112
104
  this.avm = avmProofAndVk;
113
105
  }
114
106
 
115
- public verifyStateOrReject(): string | undefined {
116
- const txEffect = this.processedTx.txEffect;
117
- const fromPrivate = this.processedTx.data;
118
-
119
- const noteEncryptedLogsHashes = [
120
- fromPrivate.forRollup?.end.noteEncryptedLogsHashes || [],
121
- fromPrivate.forPublic?.nonRevertibleAccumulatedData.noteEncryptedLogsHashes || [],
122
- fromPrivate.forPublic?.revertibleAccumulatedData.noteEncryptedLogsHashes || [],
123
- ].flat();
124
- const txNoteEncryptedLogsHash = EncryptedNoteTxL2Logs.hashNoteLogs(
125
- noteEncryptedLogsHashes.filter(log => !log.isEmpty()).map(log => log.value.toBuffer()),
126
- );
127
- if (!txNoteEncryptedLogsHash.equals(txEffect.noteEncryptedLogs.hash())) {
128
- return `Note encrypted logs hash mismatch: ${Fr.fromBuffer(txNoteEncryptedLogsHash)} === ${Fr.fromBuffer(
129
- txEffect.noteEncryptedLogs.hash(),
130
- )}`;
131
- }
132
-
133
- const encryptedLogsHashes = [
134
- fromPrivate.forRollup?.end.encryptedLogsHashes || [],
135
- fromPrivate.forPublic?.nonRevertibleAccumulatedData.encryptedLogsHashes || [],
136
- fromPrivate.forPublic?.revertibleAccumulatedData.encryptedLogsHashes || [],
137
- ].flat();
138
- const txEncryptedLogsHash = EncryptedTxL2Logs.hashSiloedLogs(
139
- encryptedLogsHashes.filter(log => !log.isEmpty()).map(log => log.getSiloedHash()),
140
- );
141
- if (!txEncryptedLogsHash.equals(txEffect.encryptedLogs.hash())) {
142
- // @todo This rejection messages is never seen. Never making it out to the logs
143
- return `Encrypted logs hash mismatch: ${Fr.fromBuffer(txEncryptedLogsHash)} === ${Fr.fromBuffer(
144
- txEffect.encryptedLogs.hash(),
145
- )}`;
146
- }
147
-
148
- const avmOutput = this.processedTx.avmProvingRequest?.inputs.output;
149
- const unencryptedLogsHashes = avmOutput
150
- ? avmOutput.accumulatedData.unencryptedLogsHashes
151
- : fromPrivate.forRollup!.end.unencryptedLogsHashes;
152
- const txUnencryptedLogsHash = UnencryptedTxL2Logs.hashSiloedLogs(
153
- unencryptedLogsHashes.filter(log => !log.isEmpty()).map(log => log.getSiloedHash()),
154
- );
155
- if (!txUnencryptedLogsHash.equals(txEffect.unencryptedLogs.hash())) {
156
- return `Unencrypted logs hash mismatch: ${Fr.fromBuffer(txUnencryptedLogsHash)} === ${Fr.fromBuffer(
157
- txEffect.unencryptedLogs.hash(),
158
- )}`;
159
- }
160
- }
161
-
162
107
  private getTubeVkData() {
163
108
  let vkIndex = TUBE_VK_INDEX;
164
109
  try {
@@ -1,14 +1,15 @@
1
- import { type ProvingJobBroker } from '@aztec/circuit-types';
1
+ import { type ForkMerkleTreeOperations, type ProvingJobBroker } from '@aztec/circuit-types';
2
2
  import { type TelemetryClient } from '@aztec/telemetry-client';
3
3
  import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
4
4
 
5
5
  import { type ProverClientConfig } from '../config.js';
6
- import { TxProver } from './tx-prover.js';
6
+ import { ProverClient } from './prover-client.js';
7
7
 
8
8
  export function createProverClient(
9
9
  config: ProverClientConfig,
10
+ worldState: ForkMerkleTreeOperations,
10
11
  broker: ProvingJobBroker,
11
12
  telemetry: TelemetryClient = new NoopTelemetryClient(),
12
13
  ) {
13
- return TxProver.new(config, broker, telemetry);
14
+ return ProverClient.new(config, worldState, broker, telemetry);
14
15
  }
@@ -0,0 +1,2 @@
1
+ export * from './factory.js';
2
+ export * from './prover-client.js';
@@ -3,7 +3,7 @@ import {
3
3
  type ActualProverConfig,
4
4
  type EpochProver,
5
5
  type EpochProverManager,
6
- type MerkleTreeWriteOperations,
6
+ type ForkMerkleTreeOperations,
7
7
  type ProverCache,
8
8
  type ProvingJobBroker,
9
9
  type ProvingJobConsumer,
@@ -25,11 +25,8 @@ import { InlineProofStore } from '../proving_broker/proof_store.js';
25
25
  import { InMemoryProverCache } from '../proving_broker/prover_cache/memory.js';
26
26
  import { ProvingAgent } from '../proving_broker/proving_agent.js';
27
27
 
28
- /**
29
- * A prover factory.
30
- * TODO(palla/prover-node): Rename this class
31
- */
32
- export class TxProver implements EpochProverManager {
28
+ /** Manages proving of epochs by orchestrating the proving of individual blocks relying on a pool of prover agents. */
29
+ export class ProverClient implements EpochProverManager {
33
30
  private running = false;
34
31
  private agents: ProvingAgent[] = [];
35
32
 
@@ -37,6 +34,7 @@ export class TxProver implements EpochProverManager {
37
34
 
38
35
  private constructor(
39
36
  private config: ProverClientConfig,
37
+ private worldState: ForkMerkleTreeOperations,
40
38
  private telemetry: TelemetryClient,
41
39
  private orchestratorClient: ProvingJobProducer,
42
40
  private agentClient?: ProvingJobConsumer,
@@ -47,9 +45,9 @@ export class TxProver implements EpochProverManager {
47
45
  this.cacheDir = this.config.cacheDir ? join(this.config.cacheDir, `tx_prover_${this.config.proverId}`) : undefined;
48
46
  }
49
47
 
50
- public createEpochProver(db: MerkleTreeWriteOperations, cache: ProverCache = new InMemoryProverCache()): EpochProver {
48
+ public createEpochProver(cache: ProverCache = new InMemoryProverCache()): EpochProver {
51
49
  return new ProvingOrchestrator(
52
- db,
50
+ this.worldState,
53
51
  new CachingBrokerFacade(this.orchestratorClient, cache),
54
52
  this.telemetry,
55
53
  this.config.proverId,
@@ -104,12 +102,16 @@ export class TxProver implements EpochProverManager {
104
102
  /**
105
103
  * Creates a new prover client and starts it
106
104
  * @param config - The prover configuration.
107
- * @param vks - The verification keys for the prover
108
- * @param worldStateSynchronizer - An instance of the world state
105
+ * @param worldState - An instance of the world state
109
106
  * @returns An instance of the prover, constructed and started.
110
107
  */
111
- public static async new(config: ProverClientConfig, broker: ProvingJobBroker, telemetry: TelemetryClient) {
112
- const prover = new TxProver(config, telemetry, broker, broker);
108
+ public static async new(
109
+ config: ProverClientConfig,
110
+ worldState: ForkMerkleTreeOperations,
111
+ broker: ProvingJobBroker,
112
+ telemetry: TelemetryClient,
113
+ ) {
114
+ const prover = new ProverClient(config, worldState, telemetry, broker, broker);
113
115
  await prover.start();
114
116
  return prover;
115
117
  }
@@ -135,7 +137,15 @@ export class TxProver implements EpochProverManager {
135
137
  const prover = await buildServerCircuitProver(this.config, this.telemetry);
136
138
  this.agents = times(
137
139
  this.config.proverAgentCount,
138
- () => new ProvingAgent(this.agentClient!, proofStore, prover, [], this.config.proverAgentPollIntervalMs),
140
+ () =>
141
+ new ProvingAgent(
142
+ this.agentClient!,
143
+ proofStore,
144
+ prover,
145
+ this.telemetry,
146
+ [],
147
+ this.config.proverAgentPollIntervalMs,
148
+ ),
139
149
  );
140
150
 
141
151
  await Promise.all(this.agents.map(agent => agent.start()));
@@ -1,16 +1,20 @@
1
1
  import { type ProverBrokerConfig } from '@aztec/circuit-types';
2
2
  import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
3
+ import { type TelemetryClient } from '@aztec/telemetry-client';
3
4
 
4
5
  import { ProvingBroker } from './proving_broker.js';
5
6
  import { InMemoryBrokerDatabase } from './proving_broker_database/memory.js';
6
7
  import { KVBrokerDatabase } from './proving_broker_database/persisted.js';
7
8
 
8
- export async function createAndStartProvingBroker(config: ProverBrokerConfig): Promise<ProvingBroker> {
9
+ export async function createAndStartProvingBroker(
10
+ config: ProverBrokerConfig,
11
+ client: TelemetryClient,
12
+ ): Promise<ProvingBroker> {
9
13
  const database = config.proverBrokerDataDirectory
10
- ? new KVBrokerDatabase(AztecLmdbStore.open(config.proverBrokerDataDirectory))
14
+ ? new KVBrokerDatabase(AztecLmdbStore.open(config.proverBrokerDataDirectory), client)
11
15
  : new InMemoryBrokerDatabase();
12
16
 
13
- const broker = new ProvingBroker(database, {
17
+ const broker = new ProvingBroker(database, client, {
14
18
  jobTimeoutMs: config.proverBrokerJobTimeoutMs,
15
19
  maxRetries: config.proverBrokerJobMaxRetries,
16
20
  timeoutIntervalMs: config.proverBrokerPollIntervalMs,
@@ -10,8 +10,11 @@ import {
10
10
  } from '@aztec/circuit-types';
11
11
  import { createDebugLogger } from '@aztec/foundation/log';
12
12
  import { RunningPromise } from '@aztec/foundation/running-promise';
13
+ import { Timer } from '@aztec/foundation/timer';
14
+ import { type TelemetryClient } from '@aztec/telemetry-client';
13
15
 
14
16
  import { type ProofStore } from './proof_store.js';
17
+ import { ProvingAgentInstrumentation } from './proving_agent_instrumentation.js';
15
18
  import { ProvingJobController, ProvingJobControllerStatus } from './proving_job_controller.js';
16
19
 
17
20
  /**
@@ -20,6 +23,8 @@ import { ProvingJobController, ProvingJobControllerStatus } from './proving_job_
20
23
  export class ProvingAgent {
21
24
  private currentJobController?: ProvingJobController;
22
25
  private runningPromise: RunningPromise;
26
+ private instrumentation: ProvingAgentInstrumentation;
27
+ private idleTimer: Timer | undefined;
23
28
 
24
29
  constructor(
25
30
  /** The source of proving jobs */
@@ -28,12 +33,15 @@ export class ProvingAgent {
28
33
  private proofStore: ProofStore,
29
34
  /** The prover implementation to defer jobs to */
30
35
  private circuitProver: ServerCircuitProver,
36
+ /** A telemetry client through which to emit metrics */
37
+ client: TelemetryClient,
31
38
  /** Optional list of allowed proof types to build */
32
39
  private proofAllowList: Array<ProvingRequestType> = [],
33
40
  /** How long to wait between jobs */
34
41
  private pollIntervalMs = 1000,
35
42
  private log = createDebugLogger('aztec:prover-client:proving-agent'),
36
43
  ) {
44
+ this.instrumentation = new ProvingAgentInstrumentation(client);
37
45
  this.runningPromise = new RunningPromise(this.safeWork, this.pollIntervalMs);
38
46
  }
39
47
 
@@ -46,6 +54,7 @@ export class ProvingAgent {
46
54
  }
47
55
 
48
56
  public start(): void {
57
+ this.idleTimer = new Timer();
49
58
  this.runningPromise.start();
50
59
  }
51
60
 
@@ -114,6 +123,11 @@ export class ProvingAgent {
114
123
  );
115
124
  }
116
125
 
126
+ if (this.idleTimer) {
127
+ this.instrumentation.recordIdleTime(this.idleTimer);
128
+ }
129
+ this.idleTimer = undefined;
130
+
117
131
  this.currentJobController.start();
118
132
  } catch (err) {
119
133
  this.log.error(`Error in ProvingAgent: ${String(err)}`);
@@ -126,9 +140,10 @@ export class ProvingAgent {
126
140
  err: Error | undefined,
127
141
  result: ProvingJobResultsMap[T] | undefined,
128
142
  ) => {
143
+ this.idleTimer = new Timer();
129
144
  if (err) {
130
145
  const retry = err.name === ProvingError.NAME ? (err as ProvingError).retry : false;
131
- this.log.info(`Job id=${jobId} type=${ProvingRequestType[type]} failed err=${err.message} retry=${retry}`);
146
+ this.log.error(`Job id=${jobId} type=${ProvingRequestType[type]} failed err=${err.message} retry=${retry}`, err);
132
147
  return this.broker.reportProvingJobError(jobId, err.message, retry);
133
148
  } else if (result) {
134
149
  const outputUri = await this.proofStore.saveProofOutput(jobId, type, result);
@@ -0,0 +1,21 @@
1
+ import { type Timer } from '@aztec/foundation/timer';
2
+ import { type Histogram, Metrics, type TelemetryClient, ValueType } from '@aztec/telemetry-client';
3
+
4
+ export class ProvingAgentInstrumentation {
5
+ private idleTime: Histogram;
6
+
7
+ constructor(client: TelemetryClient, name = 'ProvingAgent') {
8
+ const meter = client.getMeter(name);
9
+
10
+ this.idleTime = meter.createHistogram(Metrics.PROVING_AGENT_IDLE, {
11
+ description: 'Records how long an agent was idle',
12
+ unit: 'ms',
13
+ valueType: ValueType.INT,
14
+ });
15
+ }
16
+
17
+ recordIdleTime(msOrTimer: Timer | number) {
18
+ const duration = typeof msOrTimer === 'number' ? msOrTimer : Math.floor(msOrTimer.ms());
19
+ this.idleTime.record(duration);
20
+ }
21
+ }
@@ -12,10 +12,13 @@ import {
12
12
  import { createDebugLogger } from '@aztec/foundation/log';
13
13
  import { type PromiseWithResolvers, RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
14
14
  import { PriorityMemoryQueue } from '@aztec/foundation/queue';
15
+ import { Timer } from '@aztec/foundation/timer';
16
+ import { type TelemetryClient } from '@aztec/telemetry-client';
15
17
 
16
18
  import assert from 'assert';
17
19
 
18
20
  import { type ProvingBrokerDatabase } from './proving_broker_database.js';
21
+ import { type MonitorCallback, ProvingBrokerInstrumentation } from './proving_broker_instrumentation.js';
19
22
 
20
23
  type InProgressMetadata = {
21
24
  id: ProvingJobId;
@@ -58,6 +61,9 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
58
61
  // as above, but for results
59
62
  private resultsCache = new Map<ProvingJobId, ProvingJobSettledResult>();
60
63
 
64
+ // tracks when each job was enqueued
65
+ private enqueuedAt = new Map<ProvingJobId, Timer>();
66
+
61
67
  // keeps track of which jobs are currently being processed
62
68
  // in the event of a crash this information is lost, but that's ok
63
69
  // the next time the broker starts it will recreate jobsCache and still
@@ -75,18 +81,37 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
75
81
  private jobTimeoutMs: number;
76
82
  private maxRetries: number;
77
83
 
84
+ private instrumentation: ProvingBrokerInstrumentation;
85
+
78
86
  public constructor(
79
87
  private database: ProvingBrokerDatabase,
80
- { jobTimeoutMs = 30, timeoutIntervalMs = 10, maxRetries = 3 }: ProofRequestBrokerConfig = {},
88
+ client: TelemetryClient,
89
+ { jobTimeoutMs = 30_000, timeoutIntervalMs = 10_000, maxRetries = 3 }: ProofRequestBrokerConfig = {},
81
90
  private logger = createDebugLogger('aztec:prover-client:proving-broker'),
82
91
  ) {
92
+ this.instrumentation = new ProvingBrokerInstrumentation(client);
83
93
  this.timeoutPromise = new RunningPromise(this.timeoutCheck, timeoutIntervalMs);
84
94
  this.jobTimeoutMs = jobTimeoutMs;
85
95
  this.maxRetries = maxRetries;
86
96
  }
87
97
 
88
- // eslint-disable-next-line require-await
89
- public async start(): Promise<void> {
98
+ private measureQueueDepth: MonitorCallback = (type: ProvingRequestType) => {
99
+ return this.queues[type].length();
100
+ };
101
+
102
+ private countActiveJobs: MonitorCallback = (type: ProvingRequestType) => {
103
+ let count = 0;
104
+ for (const { id } of this.inProgress.values()) {
105
+ const job = this.jobsCache.get(id);
106
+ if (job?.type === type) {
107
+ count++;
108
+ }
109
+ }
110
+
111
+ return count;
112
+ };
113
+
114
+ public start(): Promise<void> {
90
115
  for (const [item, result] of this.database.allProvingJobs()) {
91
116
  this.logger.info(`Restoring proving job id=${item.id} settled=${!!result}`);
92
117
 
@@ -103,6 +128,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
103
128
  }
104
129
 
105
130
  this.timeoutPromise.start();
131
+
132
+ this.instrumentation.monitorQueueDepth(this.measureQueueDepth);
133
+ this.instrumentation.monitorActiveJobs(this.countActiveJobs);
134
+
135
+ return Promise.resolve();
106
136
  }
107
137
 
108
138
  public stop(): Promise<void> {
@@ -187,6 +217,10 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
187
217
  startedAt: time,
188
218
  lastUpdatedAt: time,
189
219
  });
220
+ const enqueuedAt = this.enqueuedAt.get(job.id);
221
+ if (enqueuedAt) {
222
+ this.instrumentation.recordJobWait(job.type, enqueuedAt);
223
+ }
190
224
 
191
225
  return { job, time };
192
226
  }
@@ -216,6 +250,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
216
250
  this.logger.info(`Retrying proving job id=${id} type=${ProvingRequestType[item.type]} retry=${retries + 1}`);
217
251
  this.retries.set(id, retries + 1);
218
252
  this.enqueueJobInternal(item);
253
+ this.instrumentation.incRetriedJobs(item.type);
219
254
  return;
220
255
  }
221
256
 
@@ -228,6 +263,11 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
228
263
  const result: ProvingJobSettledResult = { status: 'rejected', reason: String(err) };
229
264
  this.resultsCache.set(id, result);
230
265
  this.promises.get(id)!.resolve(result);
266
+ this.instrumentation.incRejectedJobs(item.type);
267
+ if (info) {
268
+ const duration = this.timeSource() - info.startedAt;
269
+ this.instrumentation.recordJobDuration(item.type, duration * 1000);
270
+ }
231
271
  }
232
272
 
233
273
  reportProvingJobProgress(
@@ -303,6 +343,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
303
343
  const result: ProvingJobSettledResult = { status: 'fulfilled', value };
304
344
  this.resultsCache.set(id, result);
305
345
  this.promises.get(id)!.resolve(result);
346
+ this.instrumentation.incResolvedJobs(item.type);
306
347
  }
307
348
 
308
349
  private timeoutCheck = () => {
@@ -320,6 +361,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
320
361
  this.logger.warn(`Proving job id=${id} timed out. Adding it back to the queue.`);
321
362
  this.inProgress.delete(id);
322
363
  this.enqueueJobInternal(item);
364
+ this.instrumentation.incTimedOutJobs(item.type);
323
365
  }
324
366
  }
325
367
  };
@@ -329,6 +371,7 @@ export class ProvingBroker implements ProvingJobProducer, ProvingJobConsumer {
329
371
  this.promises.set(job.id, promiseWithResolvers());
330
372
  }
331
373
  this.queues[job.type].put(job);
374
+ this.enqueuedAt.set(job.id, new Timer());
332
375
  this.logger.debug(`Enqueued new proving job id=${job.id}`);
333
376
  }
334
377
  }
@@ -1,14 +1,29 @@
1
1
  import { type ProofUri, ProvingJob, type ProvingJobId, ProvingJobSettledResult } from '@aztec/circuit-types';
2
2
  import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
3
3
  import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
4
+ import { LmdbMetrics, Metrics, type TelemetryClient } from '@aztec/telemetry-client';
4
5
 
5
6
  import { type ProvingBrokerDatabase } from '../proving_broker_database.js';
6
7
 
7
8
  export class KVBrokerDatabase implements ProvingBrokerDatabase {
8
9
  private jobs: AztecMap<ProvingJobId, string>;
9
10
  private jobResults: AztecMap<ProvingJobId, string>;
10
-
11
- constructor(private store: AztecKVStore) {
11
+ private metrics: LmdbMetrics;
12
+
13
+ constructor(private store: AztecKVStore, client: TelemetryClient) {
14
+ this.metrics = new LmdbMetrics(
15
+ client.getMeter('KVBrokerDatabase'),
16
+ {
17
+ name: Metrics.PROVING_QUEUE_DB_MAP_SIZE,
18
+ description: 'Database map size for the proving broker',
19
+ },
20
+ {
21
+ name: Metrics.PROVING_QUEUE_DB_USED_SIZE,
22
+ description: 'Database used size for the proving broker',
23
+ },
24
+ { name: Metrics.PROVING_QUEUE_DB_NUM_ITEMS, description: 'Number of items in the broker database' },
25
+ () => store.estimateSize(),
26
+ );
12
27
  this.jobs = store.openMap('proving_jobs');
13
28
  this.jobResults = store.openMap('proving_job_results');
14
29
  }
@@ -0,0 +1,130 @@
1
+ import { ProvingRequestType } from '@aztec/circuit-types';
2
+ import { type Timer } from '@aztec/foundation/timer';
3
+ import {
4
+ Attributes,
5
+ type Histogram,
6
+ Metrics,
7
+ type ObservableGauge,
8
+ type ObservableResult,
9
+ type TelemetryClient,
10
+ type UpDownCounter,
11
+ ValueType,
12
+ millisecondBuckets,
13
+ } from '@aztec/telemetry-client';
14
+
15
+ export type MonitorCallback = (proofType: ProvingRequestType) => number;
16
+
17
+ export class ProvingBrokerInstrumentation {
18
+ private queueSize: ObservableGauge;
19
+ private activeJobs: ObservableGauge;
20
+ private resolvedJobs: UpDownCounter;
21
+ private rejectedJobs: UpDownCounter;
22
+ private timedOutJobs: UpDownCounter;
23
+ private jobWait: Histogram;
24
+ private jobDuration: Histogram;
25
+ private retriedJobs: UpDownCounter;
26
+
27
+ constructor(client: TelemetryClient, name = 'ProvingBroker') {
28
+ const meter = client.getMeter(name);
29
+
30
+ this.queueSize = meter.createObservableGauge(Metrics.PROVING_QUEUE_SIZE, {
31
+ valueType: ValueType.INT,
32
+ });
33
+
34
+ this.activeJobs = meter.createObservableGauge(Metrics.PROVING_QUEUE_ACTIVE_JOBS, {
35
+ valueType: ValueType.INT,
36
+ });
37
+
38
+ this.resolvedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_RESOLVED_JOBS, {
39
+ valueType: ValueType.INT,
40
+ });
41
+
42
+ this.rejectedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_REJECTED_JOBS, {
43
+ valueType: ValueType.INT,
44
+ });
45
+
46
+ this.retriedJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_RETRIED_JOBS, {
47
+ valueType: ValueType.INT,
48
+ });
49
+
50
+ this.timedOutJobs = meter.createUpDownCounter(Metrics.PROVING_QUEUE_TIMED_OUT_JOBS, {
51
+ valueType: ValueType.INT,
52
+ });
53
+
54
+ this.jobWait = meter.createHistogram(Metrics.PROVING_QUEUE_JOB_WAIT, {
55
+ description: 'Records how long a job sits in the queue',
56
+ unit: 'ms',
57
+ valueType: ValueType.INT,
58
+ advice: {
59
+ explicitBucketBoundaries: millisecondBuckets(1), // 10ms -> ~327s
60
+ },
61
+ });
62
+
63
+ this.jobDuration = meter.createHistogram(Metrics.PROVING_QUEUE_JOB_DURATION, {
64
+ description: 'Records how long a job takes to complete',
65
+ unit: 'ms',
66
+ valueType: ValueType.INT,
67
+ advice: {
68
+ explicitBucketBoundaries: millisecondBuckets(1), // 10ms -> ~327s
69
+ },
70
+ });
71
+ }
72
+
73
+ monitorQueueDepth(fn: MonitorCallback) {
74
+ this.queueSize.addCallback(obs => this.observe(obs, fn));
75
+ }
76
+
77
+ monitorActiveJobs(fn: MonitorCallback) {
78
+ this.activeJobs.addCallback(obs => this.observe(obs, fn));
79
+ }
80
+
81
+ incResolvedJobs(proofType: ProvingRequestType) {
82
+ this.resolvedJobs.add(1, {
83
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
84
+ });
85
+ }
86
+
87
+ incRejectedJobs(proofType: ProvingRequestType) {
88
+ this.rejectedJobs.add(1, {
89
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
90
+ });
91
+ }
92
+
93
+ incRetriedJobs(proofType: ProvingRequestType) {
94
+ this.retriedJobs.add(1, {
95
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
96
+ });
97
+ }
98
+
99
+ incTimedOutJobs(proofType: ProvingRequestType) {
100
+ this.timedOutJobs.add(1, {
101
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
102
+ });
103
+ }
104
+
105
+ recordJobWait(proofType: ProvingRequestType, msOrTimer: Timer | number) {
106
+ const duration = typeof msOrTimer === 'number' ? msOrTimer : Math.floor(msOrTimer.ms());
107
+ this.jobWait.record(duration, {
108
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
109
+ });
110
+ }
111
+
112
+ recordJobDuration(proofType: ProvingRequestType, msOrTimer: Timer | number) {
113
+ const duration = typeof msOrTimer === 'number' ? msOrTimer : Math.floor(msOrTimer.ms());
114
+ this.jobDuration.record(duration, {
115
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
116
+ });
117
+ }
118
+
119
+ private observe(obs: ObservableResult, fn: MonitorCallback) {
120
+ for (const proofType of Object.values(ProvingRequestType)) {
121
+ // a type predicate for TypeScript to recognize that we're only iterating over enum values
122
+ if (typeof proofType !== 'number') {
123
+ continue;
124
+ }
125
+ obs.observe(fn(proofType), {
126
+ [Attributes.PROVING_JOB_TYPE]: ProvingRequestType[proofType],
127
+ });
128
+ }
129
+ }
130
+ }
@@ -43,6 +43,7 @@ import {
43
43
  makeRootRollupPublicInputs,
44
44
  } from '@aztec/circuits.js/testing';
45
45
  import { times } from '@aztec/foundation/collection';
46
+ import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
46
47
 
47
48
  import { InlineProofStore, type ProofStore } from '../proving_broker/proof_store.js';
48
49
  import { ProvingAgent } from '../proving_broker/proving_agent.js';
@@ -50,7 +51,7 @@ import { ProvingBroker } from '../proving_broker/proving_broker.js';
50
51
  import { InMemoryBrokerDatabase } from '../proving_broker/proving_broker_database/memory.js';
51
52
 
52
53
  export class TestBroker implements ProvingJobProducer {
53
- private broker = new ProvingBroker(new InMemoryBrokerDatabase());
54
+ private broker = new ProvingBroker(new InMemoryBrokerDatabase(), new NoopTelemetryClient());
54
55
  private agents: ProvingAgent[];
55
56
 
56
57
  constructor(
@@ -58,7 +59,7 @@ export class TestBroker implements ProvingJobProducer {
58
59
  prover: ServerCircuitProver,
59
60
  private proofStore: ProofStore = new InlineProofStore(),
60
61
  ) {
61
- this.agents = times(agentCount, () => new ProvingAgent(this.broker, proofStore, prover));
62
+ this.agents = times(agentCount, () => new ProvingAgent(this.broker, proofStore, prover, new NoopTelemetryClient()));
62
63
  }
63
64
 
64
65
  public async start() {
@@ -1,6 +0,0 @@
1
- import { type ProvingJobBroker } from '@aztec/circuit-types';
2
- import { type TelemetryClient } from '@aztec/telemetry-client';
3
- import { type ProverClientConfig } from '../config.js';
4
- import { TxProver } from './tx-prover.js';
5
- export declare function createProverClient(config: ProverClientConfig, broker: ProvingJobBroker, telemetry?: TelemetryClient): Promise<TxProver>;
6
- //# sourceMappingURL=factory.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/tx-prover/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,gBAAgB,EACxB,SAAS,GAAE,eAA2C,qBAGvD"}
@@ -1,6 +0,0 @@
1
- import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
2
- import { TxProver } from './tx-prover.js';
3
- export function createProverClient(config, broker, telemetry = new NoopTelemetryClient()) {
4
- return TxProver.new(config, broker, telemetry);
5
- }
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eC1wcm92ZXIvZmFjdG9yeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUduRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFMUMsTUFBTSxVQUFVLGtCQUFrQixDQUNoQyxNQUEwQixFQUMxQixNQUF3QixFQUN4QixZQUE2QixJQUFJLG1CQUFtQixFQUFFO0lBRXRELE9BQU8sUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBQ2pELENBQUMifQ==
@@ -1 +0,0 @@
1
- {"version":3,"file":"tx-prover.d.ts","sourceRoot":"","sources":["../../src/tx-prover/tx-prover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAA2C,MAAM,kBAAkB,CAAC;AAC3G,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EAEvB,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAIxC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOvD;;;GAGG;AACH,qBAAa,QAAS,YAAW,kBAAkB;IAO/C,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,WAAW,CAAC;IACpB,OAAO,CAAC,GAAG;IAVb,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAsB;IAEpC,OAAO,CAAC,QAAQ,CAAC,CAAS;IAE1B,OAAO;IAYA,iBAAiB,CAAC,EAAE,EAAE,yBAAyB,EAAE,KAAK,GAAE,WAAuC,GAAG,WAAW;IAS7G,WAAW,IAAI,EAAE;IAIlB,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5E;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IASnC;;OAEG;IACU,IAAI;IAQjB;;;;;;OAMG;WACiB,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe;IAMjG,mBAAmB,IAAI,kBAAkB;YAQlC,oBAAoB;YAmBpB,UAAU;CAGzB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,kBAAkB,GAAG,UAAU,GAAG,QAAQ,EAClD,SAAS,EAAE,eAAe,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAU9B"}