Skip to content

Commit 4589c1c

Browse files
authored
feat: merge-train/fairies (#24833)
BEGIN_COMMIT_OVERRIDE chore: remove obsolete no_predicates wrappers (#7729) (#24050) chore: barebones constants-codegen project (#24687) chore: constants codegen release (#24728) END_COMMIT_OVERRIDE
2 parents eade347 + f6ce986 commit 4589c1c

18 files changed

Lines changed: 636 additions & 105 deletions

Makefile

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ endef
5555

5656
# Fast bootstrap.
5757
fast: release-image barretenberg boxes playground docs aztec-up \
58-
bb-tests l1-contracts-tests yarn-project-tests boxes-tests playground-tests aztec-up-tests docs-tests noir-protocol-circuits-tests contract-snapshots-tests release-image-tests spartan claude-tests ipc-codegen-tests
58+
bb-tests l1-contracts-tests yarn-project-tests boxes-tests playground-tests aztec-up-tests docs-tests noir-protocol-circuits-tests contract-snapshots-tests release-image-tests spartan claude-tests ipc-codegen-tests constants-codegen-tests
5959

6060
# Full bootstrap.
6161
full: fast bb-full-tests bb-cpp-full yarn-project-benches
@@ -294,6 +294,17 @@ bb-tests: bb-cpp-native-tests bb-acir-tests bb-ts-tests bb-sol-tests bb-bbup-tes
294294

295295
bb-full-tests: bb-cpp-wasm-threads-tests bb-cpp-asan-tests bb-cpp-smt-tests
296296

297+
#==============================================================================
298+
# Protocol Constants Codegen
299+
#==============================================================================
300+
301+
.PHONY: constants-codegen constants-codegen-tests
302+
constants-codegen:
303+
$(call build,$@,protocol/constants-codegen)
304+
305+
constants-codegen-tests: constants-codegen
306+
$(call test,$@,protocol/constants-codegen)
307+
297308
#==============================================================================
298309
# IPC Codegen
299310
#==============================================================================
@@ -421,7 +432,7 @@ l1-contracts-tests: l1-contracts-verifier
421432
# Yarn Project - TypeScript monorepo with all TS packages
422433
#==============================================================================
423434

424-
yarn-project: bb-ts noir-projects l1-contracts wsdb bb-avm-sim
435+
yarn-project: bb-ts noir-projects l1-contracts wsdb bb-avm-sim constants-codegen
425436
$(call build,$@,yarn-project)
426437

427438
yarn-project-tests: yarn-project

bootstrap.sh

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ function release {
579579
noir
580580
l1-contracts
581581
noir-projects/aztec-nr
582+
protocol/constants-codegen
582583
yarn-project
583584
boxes
584585
aztec-up
@@ -603,10 +604,11 @@ function release_dryrun {
603604
function private_release {
604605
# Release flow for the private repo, run on a (nightly) ci-private-release PR. We publish only to our
605606
# internal GCP Artifact Registry: the docker image (release-image -> INTERNAL_DOCKER_REGISTRY that
606-
# GKE/staging pulls from) and the npm packages (barretenberg/ts, noir, wsdb, yarn-project -> the
607-
# INTERNAL_NPM_REGISTRY npm repo). We run the release step for real on exactly those components and do
608-
# not invoke the others — the remaining release sources publish public artifacts (github releases,
609-
# crates.io, the aztec-up/playground S3 installers) and are not interrelated with these.
607+
# GKE/staging pulls from) and the npm packages (barretenberg/ts, noir, ipc-runtime, wsdb,
608+
# protocol/constants-codegen, yarn-project -> the INTERNAL_NPM_REGISTRY npm repo). We run the release
609+
# step for real on exactly those components and do not invoke the others — the remaining release
610+
# sources publish public artifacts (github releases, crates.io, the aztec-up/playground S3 installers)
611+
# and are not interrelated with these.
610612
echo_header "private release"
611613

612614
# Default to the private staging Artifact Registry; override via the INTERNAL_*_REGISTRY env vars.
@@ -671,7 +673,7 @@ function private_release {
671673
# them. @aztec/world-state has a runtime dependency on @aztec/wsdb, and the ipc-codegen-generated
672674
# @aztec/wsdb in turn has a runtime dependency on @aztec/ipc-runtime, so ipc-runtime must precede wsdb.
673675
# npm packages are platform-independent, so only the docker image is published on arm64.
674-
local publish=(barretenberg/ts noir ipc-runtime wsdb yarn-project release-image)
676+
local publish=(barretenberg/ts noir ipc-runtime wsdb protocol/constants-codegen yarn-project release-image)
675677
if [ $(arch) == arm64 ]; then
676678
publish=(release-image)
677679
fi
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dest/
2+
node_modules/
3+
.yarn/
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"singleQuote": true,
3+
"trailingComma": "all",
4+
"printWidth": 120,
5+
"arrowParens": "avoid"
6+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodeLinker: node-modules
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Constants codegen
2+
3+
This directory will contain the standalone cross-language generator for Aztec protocol constants.
4+
5+
## Version 1 interface
6+
7+
The command reads a primary Noir source file, optionally adds named constants from other Noir files, and writes any
8+
requested combination of the supported outputs.
9+
10+
```text
11+
constants-codegen \
12+
--input <constants.nr> \
13+
[--include <file.nr>:<symbol>]... \
14+
[--typescript <output.ts>] \
15+
[--cpp <output.hpp>] \
16+
[--pil <output.pil>] \
17+
[--solidity <output.sol>] \
18+
[--rust <output.rs>]
19+
```
20+
21+
- `--input` is required.
22+
- `--include` adds one named constant from another Noir file before evaluating expressions. It may be repeated.
23+
- At least one output option is required, and any combination of output options may be used in one invocation.
24+
- Relative paths are resolved from the caller's working directory. The tool does not infer paths from the monorepo
25+
layout.
26+
- Invalid arguments, an unreadable input, an unsupported expression, or an output failure produce a diagnostic on
27+
stderr and a nonzero exit status.
28+
29+
Version 1 preserves the existing renderer behavior, including each language's current embedded symbol allowlist.
30+
TypeScript emits all parsed constants and domain separators; C++, PIL, and Solidity retain their current selected
31+
subsets and formatting.
32+
33+
Rust emits all parsed constants and domain separators: values that fit `u128` become `pub const NAME: u128` items,
34+
and larger field-sized values become `pub const NAME: &str` hex-string items.
35+
36+
## Compatibility target
37+
38+
The implementation must preserve the symbols and values currently checked in at:
39+
40+
- `yarn-project/constants/src/constants.gen.ts`
41+
- `barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp`
42+
- `barretenberg/cpp/pil/vm2/constants_gen.pil`
43+
- `l1-contracts/src/core/libraries/ConstantsGen.sol`
44+
45+
Generator instructions and formatter-only whitespace may change intentionally.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
source $(git rev-parse --show-toplevel)/ci3/source_bootstrap
4+
5+
hash=$(cache_content_hash .)
6+
7+
# Tests and in-repo generation (remake-constants.sh) run src/*.ts directly via node's built-in type stripping.
8+
# tsc only exists to emit the published npm artifact: node refuses to strip types under node_modules, so the package
9+
# must ship compiled JS. The build step validates that publish path.
10+
function build {
11+
echo_header "constants-codegen build"
12+
npm_install_deps
13+
yarn build
14+
}
15+
16+
function test_cmds {
17+
echo "$hash cd protocol/constants-codegen && node --test src/*.test.ts"
18+
echo "$hash cd protocol/constants-codegen && ./scripts/test-package.sh"
19+
}
20+
21+
function test {
22+
echo_header "constants-codegen test"
23+
test_cmds | filter_test_cmds | parallelize
24+
}
25+
26+
function release {
27+
npm_install_deps
28+
retry "deploy_npm ${REF_NAME#v}"
29+
}
30+
31+
case "$cmd" in
32+
"")
33+
build
34+
;;
35+
hash)
36+
echo "$hash"
37+
;;
38+
*)
39+
default_cmd_handler "$@"
40+
;;
41+
esac
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "@aztec/constants-codegen",
3+
"version": "0.0.0",
4+
"description": "Generate Aztec protocol constants from Noir definitions",
5+
"license": "Apache-2.0",
6+
"type": "module",
7+
"bin": "./dest/cli.js",
8+
"files": [
9+
"dest",
10+
"!dest/*.test.d.ts",
11+
"!dest/*.test.js",
12+
"README.md"
13+
],
14+
"scripts": {
15+
"build": "tsc -p tsconfig.json",
16+
"clean": "rm -rf dest",
17+
"prepack": "yarn build",
18+
"test": "node --test src/*.test.ts && yarn build && ./scripts/test-package.sh"
19+
},
20+
"devDependencies": {
21+
"@types/node": "^22",
22+
"typescript": "^5.7.0"
23+
},
24+
"engines": {
25+
"node": ">=20.10"
26+
},
27+
"packageManager": "yarn@4.13.0",
28+
"publishConfig": {
29+
"access": "public"
30+
}
31+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
package_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
6+
work_dir=$(mktemp -d)
7+
trap 'rm -rf "$work_dir"' EXIT
8+
9+
(cd "$package_dir" && npm pack --ignore-scripts --pack-destination "$work_dir" --quiet >/dev/null)
10+
11+
shopt -s nullglob
12+
tarballs=("$work_dir"/*.tgz)
13+
if [ "${#tarballs[@]}" -ne 1 ]; then
14+
echo "expected npm pack to produce one tarball, found ${#tarballs[@]}" >&2
15+
exit 1
16+
fi
17+
18+
input="$work_dir/constants.nr"
19+
cat > "$input" <<'EOF'
20+
pub global MAX_FIELD_VALUE: Field =
21+
21888242871839275222246405745257275088548364400416034343698204186575808495616;
22+
pub global MAX_ETH_ADDRESS_VALUE: Field = 0xffffffffffffffffffffffffffffffffffffffff;
23+
pub global ARCHIVE_HEIGHT: u32 = 30;
24+
EOF
25+
26+
mkdir "$work_dir/consumer"
27+
(
28+
cd "$work_dir/consumer"
29+
npm init --yes >/dev/null
30+
npm install --ignore-scripts "${tarballs[0]}" >/dev/null
31+
./node_modules/.bin/constants-codegen \
32+
--input "$input" \
33+
--typescript "$work_dir/constants.ts" \
34+
--cpp "$work_dir/constants.hpp" \
35+
--pil "$work_dir/constants.pil" \
36+
--solidity "$work_dir/Constants.sol" \
37+
--rust "$work_dir/constants.rs"
38+
)
39+
40+
function check_output {
41+
if ! grep -Fq "$2" "$work_dir/$1"; then
42+
echo "installed constants-codegen produced unexpected $1:" >&2
43+
cat "$work_dir/$1" >&2
44+
exit 1
45+
fi
46+
}
47+
48+
# Each language receives a different allowlisted subset of the input constants,
49+
# so each check uses a constant known to be in that language's subset.
50+
check_output constants.ts 'export const ARCHIVE_HEIGHT = 30;'
51+
check_output constants.hpp '#define ARCHIVE_HEIGHT 30'
52+
check_output constants.pil 'pol MAX_ETH_ADDRESS_VALUE = 1461501637330902918203684832716283019655932542975;'
53+
check_output Constants.sol 'uint256 internal constant MAX_FIELD_VALUE = 21888242871839275222246405745257275088548364400416034343698204186575808495616;'
54+
check_output constants.rs 'pub const ARCHIVE_HEIGHT: u128 = 30;'
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env node
2+
import { mkdirSync, readFileSync } from 'node:fs';
3+
import { dirname } from 'node:path';
4+
import { parseArgs } from 'node:util';
5+
6+
import {
7+
type ParsedContent,
8+
evaluateExpressions,
9+
generateCppConstants,
10+
generatePilConstants,
11+
generateRustConstants,
12+
generateSolidityConstants,
13+
generateTypescriptConstants,
14+
parseNoirFile,
15+
} from './generator.ts';
16+
17+
type GenerateOutput = (content: ParsedContent, targetPath: string) => void;
18+
19+
interface RequestedOutput {
20+
path: string;
21+
generate: GenerateOutput;
22+
}
23+
24+
function parseIncludedConstant(value: string): { path: string; symbol: string } {
25+
const separatorIndex = value.lastIndexOf(':');
26+
const path = value.slice(0, separatorIndex);
27+
const symbol = value.slice(separatorIndex + 1);
28+
if (separatorIndex <= 0 || !/^\w+$/.test(symbol)) {
29+
throw new Error(`invalid --include value '${value}', expected <file.nr>:<symbol>`);
30+
}
31+
return { path, symbol };
32+
}
33+
34+
function run(args: string[]): void {
35+
const { values } = parseArgs({
36+
args,
37+
allowPositionals: false,
38+
options: {
39+
input: { type: 'string' },
40+
include: { type: 'string', multiple: true },
41+
typescript: { type: 'string' },
42+
cpp: { type: 'string' },
43+
pil: { type: 'string' },
44+
solidity: { type: 'string' },
45+
rust: { type: 'string' },
46+
},
47+
strict: true,
48+
});
49+
50+
if (!values.input) {
51+
throw new Error('--input is required');
52+
}
53+
54+
const outputs = [
55+
values.typescript ? { path: values.typescript, generate: generateTypescriptConstants } : undefined,
56+
values.cpp ? { path: values.cpp, generate: generateCppConstants } : undefined,
57+
values.pil ? { path: values.pil, generate: generatePilConstants } : undefined,
58+
values.solidity ? { path: values.solidity, generate: generateSolidityConstants } : undefined,
59+
values.rust ? { path: values.rust, generate: generateRustConstants } : undefined,
60+
].filter((output): output is RequestedOutput => output !== undefined);
61+
62+
if (outputs.length === 0) {
63+
throw new Error('at least one output option is required');
64+
}
65+
66+
const { constantsExpressions, domainSeparatorEnum } = parseNoirFile(readFileSync(values.input, 'utf8'));
67+
for (const value of values.include ?? []) {
68+
const { path, symbol } = parseIncludedConstant(value);
69+
const { constantsExpressions: includedExpressions } = parseNoirFile(readFileSync(path, 'utf8'), {
70+
stripLineComments: true,
71+
});
72+
const expression = includedExpressions.find(([name]) => name === symbol);
73+
if (!expression) {
74+
throw new Error(`constant '${symbol}' not found in ${path}`);
75+
}
76+
constantsExpressions.push(expression);
77+
}
78+
79+
const parsedContent: ParsedContent = {
80+
constants: evaluateExpressions(constantsExpressions),
81+
domainSeparatorEnum,
82+
};
83+
84+
for (const output of outputs) {
85+
mkdirSync(dirname(output.path), { recursive: true });
86+
output.generate(parsedContent, output.path);
87+
}
88+
}
89+
90+
try {
91+
run(process.argv.slice(2));
92+
} catch (error) {
93+
const message = error instanceof Error ? error.message : String(error);
94+
console.error(`constants-codegen: ${message}`);
95+
process.exitCode = 1;
96+
}

0 commit comments

Comments
 (0)