@alejoamiras/aztec-benchmark 0.0.0-canary.g45c0c57
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.
- package/LICENSE +21 -0
- package/README.md +264 -0
- package/action/action.yml +44 -0
- package/action/comparison.cjs +408 -0
- package/action/dist/index.cjs +3 -0
- package/action/index.cjs +93 -0
- package/bin/aztec-benchmark +21 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +147 -0
- package/dist/feeWrappedInteraction.d.ts +35 -0
- package/dist/feeWrappedInteraction.js +62 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +8 -0
- package/dist/profiler.d.ts +32 -0
- package/dist/profiler.js +197 -0
- package/dist/systemInfo.d.ts +15 -0
- package/dist/systemInfo.js +61 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.js +3 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Wonderland
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Aztec Benchmark
|
|
2
|
+
[](https://www.npmjs.com/package/@alejoamiras/aztec-benchmark)
|
|
3
|
+
|
|
4
|
+
**CLI tool and reusable CI workflows for running Aztec contract benchmarks.**
|
|
5
|
+
|
|
6
|
+
Use the CLI to execute benchmark files written in TypeScript. For CI integration, this repository provides **reusable GitHub workflows** that handle the full benchmark-and-compare cycle — including environment setup, baseline management, and PR commenting — so consumer repos can integrate with a single `uses:` line.
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [CLI Usage](#cli-usage)
|
|
12
|
+
- [Configuration (`Nargo.toml`)](#configuration-nargotoml)
|
|
13
|
+
- [Options](#options)
|
|
14
|
+
- [Examples](#examples)
|
|
15
|
+
- [Writing Benchmarks](#writing-benchmarks)
|
|
16
|
+
- [Benchmark Output](#benchmark-output)
|
|
17
|
+
- [Reusable Workflows](#reusable-workflows)
|
|
18
|
+
- [PR Benchmark (`pr-benchmark.yml`)](#pr-benchmark-pr-benchmarkyml)
|
|
19
|
+
- [Update Baseline (`update-baseline.yml`)](#update-baseline-update-baselineyml)
|
|
20
|
+
- [How Baselines Work](#how-baselines-work)
|
|
21
|
+
- [Action Usage (Advanced)](#action-usage-advanced)
|
|
22
|
+
- [Inputs](#inputs)
|
|
23
|
+
- [Outputs](#outputs)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
bun add -D @alejoamiras/aztec-benchmark
|
|
31
|
+
# or
|
|
32
|
+
npm install --save-dev @alejoamiras/aztec-benchmark
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## CLI Usage
|
|
38
|
+
|
|
39
|
+
After installing, run the CLI using `npx aztec-benchmark`. By default, it looks for a `Nargo.toml` file in the current directory and runs benchmarks defined within it.
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
npx aztec-benchmark [options]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Configuration (`Nargo.toml`)
|
|
46
|
+
|
|
47
|
+
Define which contracts have associated benchmark files in your `Nargo.toml` under the `[benchmark]` section:
|
|
48
|
+
|
|
49
|
+
```toml
|
|
50
|
+
[benchmark]
|
|
51
|
+
token = "benchmarks/token_contract.benchmark.ts"
|
|
52
|
+
another_contract = "path/to/another.benchmark.ts"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The paths to the `.benchmark.ts` files are relative to the `Nargo.toml` file.
|
|
56
|
+
|
|
57
|
+
### Options
|
|
58
|
+
|
|
59
|
+
- `-c, --contracts <names...>`: Specify which contracts (keys from the `[benchmark]` section) to run. If omitted, runs all defined benchmarks.
|
|
60
|
+
- `--config <path>`: Path to your `Nargo.toml` file (default: `./Nargo.toml`).
|
|
61
|
+
- `-o, --output-dir <path>`: Directory to save benchmark JSON reports (default: `./benchmarks`).
|
|
62
|
+
- `-s, --suffix <suffix>`: Optional suffix to append to report filenames (e.g., `_pr` results in `token_pr.benchmark.json`).
|
|
63
|
+
- `--skip-proving`: Skip proving transactions. Only measures gate counts and gas; proving time will be `0` in reports. When enabled, the `wallet` is not required in the benchmark context.
|
|
64
|
+
|
|
65
|
+
### Examples
|
|
66
|
+
|
|
67
|
+
Run all benchmarks defined in `./Nargo.toml`:
|
|
68
|
+
```sh
|
|
69
|
+
npx aztec-benchmark
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Run only the `token` benchmark:
|
|
73
|
+
```sh
|
|
74
|
+
npx aztec-benchmark --contracts token
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Run `token` and `another_contract` benchmarks, saving reports with a suffix:
|
|
78
|
+
```sh
|
|
79
|
+
npx aztec-benchmark --contracts token another_contract --output-dir ./benchmark_results --suffix _v2
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Writing Benchmarks
|
|
85
|
+
|
|
86
|
+
Benchmarks are TypeScript classes extending `BenchmarkBase` from this package.
|
|
87
|
+
Each entry in the array returned by `getMethods` can either be a plain `ContractFunctionInteractionCallIntent`
|
|
88
|
+
(in which case the benchmark name is auto-derived) or a `NamedBenchmarkedInteraction` object
|
|
89
|
+
(which includes the `interaction` and a custom `name` for reporting).
|
|
90
|
+
|
|
91
|
+
### Fee Payment
|
|
92
|
+
|
|
93
|
+
By default, every benchmarked account must hold Fee Juice (FJ) to pay for transaction fees. If your accounts don't have pre-existing FJ (e.g. freshly-created accounts on sandbox), you can return a `feePaymentMethod` from `setup()` inside the `BenchmarkContext`. The profiler will pass it to every `send()` and `proveInteraction()` call automatically.
|
|
94
|
+
|
|
95
|
+
The sandbox ships with a canonical `SponsoredFPC` contract that has FJ and can sponsor fees for any account — making it the easiest way to get benchmarks running without bridging from L1.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import {
|
|
99
|
+
Benchmark, // Alias for BenchmarkBase
|
|
100
|
+
type BenchmarkContext,
|
|
101
|
+
type NamedBenchmarkedInteraction
|
|
102
|
+
} from '@alejoamiras/aztec-benchmark';
|
|
103
|
+
import type { PXE } from '@aztec/pxe/server';
|
|
104
|
+
import type { Contract } from '@aztec/aztec.js/contracts'; // Generic Contract type from Aztec.js
|
|
105
|
+
import type { AztecAddress } from '@aztec/aztec.js/addresses';
|
|
106
|
+
import type { ContractFunctionInteractionCallIntent } from '@aztec/aztec.js/authorization';
|
|
107
|
+
import type { FeePaymentMethod } from '@aztec/aztec.js/fee';
|
|
108
|
+
import { createStore } from '@aztec/kv-store/lmdb-v2';
|
|
109
|
+
import { createPXE, getPXEConfig } from '@aztec/pxe/server';
|
|
110
|
+
import { createAztecNodeClient, waitForNode } from '@aztec/aztec.js/node';
|
|
111
|
+
import { EmbeddedWallet } from '@aztec/wallets/embedded';
|
|
112
|
+
import { registerInitialLocalNetworkAccountsInWallet } from '@aztec/wallets/testing';
|
|
113
|
+
// import { YourSpecificContract } from '../artifacts/YourSpecificContract.js'; // Replace with your actual contract artifact
|
|
114
|
+
|
|
115
|
+
// 1. Define a specific context for your benchmark (optional but good practice)
|
|
116
|
+
interface MyBenchmarkContext extends BenchmarkContext {
|
|
117
|
+
pxe: PXE;
|
|
118
|
+
wallet: EmbeddedWallet;
|
|
119
|
+
deployer: AztecAddress;
|
|
120
|
+
contract: Contract; // Use the generic Contract type or your specific contract type
|
|
121
|
+
feePaymentMethod?: FeePaymentMethod;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export default class MyContractBenchmark extends Benchmark {
|
|
125
|
+
// Runs once before all benchmark methods.
|
|
126
|
+
async setup(): Promise<MyBenchmarkContext> {
|
|
127
|
+
console.log('Setting up benchmark environment...');
|
|
128
|
+
|
|
129
|
+
const { NODE_URL = 'http://localhost:8080' } = process.env;
|
|
130
|
+
const node = createAztecNodeClient(NODE_URL);
|
|
131
|
+
await waitForNode(node);
|
|
132
|
+
const l1Contracts = await node.getL1ContractAddresses();
|
|
133
|
+
const config = getPXEConfig();
|
|
134
|
+
const fullConfig = { ...config, l1Contracts };
|
|
135
|
+
// IMPORTANT: true enables proof generation for the benchmark, set it to false when using --skip-proving
|
|
136
|
+
fullConfig.proverEnabled = true;
|
|
137
|
+
// PXE wipes any store whose schema version differs from the running PXE's (Aztec 5.0.0+
|
|
138
|
+
// resets on upgrade) — a hardcoded version can resurrect or mask a stale store, so use a
|
|
139
|
+
// fresh dataDirectory per toolchain version when in doubt.
|
|
140
|
+
const pxeVersion = 2;
|
|
141
|
+
const store = await createStore('pxe', pxeVersion, {
|
|
142
|
+
dataDirectory: 'store',
|
|
143
|
+
dataStoreMapSizeKb: 1e6,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const pxe: PXE = await createPXE(node, fullConfig, { store });
|
|
147
|
+
// `EmbeddedWalletOptions` uses a unified `pxe` field for PXE config and dependency overrides.
|
|
148
|
+
const wallet: EmbeddedWallet = await EmbeddedWallet.create(node, { pxe: fullConfig });
|
|
149
|
+
const accounts: AztecAddress[] = await registerInitialLocalNetworkAccountsInWallet(wallet);
|
|
150
|
+
const [deployer] = accounts;
|
|
151
|
+
|
|
152
|
+
// Deploy your contract (replace YourSpecificContract with your actual contract class).
|
|
153
|
+
// `DeployMethod.send()` now always returns `{ contract, receipt, instance }`.
|
|
154
|
+
const { contract } = await YourSpecificContract
|
|
155
|
+
.deploy(wallet, /* constructor args */)
|
|
156
|
+
.send({ from: deployer });
|
|
157
|
+
console.log('Contract deployed at:', contract.address.toString());
|
|
158
|
+
|
|
159
|
+
// Optional: use SponsoredFPC so accounts don't need pre-existing Fee Juice.
|
|
160
|
+
// The sandbox ships with a canonical SponsoredFPC pre-deployed at a deterministic address.
|
|
161
|
+
//
|
|
162
|
+
// import { SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee/testing';
|
|
163
|
+
// import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC';
|
|
164
|
+
// import { getContractInstanceFromInstantiationParams } from '@aztec/aztec.js/contracts';
|
|
165
|
+
//
|
|
166
|
+
// const instance = await getContractInstanceFromInstantiationParams(
|
|
167
|
+
// SponsoredFPCContract.artifact,
|
|
168
|
+
// { salt: new Fr(0n) },
|
|
169
|
+
// );
|
|
170
|
+
// await wallet.registerContract(instance, SponsoredFPCContract.artifact);
|
|
171
|
+
// const feePaymentMethod = new SponsoredFeePaymentMethod(instance.address);
|
|
172
|
+
|
|
173
|
+
return { pxe, wallet, deployer, contract /*, feePaymentMethod */ };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Returns an array of interactions to benchmark.
|
|
177
|
+
getMethods(context: MyBenchmarkContext): Promise<Array<ContractFunctionInteractionCallIntent | NamedBenchmarkedInteraction>> {
|
|
178
|
+
// Ensure context is available (it should be if setup ran correctly)
|
|
179
|
+
if (!context || !context.contract) {
|
|
180
|
+
// In a real scenario, setup() must initialize the context properly.
|
|
181
|
+
// Throwing an error or returning an empty array might be appropriate here if setup failed.
|
|
182
|
+
console.error("Benchmark context or contract not initialized in setup(). Skipping getMethods.");
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const { contract, deployer } = context;
|
|
187
|
+
const recipient = deployer; // Example recipient
|
|
188
|
+
|
|
189
|
+
// Replace `contract.methods.someMethodName` with actual methods from your contract.
|
|
190
|
+
const interactionPlain = { caller: deployer, action: contract.methods.transfer(recipient, 100n) }
|
|
191
|
+
const interactionNamed1 = { caller: deployer, action: contract.methods.someOtherMethod("test_value_1") };
|
|
192
|
+
const interactionNamed2 = { caller: deployer, action: contract.methods.someOtherMethod("test_value_2") };
|
|
193
|
+
|
|
194
|
+
return [
|
|
195
|
+
// Example of a plain interaction - name will be auto-derived
|
|
196
|
+
interactionPlain,
|
|
197
|
+
// Example of a named interaction
|
|
198
|
+
{ interaction: interactionNamed1, name: "Some Other Method (value 1)" },
|
|
199
|
+
// Another named interaction
|
|
200
|
+
{ interaction: interactionNamed2, name: "Some Other Method (value 2)" },
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Optional cleanup phase
|
|
205
|
+
async teardown(context: MyBenchmarkContext): Promise<void> {
|
|
206
|
+
console.log('Cleaning up benchmark environment...');
|
|
207
|
+
if (context && context.pxe) {
|
|
208
|
+
await context.pxe.stop();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Note:** Your benchmark code needs a valid Aztec project setup to interact with contracts.
|
|
215
|
+
Your `BenchmarkBase` implementation is responsible for constructing the `ContractFunctionInteractionCallIntent` objects.
|
|
216
|
+
If you provide a `NamedBenchmarkedInteraction` object, its `name` field will be used in reports.
|
|
217
|
+
If you provide a plain `ContractFunctionInteractionCallIntent`, the tool will attempt to derive a name from the interaction (e.g., the method name).
|
|
218
|
+
If you return a `feePaymentMethod` in the `BenchmarkContext`, it is automatically passed to every transaction the profiler sends — no changes to `getMethods` are needed.
|
|
219
|
+
|
|
220
|
+
### Usage Example
|
|
221
|
+
|
|
222
|
+
See how this monorepo benchmarks its own contracts in [`packages/aztec-standards/benchmarks`](https://github.com/alejoamiras/ecosystem-tooling/tree/main/packages/aztec-standards/benchmarks).
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Benchmark Output
|
|
227
|
+
|
|
228
|
+
Your `BenchmarkBase` implementation is responsible for measuring and outputting performance data (e.g., as JSON). The comparison action uses this output.
|
|
229
|
+
Each entry in the output will be identified by the custom `name` you provided (if any) or the auto-derived name.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## CI Integration
|
|
234
|
+
|
|
235
|
+
### Inside this monorepo
|
|
236
|
+
|
|
237
|
+
The per-package gates (`aztec-standards.yml`, `aztec-fee-payment.yml`) call the repo's reusable workflows:
|
|
238
|
+
|
|
239
|
+
- **`_pr-benchmark.yml`** — on every PR: runs the suites on the PR head (`--skip-proving`), downloads the `main` baseline artifact, generates a comparison report (regressions beyond 2.5% highlighted), and posts it as a PR comment. Security split: the job executing PR code is read-only; a separate write-permission job posts the comment without executing anything from the PR.
|
|
240
|
+
- **`_update-baseline.yml`** — on pushes to `main` (+ monthly cron via `update-baselines.yml`): refreshes the baseline artifacts (`benchmark-baseline-<package>-main`).
|
|
241
|
+
|
|
242
|
+
Wiring a new package: add a `benchmark` job to its gate workflow:
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
benchmark:
|
|
246
|
+
needs: changes
|
|
247
|
+
if: needs.changes.outputs.relevant == 'true' && github.event_name == 'pull_request'
|
|
248
|
+
permissions:
|
|
249
|
+
contents: read
|
|
250
|
+
pull-requests: write
|
|
251
|
+
issues: write
|
|
252
|
+
actions: read
|
|
253
|
+
uses: ./.github/workflows/_pr-benchmark.yml
|
|
254
|
+
with:
|
|
255
|
+
package-dir: packages/<your-package>
|
|
256
|
+
pr-workflow: <your-package>.yml
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### From other repositories
|
|
260
|
+
|
|
261
|
+
The reusable workflows reference this repo's local `setup-aztec` action, so they are not directly callable cross-repo. External projects have two options:
|
|
262
|
+
|
|
263
|
+
1. **Use the CLI directly** (recommended): install `@alejoamiras/aztec-benchmark` as a devDependency, add a `[benchmark]` table to your `Nargo.toml`, and run `aztec-benchmark --suffix _base` in a job that has an Aztec local network running. The comparison helper is importable as `require('@alejoamiras/aztec-benchmark/action/comparison.cjs')` — see `_pr-benchmark.yml` in this repo as a reference implementation for baselines, comparison and PR comments.
|
|
264
|
+
2. **Vendor the workflows**: copy `_pr-benchmark.yml`, `_update-baseline.yml` and `.github/actions/setup-aztec/` into your repo and adjust `package-dir`.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: 'Generate and Compare Aztec Benchmarks'
|
|
2
|
+
description: 'Generates _latest benchmark reports for all contracts using `aztec-benchmark`, then compares them to _base reports and outputs markdown.'
|
|
3
|
+
inputs:
|
|
4
|
+
# Inputs for Comparison
|
|
5
|
+
threshold:
|
|
6
|
+
description: 'Regression threshold percentage (e.g., 2.5 for 2.5%). Changes above this are marked red.'
|
|
7
|
+
required: false
|
|
8
|
+
default: '2.5' # Default 2.5%
|
|
9
|
+
output_markdown_path:
|
|
10
|
+
description: 'Path where the comparison markdown report will be saved.'
|
|
11
|
+
required: false
|
|
12
|
+
default: 'benchmark-comparison.md'
|
|
13
|
+
base_suffix:
|
|
14
|
+
description: 'Suffix used to identify the base benchmark report files (e.g., contract_name<base_suffix>.benchmark.json).'
|
|
15
|
+
required: false
|
|
16
|
+
default: '_base'
|
|
17
|
+
current_suffix:
|
|
18
|
+
description: 'Suffix used for the current benchmark report files, generated by this action (e.g., contract_name<current_suffix>.benchmark.json).'
|
|
19
|
+
required: false
|
|
20
|
+
default: '_latest'
|
|
21
|
+
config_path:
|
|
22
|
+
description: 'Path to the Nargo.toml configuration file.'
|
|
23
|
+
required: false
|
|
24
|
+
default: './Nargo.toml'
|
|
25
|
+
reports_dir:
|
|
26
|
+
description: 'Directory where benchmark JSON reports are stored and will be generated.'
|
|
27
|
+
required: false
|
|
28
|
+
default: './benchmarks'
|
|
29
|
+
only_report:
|
|
30
|
+
description: 'If true, skips executing the aztec-benchmark CLI and just runs the comparison.'
|
|
31
|
+
required: false
|
|
32
|
+
default: 'false'
|
|
33
|
+
circuit_details:
|
|
34
|
+
description: 'If true, includes per-circuit gate count breakdown in an expandable section below each contract table.'
|
|
35
|
+
required: false
|
|
36
|
+
default: 'false'
|
|
37
|
+
outputs:
|
|
38
|
+
comparison_markdown:
|
|
39
|
+
description: "The generated comparison report in Markdown format."
|
|
40
|
+
markdown_file_path:
|
|
41
|
+
description: "The path to the generated markdown file."
|
|
42
|
+
runs:
|
|
43
|
+
using: 'node20'
|
|
44
|
+
main: 'dist/index.cjs' # Entry point is within the action directory, in the dist subfolder
|