@aztec/end-to-end 0.87.5 → 0.87.7

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.
@@ -2,6 +2,7 @@ import { EcdsaRAccountContractArtifact, getEcdsaRAccount } from '@aztec/accounts
2
2
  import { SchnorrAccountContractArtifact, getSchnorrAccount, getSchnorrWallet } from '@aztec/accounts/schnorr';
3
3
  import {
4
4
  type AccountWallet,
5
+ AccountWalletWithSecretKey,
5
6
  AztecAddress,
6
7
  type AztecNode,
7
8
  FeeJuicePaymentMethod,
@@ -47,6 +48,7 @@ import {
47
48
  FeeJuicePortalTestingHarnessFactory,
48
49
  type GasBridgingTestHarness,
49
50
  } from '../../shared/gas_portal_test_harness.js';
51
+ import { ProxyLogger } from './benchmark.js';
50
52
  import { type ClientFlowsConfig, FULL_FLOWS_CONFIG, KEY_FLOWS_CONFIG } from './config.js';
51
53
 
52
54
  const { E2E_DATA_PATH: dataPath, BENCHMARK_CONFIG } = process.env;
@@ -91,6 +93,8 @@ export class ClientFlowsBenchmark {
91
93
  // PXE used by the benchmarking user. It can be set up with client-side proving enabled
92
94
  public userPXE!: PXE;
93
95
 
96
+ public realProofs = ['true', '1'].includes(process.env.REAL_PROOFS ?? '');
97
+
94
98
  public paymentMethods: Record<BenchmarkingFeePaymentMethod, { forWallet: FeePaymentMethodGetter; circuits: number }> =
95
99
  {
96
100
  // eslint-disable-next-line camelcase
@@ -121,6 +125,8 @@ export class ClientFlowsBenchmark {
121
125
 
122
126
  public config: ClientFlowsConfig;
123
127
 
128
+ private proxyLogger: ProxyLogger;
129
+
124
130
  constructor(testName?: string, setupOptions: Partial<SetupOptions & DeployL1ContractsArgs> = {}) {
125
131
  this.logger = createLogger(`bench:client_flows${testName ? `:${testName}` : ''}`);
126
132
  this.snapshotManager = createSnapshotManager(
@@ -130,6 +136,8 @@ export class ClientFlowsBenchmark {
130
136
  { ...setupOptions },
131
137
  );
132
138
  this.config = BENCHMARK_CONFIG === 'key_flows' ? KEY_FLOWS_CONFIG : FULL_FLOWS_CONFIG;
139
+ ProxyLogger.create();
140
+ this.proxyLogger = ProxyLogger.getInstance();
133
141
  }
134
142
 
135
143
  async setup() {
@@ -163,7 +171,7 @@ export class ClientFlowsBenchmark {
163
171
  expect(balanceAfter).toEqual(balanceBefore + amount);
164
172
  }
165
173
 
166
- async createBenchmarkingAccountManager(type: 'ecdsar1' | 'schnorr') {
174
+ async createBenchmarkingAccountManager(pxe: PXE, type: 'ecdsar1' | 'schnorr') {
167
175
  const benchysSecretKey = Fr.random();
168
176
  const salt = Fr.random();
169
177
 
@@ -171,10 +179,10 @@ export class ClientFlowsBenchmark {
171
179
  let benchysAccountManager;
172
180
  if (type === 'schnorr') {
173
181
  benchysPrivateSigningKey = deriveSigningKey(benchysSecretKey);
174
- benchysAccountManager = await getSchnorrAccount(this.userPXE, benchysSecretKey, benchysPrivateSigningKey, salt);
182
+ benchysAccountManager = await getSchnorrAccount(pxe, benchysSecretKey, benchysPrivateSigningKey, salt);
175
183
  } else if (type === 'ecdsar1') {
176
184
  benchysPrivateSigningKey = randomBytes(32);
177
- benchysAccountManager = await getEcdsaRAccount(this.userPXE, benchysSecretKey, benchysPrivateSigningKey, salt);
185
+ benchysAccountManager = await getEcdsaRAccount(pxe, benchysSecretKey, benchysPrivateSigningKey, salt);
178
186
  } else {
179
187
  throw new Error(`Unknown account type: ${type}`);
180
188
  }
@@ -212,11 +220,15 @@ export class ClientFlowsBenchmark {
212
220
  const l1Contracts = await aztecNode.getL1ContractAddresses();
213
221
  const userPXEConfigWithContracts = {
214
222
  ...userPXEConfig,
215
- proverEnabled: ['true', '1'].includes(process.env.REAL_PROOFS ?? ''),
223
+ proverEnabled: this.realProofs,
216
224
  l1Contracts,
217
225
  } as PXEServiceConfig;
218
226
 
219
- this.userPXE = await createPXEService(this.aztecNode, userPXEConfigWithContracts, 'pxe-user');
227
+ this.userPXE = await createPXEService(this.aztecNode, userPXEConfigWithContracts, {
228
+ loggers: {
229
+ prover: this.proxyLogger.createLogger('pxe:bb:wasm:bundle:proxied'),
230
+ },
231
+ });
220
232
  },
221
233
  );
222
234
  }
@@ -337,7 +349,7 @@ export class ClientFlowsBenchmark {
337
349
  }
338
350
 
339
351
  public async createAndFundBenchmarkingWallet(accountType: AccountType) {
340
- const benchysAccountManager = await this.createBenchmarkingAccountManager(accountType);
352
+ const benchysAccountManager = await this.createBenchmarkingAccountManager(this.pxe, accountType);
341
353
  const benchysWallet = await benchysAccountManager.getWallet();
342
354
  const benchysAddress = benchysAccountManager.getAddress();
343
355
  const claim = await this.feeJuiceBridgeTestHarness.prepareTokensOnL1(
@@ -346,13 +358,19 @@ export class ClientFlowsBenchmark {
346
358
  );
347
359
  const paymentMethod = new FeeJuicePaymentMethodWithClaim(benchysWallet, claim);
348
360
  await benchysAccountManager.deploy({ fee: { paymentMethod } }).wait();
349
- // Register benchy on admin's PXE so we can check its balances
350
- await this.pxe.registerContract({
361
+ // Register benchy on the user's PXE, where we're going to be interacting from
362
+ await this.userPXE.registerContract({
351
363
  instance: benchysAccountManager.getInstance(),
352
364
  artifact: accountType === 'ecdsar1' ? EcdsaRAccountContractArtifact : SchnorrAccountContractArtifact,
353
365
  });
354
- await this.pxe.registerAccount(benchysWallet.getSecretKey(), benchysWallet.getCompleteAddress().partialAddress);
355
- return benchysWallet;
366
+ await this.userPXE.registerAccount(benchysWallet.getSecretKey(), benchysWallet.getCompleteAddress().partialAddress);
367
+ const entrypoint = await benchysAccountManager.getAccount();
368
+ return new AccountWalletWithSecretKey(
369
+ this.userPXE,
370
+ entrypoint,
371
+ benchysWallet.getSecretKey(),
372
+ benchysAccountManager.salt,
373
+ );
356
374
  }
357
375
 
358
376
  public async applyDeployAmmSnapshot() {
@@ -5,134 +5,29 @@ import { createLogger, logger } from '@aztec/foundation/log';
5
5
  import { Timer } from '@aztec/foundation/timer';
6
6
  import { WASMSimulator } from '@aztec/simulator/client';
7
7
  import type { PrivateExecutionStep } from '@aztec/stdlib/kernel';
8
+ import type { ProvingStats, ProvingTimings, SimulationStats } from '@aztec/stdlib/tx';
8
9
 
9
10
  import { Decoder } from 'msgpackr';
10
- import assert from 'node:assert';
11
11
  import { readFile, readdir, writeFile } from 'node:fs/promises';
12
12
  import { join } from 'node:path';
13
13
 
14
- const logLevel = ['silent', 'fatal', 'error', 'warn', 'info', 'verbose', 'debug', 'trace'] as const;
15
- type LogLevel = (typeof logLevel)[number];
16
-
17
- type Log = {
18
- type: LogLevel;
19
- timestamp: number;
20
- prefix: string;
21
- message: string;
22
-
23
- data: any;
24
- };
25
-
26
- const GATE_TYPES = [
27
- 'ecc_op',
28
- 'busread',
29
- 'lookup',
30
- 'pub_inputs',
31
- 'arithmetic',
32
- 'delta_range',
33
- 'elliptic',
34
- 'aux',
35
- 'poseidon2_external',
36
- 'poseidon2_internal',
37
- 'overflow',
38
- ] as const;
39
-
40
- type GateType = (typeof GATE_TYPES)[number];
41
-
42
- type StructuredTrace = {
43
- [k in GateType]: number;
44
- };
45
-
46
- export class ProxyLogger {
47
- private static instance: ProxyLogger;
48
- private logs: Log[] = [];
49
-
50
- private constructor() {}
51
-
52
- static create() {
53
- ProxyLogger.instance = new ProxyLogger();
54
- }
55
-
56
- static getInstance() {
57
- return ProxyLogger.instance;
58
- }
59
-
60
- createLogger(prefix: string): Logger {
61
- return new Proxy(createLogger(prefix), {
62
- get: (target: Logger, prop: keyof Logger) => {
63
- if (logLevel.includes(prop as (typeof logLevel)[number])) {
64
- return function (this: Logger, ...data: Parameters<Logger[LogLevel]>) {
65
- const loggingFn = prop as LogLevel;
66
- const args = [loggingFn, prefix, ...data] as Parameters<ProxyLogger['handleLog']>;
67
- ProxyLogger.getInstance().handleLog(...args);
68
- target[loggingFn].call(this, ...[data[0], data[1]]);
69
- };
70
- } else {
71
- return target[prop];
72
- }
73
- },
74
- });
75
- }
76
-
77
- private handleLog(type: (typeof logLevel)[number], prefix: string, message: string, data: any) {
78
- this.logs.unshift({ type, prefix, message, data, timestamp: Date.now() });
79
- }
80
-
81
- public flushLogs() {
82
- this.logs = [];
83
- }
84
-
85
- public getLogs() {
86
- return this.logs;
87
- }
88
- }
14
+ import { type Log, type ProverType, ProxyLogger, generateBenchmark } from './benchmark.js';
89
15
 
90
16
  type NativeProverConfig = { bbBinaryPath?: string; bbWorkingDirectory?: string };
91
17
 
92
- type ProverType = 'wasm' | 'native';
93
-
94
- type Step = { fnName: string; gateCount: number; accGateCount?: number };
95
-
96
18
  async function createProver(config: NativeProverConfig = {}, log: Logger) {
97
- const simulationProvider = new WASMSimulator();
19
+ const simulator = new WASMSimulator();
98
20
  if (!config.bbBinaryPath || !config.bbWorkingDirectory) {
99
- return { prover: new BBWASMBundlePrivateKernelProver(simulationProvider, 16, log), type: 'wasm' as ProverType };
21
+ return { prover: new BBWASMBundlePrivateKernelProver(simulator, 16, log), type: 'wasm' as ProverType };
100
22
  } else {
101
23
  const bbConfig = config as Required<NativeProverConfig>;
102
24
  return {
103
- prover: await BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, simulationProvider, log),
25
+ prover: await BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, simulator, log),
104
26
  type: 'native' as ProverType,
105
27
  };
106
28
  }
107
29
  }
108
30
 
109
- function getMinimumTrace(logs: Log[]): StructuredTrace {
110
- const minimumMessage = 'Trace details:';
111
- const minimumMessageIndex = logs.findIndex(log => log.message.includes(minimumMessage));
112
- const candidateLogs = logs.slice(minimumMessageIndex - GATE_TYPES.length, minimumMessageIndex);
113
-
114
- const traceLogs = candidateLogs
115
- .filter(log => GATE_TYPES.some(type => log.message.includes(type)))
116
- .map(log => log.message.split(/\t|\n/))
117
- .flat()
118
- .map(log => log.replace(/\(mem: .*\)/, '').trim())
119
- .filter(Boolean);
120
-
121
- const traceSizes = traceLogs.map(log => {
122
- const [gateType, gateSizeStr] = log
123
- .replace(/\n.*\)$/, '')
124
- .replace(/bb - /, '')
125
- .split(':')
126
- .map(s => s.trim());
127
- const gateSize = parseInt(gateSizeStr);
128
- assert(GATE_TYPES.includes(gateType as GateType), `Gate type ${gateType} is not recognized`);
129
- return { [gateType]: gateSize };
130
- });
131
-
132
- assert(traceSizes.length === GATE_TYPES.length, 'Decoded trace sizes do not match expected amount of gate types');
133
- return traceSizes.reduce((acc, curr) => ({ ...acc, ...curr }), {}) as StructuredTrace;
134
- }
135
-
136
31
  async function main() {
137
32
  ProxyLogger.create();
138
33
  const proxyLogger = ProxyLogger.getInstance();
@@ -160,15 +55,15 @@ async function main() {
160
55
  });
161
56
  const profileFile = await readFile(join(ivcFolder, flow, 'profile.json'));
162
57
  const profile = JSON.parse(profileFile.toString()) as {
163
- syncTime: number;
58
+ stats: ProvingStats | SimulationStats;
164
59
  steps: {
165
- fnName: string;
60
+ functionName: string;
166
61
  gateCount: number;
167
62
  timings: { witgen: number; gateCount: number };
168
63
  }[];
169
64
  };
170
65
  const privateExecutionSteps: PrivateExecutionStep[] = profile.steps.map((step, i) => ({
171
- functionName: step.fnName,
66
+ functionName: step.functionName,
172
67
  gateCount: step.gateCount,
173
68
  bytecode: stepsFromFile[i].bytecode,
174
69
  // TODO(AD) do we still want to take this from witness.json?
@@ -176,10 +71,9 @@ async function main() {
176
71
  vk: stepsFromFile[i].vk,
177
72
  timings: {
178
73
  witgen: step.timings.witgen,
179
- gateCount: step.timings.witgen,
74
+ gateCount: step.timings.gateCount,
180
75
  },
181
76
  }));
182
- let stats: { duration: number; eventName: string; proofSize: number } | undefined;
183
77
 
184
78
  let error: any;
185
79
  let currentLogs: Log[] = [];
@@ -195,38 +89,10 @@ async function main() {
195
89
  // Extract logs from this run from the proxy and write them to disk unconditionally
196
90
  currentLogs = proxyLogger.getLogs();
197
91
  await writeFile(join(ivcFolder, flow, 'logs.json'), JSON.stringify(currentLogs, null, 2));
198
-
199
- if (!error) {
200
- stats = currentLogs[0].data as { duration: number; eventName: string; proofSize: number };
92
+ if (!(profile.stats.timings as ProvingTimings).proving) {
93
+ (profile.stats.timings as ProvingTimings).proving = provingTime;
201
94
  }
202
-
203
- const minimumTrace = getMinimumTrace(currentLogs);
204
-
205
- const steps = profile.steps.reduce<Step[]>((acc, step, i) => {
206
- const previousAccGateCount = i === 0 ? 0 : acc[i - 1].accGateCount!;
207
- return [
208
- ...acc,
209
- {
210
- fnName: step.fnName,
211
- gateCount: step.gateCount,
212
- accGateCount: previousAccGateCount + step.gateCount,
213
- timings: {
214
- witgen: step.timings.witgen,
215
- },
216
- },
217
- ];
218
- }, []);
219
- const totalGateCount = steps[steps.length - 1].accGateCount;
220
- const benchmark = {
221
- syncTime: profile.syncTime,
222
- provingTime,
223
- proverType,
224
- minimumTrace: minimumTrace,
225
- totalGateCount,
226
- stats,
227
- steps,
228
- error,
229
- };
95
+ const benchmark = generateBenchmark(flow, currentLogs, profile.stats, privateExecutionSteps, proverType, error);
230
96
  await writeFile(join(ivcFolder, flow, 'benchmark.json'), JSON.stringify(benchmark, null, 2));
231
97
  proxyLogger.flushLogs();
232
98
  }
@@ -53,7 +53,7 @@ type MetricFilter = {
53
53
  };
54
54
 
55
55
  // See https://github.com/benchmark-action/github-action-benchmark/blob/e3c661617bc6aa55f26ae4457c737a55545a86a4/src/extract.ts#L659-L670
56
- type GithubActionBenchmarkResult = {
56
+ export type GithubActionBenchmarkResult = {
57
57
  name: string;
58
58
  value: number;
59
59
  range?: string;
@@ -48,7 +48,7 @@ export const createPXEServiceAndSubmitTransactions = async (
48
48
  ): Promise<NodeContext> => {
49
49
  const rpcConfig = getRpcConfig();
50
50
  rpcConfig.proverEnabled = false;
51
- const pxeService = await createPXEService(node, rpcConfig, true);
51
+ const pxeService = await createPXEService(node, rpcConfig, { useLogSuffix: true });
52
52
 
53
53
  const account = await getSchnorrAccount(
54
54
  pxeService,
@@ -71,7 +71,7 @@ export async function createPXEServiceAndPrepareTransactions(
71
71
  ): Promise<{ pxeService: PXEService; txs: ProvenTx[]; node: AztecNodeService }> {
72
72
  const rpcConfig = getRpcConfig();
73
73
  rpcConfig.proverEnabled = false;
74
- const pxe = await createPXEService(node, rpcConfig, true);
74
+ const pxe = await createPXEService(node, rpcConfig, { useLogSuffix: true });
75
75
 
76
76
  const account = await getSchnorrAccount(pxe, fundedAccount.secret, fundedAccount.signingKey, fundedAccount.salt);
77
77
  await account.register();
@@ -54,13 +54,13 @@ import { type ProverNode, type ProverNodeConfig, createProverNode } from '@aztec
54
54
  import {
55
55
  type PXEService,
56
56
  type PXEServiceConfig,
57
- createPXEServiceWithSimulationProvider,
57
+ createPXEServiceWithSimulator,
58
58
  getPXEServiceConfig,
59
59
  } from '@aztec/pxe/server';
60
60
  import type { SequencerClient } from '@aztec/sequencer-client';
61
61
  import type { TestSequencerClient } from '@aztec/sequencer-client/test';
62
- import { WASMSimulator } from '@aztec/simulator/client';
63
- import { SimulationProviderRecorderWrapper } from '@aztec/simulator/testing';
62
+ import { MemoryCircuitRecorder, SimulatorRecorderWrapper, WASMSimulator } from '@aztec/simulator/client';
63
+ import { FileCircuitRecorder } from '@aztec/simulator/testing';
64
64
  import { getContractClassFromArtifact, getContractInstanceFromDeployParams } from '@aztec/stdlib/contract';
65
65
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
66
66
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
@@ -170,14 +170,14 @@ export async function setupPXEService(
170
170
  pxeServiceConfig.dataDirectory = path.join(tmpdir(), randomBytes(8).toString('hex'));
171
171
  }
172
172
 
173
- const simulationProvider = new WASMSimulator();
174
- const simulationProviderWithRecorder = new SimulationProviderRecorderWrapper(simulationProvider);
175
- const pxe = await createPXEServiceWithSimulationProvider(
176
- aztecNode,
177
- simulationProviderWithRecorder,
178
- pxeServiceConfig,
173
+ const simulator = new WASMSimulator();
174
+ const recorder = process.env.CIRCUIT_RECORD_DIR
175
+ ? new FileCircuitRecorder(process.env.CIRCUIT_RECORD_DIR)
176
+ : new MemoryCircuitRecorder();
177
+ const simulatorWithRecorder = new SimulatorRecorderWrapper(simulator, recorder);
178
+ const pxe = await createPXEServiceWithSimulator(aztecNode, simulatorWithRecorder, pxeServiceConfig, {
179
179
  useLogSuffix,
180
- );
180
+ });
181
181
 
182
182
  const teardown = async () => {
183
183
  if (!configuredDataDirectory) {
@@ -1,7 +0,0 @@
1
- /**
2
- * This module exposes the ability to capture the private exection steps that go into our "Client IVC" prover.
3
- * These are used for debugging and benchmarking barretenberg (the prover component).
4
- */
5
- import type { ContractFunctionInteraction, DeployMethod, DeployOptions, ProfileMethodOptions } from '@aztec/aztec.js/contracts';
6
- export declare function capturePrivateExecutionStepsIfEnvSet(label: string, interaction: ContractFunctionInteraction | DeployMethod, opts?: Omit<ProfileMethodOptions & DeployOptions, 'profileMode'>, expectedSteps?: number): Promise<void>;
7
- //# sourceMappingURL=capture_private_execution_steps.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"capture_private_execution_steps.d.ts","sourceRoot":"","sources":["../../src/shared/capture_private_execution_steps.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EACV,2BAA2B,EAC3B,YAAY,EACZ,aAAa,EACb,oBAAoB,EACrB,MAAM,2BAA2B,CAAC;AASnC,wBAAsB,oCAAoC,CACxD,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,2BAA2B,GAAG,YAAY,EACvD,IAAI,CAAC,EAAE,IAAI,CAAC,oBAAoB,GAAG,aAAa,EAAE,aAAa,CAAC,EAChE,aAAa,CAAC,EAAE,MAAM,iBA6CvB"}
@@ -1,49 +0,0 @@
1
- /**
2
- * This module exposes the ability to capture the private exection steps that go into our "Client IVC" prover.
3
- * These are used for debugging and benchmarking barretenberg (the prover component).
4
- */ import { createLogger } from '@aztec/foundation/log';
5
- import { serializePrivateExecutionSteps } from '@aztec/stdlib/kernel';
6
- import { promises as fs } from 'fs';
7
- import path from 'path';
8
- const logger = createLogger('e2e:capture-private-execution-steps');
9
- export async function capturePrivateExecutionStepsIfEnvSet(label, interaction, opts, expectedSteps) {
10
- // Not included in env_var.ts as internal to e2e tests.
11
- const ivcFolder = process.env.CAPTURE_IVC_FOLDER;
12
- if (!ivcFolder) {
13
- return;
14
- }
15
- const profileMode = [
16
- 'execution-steps',
17
- 'full'
18
- ].includes(process.env.PROFILE_MODE ?? '') ? process.env.PROFILE_MODE : 'execution-steps';
19
- logger.info(`Capturing client ivc execution profile for ${label} in mode ${profileMode}`);
20
- const result = await interaction.profile({
21
- ...opts,
22
- profileMode
23
- });
24
- if (expectedSteps !== undefined && result.executionSteps.length !== expectedSteps) {
25
- throw new Error(`Expected ${expectedSteps} execution steps, got ${result.executionSteps.length}`);
26
- }
27
- const resultsDirectory = path.join(ivcFolder, label);
28
- logger.info(`Writing private execution steps to ${resultsDirectory}`);
29
- await fs.mkdir(resultsDirectory, {
30
- recursive: true
31
- });
32
- // Write the client IVC files read by the prover.
33
- const ivcInputsPath = path.join(resultsDirectory, 'ivc-inputs.msgpack');
34
- await fs.writeFile(ivcInputsPath, serializePrivateExecutionSteps(result.executionSteps));
35
- if (profileMode === 'full') {
36
- // If we have gate counts, write the steps in human-readable format.
37
- await fs.writeFile(path.join(resultsDirectory, 'profile.json'), JSON.stringify({
38
- timings: result.timings,
39
- steps: result.executionSteps.map((step)=>({
40
- fnName: step.functionName,
41
- gateCount: step.gateCount,
42
- timings: step.timings
43
- }))
44
- }, null, 2));
45
- // In full mode, we also write the raw witnesses in a more human-readable format.
46
- await fs.writeFile(path.join(resultsDirectory, 'witnesses.json'), JSON.stringify(result.executionSteps.map((step)=>Object.fromEntries(step.witness))));
47
- }
48
- logger.info(`Wrote private execution steps to ${resultsDirectory}`);
49
- }
@@ -1,68 +0,0 @@
1
- /**
2
- * This module exposes the ability to capture the private exection steps that go into our "Client IVC" prover.
3
- * These are used for debugging and benchmarking barretenberg (the prover component).
4
- */
5
- import type {
6
- ContractFunctionInteraction,
7
- DeployMethod,
8
- DeployOptions,
9
- ProfileMethodOptions,
10
- } from '@aztec/aztec.js/contracts';
11
- import { createLogger } from '@aztec/foundation/log';
12
- import { serializePrivateExecutionSteps } from '@aztec/stdlib/kernel';
13
-
14
- import { promises as fs } from 'fs';
15
- import path from 'path';
16
-
17
- const logger = createLogger('e2e:capture-private-execution-steps');
18
-
19
- export async function capturePrivateExecutionStepsIfEnvSet(
20
- label: string,
21
- interaction: ContractFunctionInteraction | DeployMethod,
22
- opts?: Omit<ProfileMethodOptions & DeployOptions, 'profileMode'>,
23
- expectedSteps?: number,
24
- ) {
25
- // Not included in env_var.ts as internal to e2e tests.
26
- const ivcFolder = process.env.CAPTURE_IVC_FOLDER;
27
- if (!ivcFolder) {
28
- return;
29
- }
30
- const profileMode = ['execution-steps', 'full'].includes(process.env.PROFILE_MODE ?? '')
31
- ? (process.env.PROFILE_MODE as 'full' | 'execution-steps')
32
- : 'execution-steps';
33
- logger.info(`Capturing client ivc execution profile for ${label} in mode ${profileMode}`);
34
- const result = await interaction.profile({ ...opts, profileMode });
35
- if (expectedSteps !== undefined && result.executionSteps.length !== expectedSteps) {
36
- throw new Error(`Expected ${expectedSteps} execution steps, got ${result.executionSteps.length}`);
37
- }
38
- const resultsDirectory = path.join(ivcFolder, label);
39
- logger.info(`Writing private execution steps to ${resultsDirectory}`);
40
- await fs.mkdir(resultsDirectory, { recursive: true });
41
- // Write the client IVC files read by the prover.
42
- const ivcInputsPath = path.join(resultsDirectory, 'ivc-inputs.msgpack');
43
- await fs.writeFile(ivcInputsPath, serializePrivateExecutionSteps(result.executionSteps));
44
- if (profileMode === 'full') {
45
- // If we have gate counts, write the steps in human-readable format.
46
- await fs.writeFile(
47
- path.join(resultsDirectory, 'profile.json'),
48
- JSON.stringify(
49
- {
50
- timings: result.timings,
51
- steps: result.executionSteps.map(step => ({
52
- fnName: step.functionName,
53
- gateCount: step.gateCount,
54
- timings: step.timings,
55
- })),
56
- },
57
- null,
58
- 2,
59
- ),
60
- );
61
- // In full mode, we also write the raw witnesses in a more human-readable format.
62
- await fs.writeFile(
63
- path.join(resultsDirectory, 'witnesses.json'),
64
- JSON.stringify(result.executionSteps.map(step => Object.fromEntries(step.witness))),
65
- );
66
- }
67
- logger.info(`Wrote private execution steps to ${resultsDirectory}`);
68
- }