@aztec/bb-prover 0.43.0 → 0.44.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.
@@ -0,0 +1,149 @@
1
+ import { type CircuitName } from '@aztec/circuit-types/stats';
2
+ import { type Timer } from '@aztec/foundation/timer';
3
+ import {
4
+ Attributes,
5
+ type Gauge,
6
+ type Histogram,
7
+ Metrics,
8
+ type TelemetryClient,
9
+ type Tracer,
10
+ ValueType,
11
+ } from '@aztec/telemetry-client';
12
+
13
+ /**
14
+ * Instrumentation class for Prover implementations.
15
+ */
16
+ export class ProverInstrumentation {
17
+ private simulationDuration: Histogram;
18
+ private witGenDuration: Gauge;
19
+ private provingDuration: Gauge;
20
+
21
+ private witGenInputSize: Gauge;
22
+ private witGenOutputSize: Gauge;
23
+
24
+ private proofSize: Gauge;
25
+ private circuitSize: Gauge;
26
+ private circuitPublicInputCount: Gauge;
27
+
28
+ public readonly tracer: Tracer;
29
+
30
+ constructor(telemetry: TelemetryClient, name: string) {
31
+ this.tracer = telemetry.getTracer(name);
32
+ const meter = telemetry.getMeter(name);
33
+
34
+ this.simulationDuration = meter.createHistogram(Metrics.CIRCUIT_SIMULATION_DURATION, {
35
+ description: 'Records how long it takes to simulate a circuit',
36
+ unit: 's',
37
+ valueType: ValueType.DOUBLE,
38
+ advice: {
39
+ explicitBucketBoundaries: [0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60],
40
+ },
41
+ });
42
+
43
+ this.witGenDuration = meter.createGauge(Metrics.CIRCUIT_WITNESS_GEN_DURATION, {
44
+ description: 'Records how long it takes to generate the partial witness for a circuit',
45
+ unit: 's',
46
+ valueType: ValueType.DOUBLE,
47
+ });
48
+
49
+ // ideally this would be a histogram, but proving takes a long time on the server
50
+ // and they don't happen that often so Prometheus & Grafana have a hard time handling it
51
+ this.provingDuration = meter.createGauge(Metrics.CIRCUIT_PROVING_DURATION, {
52
+ unit: 's',
53
+ description: 'Records how long it takes to prove a circuit',
54
+ valueType: ValueType.DOUBLE,
55
+ });
56
+
57
+ this.witGenInputSize = meter.createGauge(Metrics.CIRCUIT_WITNESS_GEN_INPUT_SIZE, {
58
+ unit: 'By',
59
+ description: 'Records the size of the input to the witness generation',
60
+ valueType: ValueType.INT,
61
+ });
62
+
63
+ this.witGenOutputSize = meter.createGauge(Metrics.CIRCUIT_WITNESS_GEN_OUTPUT_SIZE, {
64
+ unit: 'By',
65
+ description: 'Records the size of the output of the witness generation',
66
+ valueType: ValueType.INT,
67
+ });
68
+
69
+ this.proofSize = meter.createGauge(Metrics.CIRCUIT_PROVING_PROOF_SIZE, {
70
+ unit: 'By',
71
+ description: 'Records the size of the proof generated for a circuit',
72
+ valueType: ValueType.INT,
73
+ });
74
+
75
+ this.circuitPublicInputCount = meter.createGauge(Metrics.CIRCUIT_PUBLIC_INPUTS_COUNT, {
76
+ description: 'Records the number of public inputs in a circuit',
77
+ valueType: ValueType.INT,
78
+ });
79
+
80
+ this.circuitSize = meter.createGauge(Metrics.CIRCUIT_SIZE, {
81
+ description: 'Records the size of the circuit in gates',
82
+ valueType: ValueType.INT,
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Records the duration of a circuit operation.
88
+ * @param metric - The metric to record
89
+ * @param circuitName - The name of the circuit
90
+ * @param timerOrS - The duration
91
+ */
92
+ recordDuration(
93
+ metric: 'simulationDuration' | 'witGenDuration' | 'provingDuration',
94
+ circuitName: CircuitName,
95
+ timerOrS: Timer | number,
96
+ ) {
97
+ const s = typeof timerOrS === 'number' ? timerOrS : timerOrS.s();
98
+ this[metric].record(s, {
99
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: circuitName,
100
+ [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Records the duration of an AVM circuit operation.
106
+ * @param metric - The metric to record
107
+ * @param appCircuitName - The name of the function circuit (should be a `contract:function` string)
108
+ * @param timerOrS - The duration
109
+ */
110
+ recordAvmDuration(metric: 'witGenDuration' | 'provingDuration', appCircuitName: string, timerOrS: Timer | number) {
111
+ const s = typeof timerOrS === 'number' ? timerOrS : timerOrS.s();
112
+ this[metric].record(s, {
113
+ [Attributes.APP_CIRCUIT_NAME]: appCircuitName,
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Records the size of a circuit operation.
119
+ * @param metric - Records the size of a circuit operation.
120
+ * @param circuitName - The name of the circuit
121
+ * @param size - The size
122
+ */
123
+ recordSize(
124
+ metric: 'witGenInputSize' | 'witGenOutputSize' | 'proofSize' | 'circuitSize' | 'circuitPublicInputCount',
125
+ circuitName: CircuitName,
126
+ size: number,
127
+ ) {
128
+ this[metric].record(Math.ceil(size), {
129
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: circuitName,
130
+ [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
131
+ });
132
+ }
133
+
134
+ /**
135
+ * Records the size of an AVM circuit operation.
136
+ * @param metric - The metric to record
137
+ * @param appCircuitName - The name of the function circuit (should be a `contract:function` string)
138
+ * @param size - The size
139
+ */
140
+ recordAvmSize(
141
+ metric: 'witGenInputSize' | 'witGenOutputSize' | 'proofSize' | 'circuitSize' | 'circuitPublicInputCount',
142
+ appCircuitName: string,
143
+ size: number,
144
+ ) {
145
+ this[metric].record(Math.ceil(size), {
146
+ [Attributes.APP_CIRCUIT_NAME]: appCircuitName,
147
+ });
148
+ }
149
+ }
@@ -42,6 +42,7 @@ import { type NoirCompiledCircuit } from '@aztec/types/noir';
42
42
  import { serializeWitness } from '@noir-lang/noirc_abi';
43
43
  import { type WitnessMap } from '@noir-lang/types';
44
44
  import * as fs from 'fs/promises';
45
+ import { join } from 'path';
45
46
 
46
47
  import {
47
48
  BB_RESULT,
@@ -175,7 +176,7 @@ export class BBNativeProofCreator implements ProofCreator {
175
176
  throw new Error(errorMessage);
176
177
  }
177
178
 
178
- this.log.info(`Successfully verified ${circuitType} proof in ${result.duration} ms`);
179
+ this.log.info(`Successfully verified ${circuitType} proof in ${Math.ceil(result.durationMs)} ms`);
179
180
  }
180
181
 
181
182
  private async verifyProofFromKey(
@@ -304,13 +305,14 @@ export class BBNativeProofCreator implements ProofCreator {
304
305
  }> {
305
306
  const compressedBincodedWitness = serializeWitness(partialWitness);
306
307
 
307
- const inputsWitnessFile = `${directory}/witness.gz`;
308
+ const inputsWitnessFile = join(directory, 'witness.gz');
308
309
 
309
310
  await fs.writeFile(inputsWitnessFile, compressedBincodedWitness);
310
311
 
311
312
  this.log.debug(`Written ${inputsWitnessFile}`);
312
313
 
313
- this.log.info(`Proving ${circuitType} circuit...`);
314
+ const dbgCircuitName = appCircuitName ? `(${appCircuitName})` : '';
315
+ this.log.info(`Proving ${circuitType}${dbgCircuitName} circuit...`);
314
316
 
315
317
  const timer = new Timer();
316
318
 
@@ -324,13 +326,11 @@ export class BBNativeProofCreator implements ProofCreator {
324
326
  );
325
327
 
326
328
  if (provingResult.status === BB_RESULT.FAILURE) {
327
- this.log.error(`Failed to generate proof for ${circuitType}: ${provingResult.reason}`);
329
+ this.log.error(`Failed to generate proof for ${circuitType}${dbgCircuitName}: ${provingResult.reason}`);
328
330
  throw new Error(provingResult.reason);
329
331
  }
330
332
 
331
- this.log.info(
332
- `Generated ${circuitType === 'App' ? appCircuitName : circuitType} circuit proof in ${timer.ms()} ms`,
333
- );
333
+ this.log.info(`Generated ${circuitType}${dbgCircuitName} circuit proof in ${Math.ceil(timer.ms())} ms`);
334
334
 
335
335
  if (circuitType === 'App') {
336
336
  const vkData = await extractVkData(directory);
@@ -339,7 +339,7 @@ export class BBNativeProofCreator implements ProofCreator {
339
339
  this.log.debug(`Generated proof`, {
340
340
  eventName: 'circuit-proving',
341
341
  circuitName: 'app-circuit',
342
- duration: provingResult.duration,
342
+ duration: provingResult.durationMs,
343
343
  inputSize: compressedBincodedWitness.length,
344
344
  proofSize: proof.binaryProof.buffer.length,
345
345
  appCircuitName,
@@ -358,7 +358,7 @@ export class BBNativeProofCreator implements ProofCreator {
358
358
 
359
359
  this.log.debug(`Generated proof`, {
360
360
  circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
361
- duration: provingResult.duration,
361
+ duration: provingResult.durationMs,
362
362
  eventName: 'circuit-proving',
363
363
  inputSize: compressedBincodedWitness.length,
364
364
  proofSize: proof.binaryProof.buffer.length,
@@ -57,6 +57,7 @@ import {
57
57
  convertRootRollupOutputsFromWitnessMap,
58
58
  } from '@aztec/noir-protocol-circuits-types';
59
59
  import { NativeACVMSimulator } from '@aztec/simulator';
60
+ import { Attributes, type TelemetryClient, trackSpan } from '@aztec/telemetry-client';
60
61
 
61
62
  import { abiEncode } from '@noir-lang/noirc_abi';
62
63
  import { type Abi, type WitnessMap } from '@noir-lang/types';
@@ -78,6 +79,7 @@ import {
78
79
  writeProofAsFields,
79
80
  } from '../bb/execute.js';
80
81
  import type { ACVMConfig, BBConfig } from '../config.js';
82
+ import { ProverInstrumentation } from '../instrumentation.js';
81
83
  import { PublicKernelArtifactMapping } from '../mappings/mappings.js';
82
84
  import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
83
85
  import { extractVkData } from '../verification_key/verification_key_data.js';
@@ -102,9 +104,18 @@ export class BBNativeRollupProver implements ServerCircuitProver {
102
104
  ServerProtocolArtifact,
103
105
  Promise<VerificationKeyData>
104
106
  >();
105
- constructor(private config: BBProverConfig) {}
106
107
 
107
- static async new(config: BBProverConfig) {
108
+ private instrumentation: ProverInstrumentation;
109
+
110
+ constructor(private config: BBProverConfig, telemetry: TelemetryClient) {
111
+ this.instrumentation = new ProverInstrumentation(telemetry, 'BBNativeRollupProver');
112
+ }
113
+
114
+ get tracer() {
115
+ return this.instrumentation.tracer;
116
+ }
117
+
118
+ static async new(config: BBProverConfig, telemetry: TelemetryClient) {
108
119
  await fs.access(config.acvmBinaryPath, fs.constants.R_OK);
109
120
  await fs.mkdir(config.acvmWorkingDirectory, { recursive: true });
110
121
  await fs.access(config.bbBinaryPath, fs.constants.R_OK);
@@ -112,7 +123,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
112
123
  logger.info(`Using native BB at ${config.bbBinaryPath} and working directory ${config.bbWorkingDirectory}`);
113
124
  logger.info(`Using native ACVM at ${config.acvmBinaryPath} and working directory ${config.acvmWorkingDirectory}`);
114
125
 
115
- return new BBNativeRollupProver(config);
126
+ return new BBNativeRollupProver(config, telemetry);
116
127
  }
117
128
 
118
129
  /**
@@ -120,6 +131,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
120
131
  * @param inputs - Inputs to the circuit.
121
132
  * @returns The public inputs of the parity circuit.
122
133
  */
134
+ @trackSpan('BBNativeRollupProver.getBaseParityProof', { [Attributes.PROTOCOL_CIRCUIT_NAME]: 'base-parity' })
123
135
  public async getBaseParityProof(inputs: BaseParityInputs): Promise<RootParityInput<typeof RECURSIVE_PROOF_LENGTH>> {
124
136
  const { circuitOutput, proof } = await this.createRecursiveProof(
125
137
  inputs,
@@ -141,6 +153,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
141
153
  * @param inputs - Inputs to the circuit.
142
154
  * @returns The public inputs of the parity circuit.
143
155
  */
156
+ @trackSpan('BBNativeRollupProver.getRootParityProof', { [Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-parity' })
144
157
  public async getRootParityProof(
145
158
  inputs: RootParityInputs,
146
159
  ): Promise<RootParityInput<typeof NESTED_RECURSIVE_PROOF_LENGTH>> {
@@ -164,6 +177,9 @@ export class BBNativeRollupProver implements ServerCircuitProver {
164
177
  * @param inputs - The inputs to the AVM circuit.
165
178
  * @returns The proof.
166
179
  */
180
+ @trackSpan('BBNativeRollupProver.getAvmProof', inputs => ({
181
+ [Attributes.APP_CIRCUIT_NAME]: inputs.functionName,
182
+ }))
167
183
  public async getAvmProof(inputs: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
168
184
  const proofAndVk = await this.createAvmProof(inputs);
169
185
  await this.verifyAvmProof(proofAndVk.proof, proofAndVk.verificationKey);
@@ -175,6 +191,11 @@ export class BBNativeRollupProver implements ServerCircuitProver {
175
191
  * @param kernelRequest - The object encapsulating the request for a proof
176
192
  * @returns The requested circuit's public inputs and proof
177
193
  */
194
+ @trackSpan('BBNativeRollupProver.getPublicKernelProof', kernelReq => ({
195
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: mapProtocolArtifactNameToCircuitName(
196
+ PublicKernelArtifactMapping[kernelReq.type]!.artifact,
197
+ ),
198
+ }))
178
199
  public async getPublicKernelProof(
179
200
  kernelRequest: PublicKernelNonTailRequest,
180
201
  ): Promise<PublicInputsAndRecursiveProof<PublicKernelCircuitPublicInputs>> {
@@ -385,11 +406,16 @@ export class BBNativeRollupProver implements ServerCircuitProver {
385
406
  const inputWitness = convertInput(input);
386
407
  const timer = new Timer();
387
408
  const outputWitness = await simulator.simulateCircuit(inputWitness, artifact);
388
- const witnessGenerationDuration = timer.ms();
389
409
  const output = convertOutput(outputWitness);
410
+
411
+ const circuitName = mapProtocolArtifactNameToCircuitName(circuitType);
412
+ this.instrumentation.recordDuration('witGenDuration', circuitName, timer);
413
+ this.instrumentation.recordSize('witGenInputSize', circuitName, input.toBuffer().length);
414
+ this.instrumentation.recordSize('witGenOutputSize', circuitName, output.toBuffer().length);
415
+
390
416
  logger.debug(`Generated witness`, {
391
- circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
392
- duration: witnessGenerationDuration,
417
+ circuitName,
418
+ duration: timer.ms(),
393
419
  inputSize: input.toBuffer().length,
394
420
  outputSize: output.toBuffer().length,
395
421
  eventName: 'circuit-witness-generation',
@@ -439,22 +465,24 @@ export class BBNativeRollupProver implements ServerCircuitProver {
439
465
  const rawProof = await fs.readFile(`${provingResult.proofPath!}/${PROOF_FILENAME}`);
440
466
 
441
467
  const proof = new Proof(rawProof, vkData.numPublicInputs);
442
- logger.info(
443
- `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
444
- proof.buffer.length
445
- } bytes`,
446
- {
447
- circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
448
- // does not include reading the proof from disk
449
- duration: provingResult.duration,
450
- proofSize: proof.buffer.length,
451
- eventName: 'circuit-proving',
452
- // circuitOutput is the partial witness that became the input to the proof
453
- inputSize: output.toBuffer().length,
454
- circuitSize: vkData.circuitSize,
455
- numPublicInputs: vkData.numPublicInputs,
456
- } satisfies CircuitProvingStats,
457
- );
468
+ const circuitName = mapProtocolArtifactNameToCircuitName(circuitType);
469
+
470
+ this.instrumentation.recordDuration('provingDuration', circuitName, provingResult.durationMs / 1000);
471
+ this.instrumentation.recordSize('proofSize', circuitName, proof.buffer.length);
472
+ this.instrumentation.recordSize('circuitPublicInputCount', circuitName, vkData.numPublicInputs);
473
+ this.instrumentation.recordSize('circuitSize', circuitName, vkData.circuitSize);
474
+
475
+ logger.info(`Generated proof for ${circuitType} in ${Math.ceil(provingResult.durationMs)} ms`, {
476
+ circuitName,
477
+ // does not include reading the proof from disk
478
+ duration: provingResult.durationMs,
479
+ proofSize: proof.buffer.length,
480
+ eventName: 'circuit-proving',
481
+ // circuitOutput is the partial witness that became the input to the proof
482
+ inputSize: output.toBuffer().length,
483
+ circuitSize: vkData.circuitSize,
484
+ numPublicInputs: vkData.numPublicInputs,
485
+ } satisfies CircuitProvingStats);
458
486
 
459
487
  return { circuitOutput: output, proof };
460
488
  };
@@ -462,12 +490,12 @@ export class BBNativeRollupProver implements ServerCircuitProver {
462
490
  }
463
491
 
464
492
  private async generateAvmProofWithBB(input: AvmCircuitInputs, workingDirectory: string): Promise<BBSuccess> {
465
- logger.debug(`Proving avm-circuit...`);
493
+ logger.info(`Proving avm-circuit for ${input.functionName}...`);
466
494
 
467
495
  const provingResult = await generateAvmProof(this.config.bbBinaryPath, workingDirectory, input, logger.verbose);
468
496
 
469
497
  if (provingResult.status === BB_RESULT.FAILURE) {
470
- logger.error(`Failed to generate proof for avm-circuit: ${provingResult.reason}`);
498
+ logger.error(`Failed to generate AVM proof for ${input.functionName}: ${provingResult.reason}`);
471
499
  throw new Error(provingResult.reason);
472
500
  }
473
501
 
@@ -489,19 +517,24 @@ export class BBNativeRollupProver implements ServerCircuitProver {
489
517
  const proof = new Proof(rawProof, verificationKey.numPublicInputs);
490
518
 
491
519
  const circuitType = 'avm-circuit' as const;
520
+ const appCircuitName = 'unknown' as const;
521
+ this.instrumentation.recordAvmDuration('provingDuration', appCircuitName, provingResult.durationMs);
522
+ this.instrumentation.recordAvmSize('proofSize', appCircuitName, proof.buffer.length);
523
+ this.instrumentation.recordAvmSize('circuitPublicInputCount', appCircuitName, verificationKey.numPublicInputs);
524
+ this.instrumentation.recordAvmSize('circuitSize', appCircuitName, verificationKey.circuitSize);
525
+
492
526
  logger.info(
493
- `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
494
- proof.buffer.length
495
- } bytes`,
527
+ `Generated proof for ${circuitType}(${input.functionName}) in ${Math.ceil(provingResult.durationMs)} ms`,
496
528
  {
497
529
  circuitName: circuitType,
530
+ appCircuitName: input.functionName,
498
531
  // does not include reading the proof from disk
499
- duration: provingResult.duration,
532
+ duration: provingResult.durationMs,
500
533
  proofSize: proof.buffer.length,
501
534
  eventName: 'circuit-proving',
502
535
  inputSize: input.toBuffer().length,
503
- circuitSize: verificationKey.circuitSize,
504
- numPublicInputs: verificationKey.numPublicInputs,
536
+ circuitSize: verificationKey.circuitSize, // FIX: wrong in VK
537
+ numPublicInputs: verificationKey.numPublicInputs, // FIX: wrong in VK
505
538
  } satisfies CircuitProvingStats,
506
539
  );
507
540
 
@@ -540,14 +573,19 @@ export class BBNativeRollupProver implements ServerCircuitProver {
540
573
  // Read the proof as fields
541
574
  const proof = await this.readProofAsFields(provingResult.proofPath!, circuitType, proofLength);
542
575
 
576
+ const circuitName = mapProtocolArtifactNameToCircuitName(circuitType);
577
+ this.instrumentation.recordDuration('provingDuration', circuitName, provingResult.durationMs / 1000);
578
+ this.instrumentation.recordSize('proofSize', circuitName, proof.binaryProof.buffer.length);
579
+ this.instrumentation.recordSize('circuitPublicInputCount', circuitName, vkData.numPublicInputs);
580
+ this.instrumentation.recordSize('circuitSize', circuitName, vkData.circuitSize);
543
581
  logger.info(
544
- `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
582
+ `Generated proof for ${circuitType} in ${Math.ceil(provingResult.durationMs)} ms, size: ${
545
583
  proof.proof.length
546
584
  } fields`,
547
585
  {
548
- circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
586
+ circuitName,
549
587
  circuitSize: vkData.circuitSize,
550
- duration: provingResult.duration,
588
+ duration: provingResult.durationMs,
551
589
  inputSize: output.toBuffer().length,
552
590
  proofSize: proof.binaryProof.buffer.length,
553
591
  eventName: 'circuit-proving',
@@ -609,7 +647,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
609
647
  throw new Error(errorMessage);
610
648
  }
611
649
 
612
- logger.debug(`Successfully verified proof from key in ${result.duration} ms`);
650
+ logger.debug(`Successfully verified proof from key in ${result.durationMs} ms`);
613
651
  };
614
652
 
615
653
  await runInDirectory(this.config.bbWorkingDirectory, operation);
package/src/stats.ts CHANGED
@@ -1,21 +1,7 @@
1
- import { type PublicKernelRequest, PublicKernelType } from '@aztec/circuit-types';
2
1
  import type { CircuitName } from '@aztec/circuit-types/stats';
3
2
  import { type ClientProtocolArtifact, type ServerProtocolArtifact } from '@aztec/noir-protocol-circuits-types';
4
3
 
5
- export function mapPublicKernelToCircuitName(kernelType: PublicKernelRequest['type']): CircuitName {
6
- switch (kernelType) {
7
- case PublicKernelType.SETUP:
8
- return 'public-kernel-setup';
9
- case PublicKernelType.APP_LOGIC:
10
- return 'public-kernel-app-logic';
11
- case PublicKernelType.TEARDOWN:
12
- return 'public-kernel-teardown';
13
- case PublicKernelType.TAIL:
14
- return 'public-kernel-tail';
15
- default:
16
- throw new Error(`Unknown kernel type: ${kernelType}`);
17
- }
18
- }
4
+ export { mapPublicKernelToCircuitName } from '@aztec/circuit-types';
19
5
 
20
6
  export function mapProtocolArtifactNameToCircuitName(
21
7
  artifact: ServerProtocolArtifact | ClientProtocolArtifact,
@@ -57,7 +57,9 @@ import {
57
57
  convertSimulatedPublicTailOutputFromWitnessMap,
58
58
  } from '@aztec/noir-protocol-circuits-types';
59
59
  import { type SimulationProvider, WASMSimulator, emitCircuitSimulationStats } from '@aztec/simulator';
60
+ import { type TelemetryClient, trackSpan } from '@aztec/telemetry-client';
60
61
 
62
+ import { ProverInstrumentation } from '../instrumentation.js';
61
63
  import { SimulatedPublicKernelArtifactMapping } from '../mappings/mappings.js';
62
64
  import { mapPublicKernelToCircuitName } from '../stats.js';
63
65
 
@@ -81,11 +83,19 @@ const VERIFICATION_KEYS: Record<ServerProtocolArtifact, VerificationKeyAsFields>
81
83
  */
82
84
  export class TestCircuitProver implements ServerCircuitProver {
83
85
  private wasmSimulator = new WASMSimulator();
86
+ private instrumentation: ProverInstrumentation;
84
87
 
85
88
  constructor(
89
+ telemetry: TelemetryClient,
86
90
  private simulationProvider?: SimulationProvider,
87
91
  private logger = createDebugLogger('aztec:test-prover'),
88
- ) {}
92
+ ) {
93
+ this.instrumentation = new ProverInstrumentation(telemetry, 'TestCircuitProver');
94
+ }
95
+
96
+ get tracer() {
97
+ return this.instrumentation.tracer;
98
+ }
89
99
 
90
100
  public async getEmptyPrivateKernelProof(
91
101
  inputs: PrivateKernelEmptyInputData,
@@ -111,6 +121,7 @@ export class TestCircuitProver implements ServerCircuitProver {
111
121
  * @param inputs - Inputs to the circuit.
112
122
  * @returns The public inputs of the parity circuit.
113
123
  */
124
+ @trackSpan('TestCircuitProver.getBaseParityProof')
114
125
  public async getBaseParityProof(inputs: BaseParityInputs): Promise<RootParityInput<typeof RECURSIVE_PROOF_LENGTH>> {
115
126
  const timer = new Timer();
116
127
  const witnessMap = convertBaseParityInputsToWitnessMap(inputs);
@@ -125,6 +136,8 @@ export class TestCircuitProver implements ServerCircuitProver {
125
136
  result,
126
137
  );
127
138
 
139
+ this.instrumentation.recordDuration('simulationDuration', 'base-parity', timer);
140
+
128
141
  emitCircuitSimulationStats(
129
142
  'base-parity',
130
143
  timer.ms(),
@@ -141,6 +154,7 @@ export class TestCircuitProver implements ServerCircuitProver {
141
154
  * @param inputs - Inputs to the circuit.
142
155
  * @returns The public inputs of the parity circuit.
143
156
  */
157
+ @trackSpan('TestCircuitProver.getRootParityProof')
144
158
  public async getRootParityProof(
145
159
  inputs: RootParityInputs,
146
160
  ): Promise<RootParityInput<typeof NESTED_RECURSIVE_PROOF_LENGTH>> {
@@ -158,6 +172,7 @@ export class TestCircuitProver implements ServerCircuitProver {
158
172
  result,
159
173
  );
160
174
 
175
+ this.instrumentation.recordDuration('simulationDuration', 'root-parity', timer);
161
176
  emitCircuitSimulationStats(
162
177
  'root-parity',
163
178
  timer.ms(),
@@ -174,6 +189,7 @@ export class TestCircuitProver implements ServerCircuitProver {
174
189
  * @param input - Inputs to the circuit.
175
190
  * @returns The public inputs as outputs of the simulation.
176
191
  */
192
+ @trackSpan('TestCircuitProver.getBaseRollupProof')
177
193
  public async getBaseRollupProof(
178
194
  input: BaseRollupInputs,
179
195
  ): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs>> {
@@ -185,6 +201,7 @@ export class TestCircuitProver implements ServerCircuitProver {
185
201
 
186
202
  const result = convertSimulatedBaseRollupOutputsFromWitnessMap(witness);
187
203
 
204
+ this.instrumentation.recordDuration('simulationDuration', 'base-rollup', timer);
188
205
  emitCircuitSimulationStats(
189
206
  'base-rollup',
190
207
  timer.ms(),
@@ -203,6 +220,7 @@ export class TestCircuitProver implements ServerCircuitProver {
203
220
  * @param input - Inputs to the circuit.
204
221
  * @returns The public inputs as outputs of the simulation.
205
222
  */
223
+ @trackSpan('TestCircuitProver.getMergeRollupProof')
206
224
  public async getMergeRollupProof(
207
225
  input: MergeRollupInputs,
208
226
  ): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs>> {
@@ -214,6 +232,7 @@ export class TestCircuitProver implements ServerCircuitProver {
214
232
 
215
233
  const result = convertMergeRollupOutputsFromWitnessMap(witness);
216
234
 
235
+ this.instrumentation.recordDuration('simulationDuration', 'merge-rollup', timer);
217
236
  emitCircuitSimulationStats(
218
237
  'merge-rollup',
219
238
  timer.ms(),
@@ -233,6 +252,7 @@ export class TestCircuitProver implements ServerCircuitProver {
233
252
  * @param input - Inputs to the circuit.
234
253
  * @returns The public inputs as outputs of the simulation.
235
254
  */
255
+ @trackSpan('TestCircuitProver.getRootRollupProof')
236
256
  public async getRootRollupProof(
237
257
  input: RootRollupInputs,
238
258
  ): Promise<PublicInputsAndRecursiveProof<RootRollupPublicInputs>> {
@@ -244,6 +264,7 @@ export class TestCircuitProver implements ServerCircuitProver {
244
264
 
245
265
  const result = convertRootRollupOutputsFromWitnessMap(witness);
246
266
 
267
+ this.instrumentation.recordDuration('simulationDuration', 'root-rollup', timer);
247
268
  emitCircuitSimulationStats(
248
269
  'root-rollup',
249
270
  timer.ms(),
@@ -258,6 +279,7 @@ export class TestCircuitProver implements ServerCircuitProver {
258
279
  );
259
280
  }
260
281
 
282
+ @trackSpan('TestCircuitProver.getPublicKernelProof')
261
283
  public async getPublicKernelProof(
262
284
  kernelRequest: PublicKernelNonTailRequest,
263
285
  ): Promise<PublicInputsAndRecursiveProof<PublicKernelCircuitPublicInputs>> {
@@ -274,8 +296,10 @@ export class TestCircuitProver implements ServerCircuitProver {
274
296
  );
275
297
 
276
298
  const result = kernelOps.convertOutputs(witness);
299
+ const circuitName = mapPublicKernelToCircuitName(kernelRequest.type);
300
+ this.instrumentation.recordDuration('simulationDuration', circuitName, timer);
277
301
  emitCircuitSimulationStats(
278
- mapPublicKernelToCircuitName(kernelRequest.type),
302
+ circuitName,
279
303
  timer.ms(),
280
304
  kernelRequest.inputs.toBuffer().length,
281
305
  result.toBuffer().length,
@@ -289,6 +313,7 @@ export class TestCircuitProver implements ServerCircuitProver {
289
313
  );
290
314
  }
291
315
 
316
+ @trackSpan('TestCircuitProver.getPublicTailProof')
292
317
  public async getPublicTailProof(
293
318
  kernelRequest: PublicKernelTailRequest,
294
319
  ): Promise<PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>> {
@@ -301,6 +326,7 @@ export class TestCircuitProver implements ServerCircuitProver {
301
326
  );
302
327
 
303
328
  const result = convertSimulatedPublicTailOutputFromWitnessMap(witness);
329
+ this.instrumentation.recordDuration('simulationDuration', 'public-kernel-tail', timer);
304
330
  emitCircuitSimulationStats(
305
331
  'public-kernel-tail',
306
332
  timer.ms(),