Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ function release {
noir
l1-contracts
noir-projects/aztec-nr
protocol/constants-codegen
yarn-project
boxes
aztec-up
Expand All @@ -603,10 +604,11 @@ function release_dryrun {
function private_release {
# Release flow for the private repo, run on a (nightly) ci-private-release PR. We publish only to our
# internal GCP Artifact Registry: the docker image (release-image -> INTERNAL_DOCKER_REGISTRY that
# GKE/staging pulls from) and the npm packages (barretenberg/ts, noir, wsdb, yarn-project -> the
# INTERNAL_NPM_REGISTRY npm repo). We run the release step for real on exactly those components and do
# not invoke the others — the remaining release sources publish public artifacts (github releases,
# crates.io, the aztec-up/playground S3 installers) and are not interrelated with these.
# GKE/staging pulls from) and the npm packages (barretenberg/ts, noir, ipc-runtime, wsdb,
# protocol/constants-codegen, yarn-project -> the INTERNAL_NPM_REGISTRY npm repo). We run the release
# step for real on exactly those components and do not invoke the others — the remaining release
# sources publish public artifacts (github releases, crates.io, the aztec-up/playground S3 installers)
# and are not interrelated with these.
echo_header "private release"

# Default to the private staging Artifact Registry; override via the INTERNAL_*_REGISTRY env vars.
Expand Down Expand Up @@ -671,7 +673,7 @@ function private_release {
# them. @aztec/world-state has a runtime dependency on @aztec/wsdb, and the ipc-codegen-generated
# @aztec/wsdb in turn has a runtime dependency on @aztec/ipc-runtime, so ipc-runtime must precede wsdb.
# npm packages are platform-independent, so only the docker image is published on arm64.
local publish=(barretenberg/ts noir ipc-runtime wsdb yarn-project release-image)
local publish=(barretenberg/ts noir ipc-runtime wsdb protocol/constants-codegen yarn-project release-image)
if [ $(arch) == arm64 ]; then
publish=(release-image)
fi
Expand Down
8 changes: 6 additions & 2 deletions protocol/constants-codegen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This directory will contain the standalone cross-language generator for Aztec pr
## Version 1 interface

The command reads a primary Noir source file, optionally adds named constants from other Noir files, and writes any
requested combination of the four outputs produced by the existing generator.
requested combination of the supported outputs.

```text
constants-codegen \
Expand All @@ -14,7 +14,8 @@ constants-codegen \
[--typescript <output.ts>] \
[--cpp <output.hpp>] \
[--pil <output.pil>] \
[--solidity <output.sol>]
[--solidity <output.sol>] \
[--rust <output.rs>]
```

- `--input` is required.
Expand All @@ -29,6 +30,9 @@ Version 1 preserves the existing renderer behavior, including each language's cu
TypeScript emits all parsed constants and domain separators; C++, PIL, and Solidity retain their current selected
subsets and formatting.

Rust emits all parsed constants and domain separators: values that fit `u128` become `pub const NAME: u128` items,
and larger field-sized values become `pub const NAME: &str` hex-string items.

## Compatibility target

The implementation must preserve the symbols and values currently checked in at:
Expand Down
6 changes: 6 additions & 0 deletions protocol/constants-codegen/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ function build {

function test_cmds {
echo "$hash cd protocol/constants-codegen && node --test src/*.test.ts"
echo "$hash cd protocol/constants-codegen && ./scripts/test-package.sh"
}

function test {
echo_header "constants-codegen test"
test_cmds | filter_test_cmds | parallelize
}

function release {
npm_install_deps
retry "deploy_npm ${REF_NAME#v}"
}

case "$cmd" in
"")
build
Expand Down
4 changes: 2 additions & 2 deletions protocol/constants-codegen/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@aztec-foundation/constants-codegen",
"name": "@aztec/constants-codegen",
"version": "0.0.0",
"description": "Generate Aztec protocol constants from Noir definitions",
"license": "Apache-2.0",
Expand All @@ -15,7 +15,7 @@
"build": "tsc -p tsconfig.json",
"clean": "rm -rf dest",
"prepack": "yarn build",
"test": "node --test src/*.test.ts"
"test": "node --test src/*.test.ts && yarn build && ./scripts/test-package.sh"
},
"devDependencies": {
"@types/node": "^22",
Expand Down
54 changes: 54 additions & 0 deletions protocol/constants-codegen/scripts/test-package.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash

set -euo pipefail

package_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
work_dir=$(mktemp -d)
trap 'rm -rf "$work_dir"' EXIT

(cd "$package_dir" && npm pack --ignore-scripts --pack-destination "$work_dir" --quiet >/dev/null)

shopt -s nullglob
tarballs=("$work_dir"/*.tgz)
if [ "${#tarballs[@]}" -ne 1 ]; then
echo "expected npm pack to produce one tarball, found ${#tarballs[@]}" >&2
exit 1
fi

input="$work_dir/constants.nr"
cat > "$input" <<'EOF'
pub global MAX_FIELD_VALUE: Field =
21888242871839275222246405745257275088548364400416034343698204186575808495616;
pub global MAX_ETH_ADDRESS_VALUE: Field = 0xffffffffffffffffffffffffffffffffffffffff;
pub global ARCHIVE_HEIGHT: u32 = 30;
EOF

mkdir "$work_dir/consumer"
(
cd "$work_dir/consumer"
npm init --yes >/dev/null
npm install --ignore-scripts "${tarballs[0]}" >/dev/null
./node_modules/.bin/constants-codegen \
--input "$input" \
--typescript "$work_dir/constants.ts" \
--cpp "$work_dir/constants.hpp" \
--pil "$work_dir/constants.pil" \
--solidity "$work_dir/Constants.sol" \
--rust "$work_dir/constants.rs"
)

function check_output {
if ! grep -Fq "$2" "$work_dir/$1"; then
echo "installed constants-codegen produced unexpected $1:" >&2
cat "$work_dir/$1" >&2
exit 1
fi
}

# Each language receives a different allowlisted subset of the input constants,
# so each check uses a constant known to be in that language's subset.
check_output constants.ts 'export const ARCHIVE_HEIGHT = 30;'
check_output constants.hpp '#define ARCHIVE_HEIGHT 30'
check_output constants.pil 'pol MAX_ETH_ADDRESS_VALUE = 1461501637330902918203684832716283019655932542975;'
check_output Constants.sol 'uint256 internal constant MAX_FIELD_VALUE = 21888242871839275222246405745257275088548364400416034343698204186575808495616;'
check_output constants.rs 'pub const ARCHIVE_HEIGHT: u128 = 30;'
3 changes: 3 additions & 0 deletions protocol/constants-codegen/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
evaluateExpressions,
generateCppConstants,
generatePilConstants,
generateRustConstants,
generateSolidityConstants,
generateTypescriptConstants,
parseNoirFile,
Expand Down Expand Up @@ -41,6 +42,7 @@ function run(args: string[]): void {
cpp: { type: 'string' },
pil: { type: 'string' },
solidity: { type: 'string' },
rust: { type: 'string' },
},
strict: true,
});
Expand All @@ -54,6 +56,7 @@ function run(args: string[]): void {
values.cpp ? { path: values.cpp, generate: generateCppConstants } : undefined,
values.pil ? { path: values.pil, generate: generatePilConstants } : undefined,
values.solidity ? { path: values.solidity, generate: generateSolidityConstants } : undefined,
values.rust ? { path: values.rust, generate: generateRustConstants } : undefined,
].filter((output): output is RequestedOutput => output !== undefined);

if (outputs.length === 0) {
Expand Down
16 changes: 16 additions & 0 deletions protocol/constants-codegen/src/generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
evaluateExpressions,
generateCppConstants,
generatePilConstants,
generateRustConstants,
generateSolidityConstants,
generateTypescriptConstants,
parseNoirFile,
Expand Down Expand Up @@ -66,6 +67,21 @@ test('generates the existing PIL subset', () => {
assert.doesNotMatch(output, /ARCHIVE_HEIGHT/);
});

test('generates Rust constants', () => {
const output = generateToString(generateRustConstants);

assert.match(output, /pub const ARCHIVE_HEIGHT: u128 = 30;/);
assert.match(
output,
/pub const MAX_ETH_ADDRESS_VALUE: &str = "0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff";/,
);
assert.match(
output,
/pub const MAX_FIELD_VALUE: &str = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";/,
);
assert.match(output, /pub const DOM_SEP__MERKLE_HASH: u128 = 2982624097;/);
});

test('generates the existing Solidity subset', () => {
const output = generateToString(generateSolidityConstants);

Expand Down
37 changes: 37 additions & 0 deletions protocol/constants-codegen/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,32 @@ export function processConstantsSolidity(constants: { [key: string]: string }, p
return code.join('\n');
}

/**
* Processes a collection of constants and generates code to export them as Rust constants.
*
* @param constants - An object containing key-value pairs representing constants.
* @param generatorIndices - An object containing key-value pairs representing domain separator indices.
* @returns A string containing code that exports the constants as Rust constants.
*/
export function processConstantsRust(
constants: { [key: string]: string },
generatorIndices: { [key: string]: number },
): string {
const code: string[] = [];
Object.entries(constants).forEach(([key, value]) => {
if (BigInt(value) <= 2n ** 128n - 1n) {
code.push(`pub const ${key}: u128 = ${value};`);
} else {
// Field-sized values exceed u128, so they are emitted as hex strings.
code.push(`pub const ${key}: &str = "0x${BigInt(value).toString(16).padStart(64, '0')}";`);
}
});
Object.entries(generatorIndices).forEach(([key, value]) => {
code.push(`pub const DOM_SEP__${key}: u128 = ${value};`);
});
return code.join('\n');
}

/**
* Generate the constants file in Typescript.
*/
Expand Down Expand Up @@ -537,6 +563,17 @@ ${processConstantsSolidity(constants)}
fs.writeFileSync(targetPath, resultSolidity);
}

/**
* Generate the constants file in Rust.
*/
export function generateRustConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) {
const resultRust: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants
${processConstantsRust(constants, domainSeparatorEnum)}
`;

fs.writeFileSync(targetPath, resultRust);
}

/**
* Parse the content of the constants file in Noir.
*/
Expand Down
4 changes: 2 additions & 2 deletions protocol/constants-codegen/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ __metadata:
version: 8
cacheKey: 10c0

"@aztec-foundation/constants-codegen@workspace:.":
"@aztec/constants-codegen@workspace:.":
version: 0.0.0-use.local
resolution: "@aztec-foundation/constants-codegen@workspace:."
resolution: "@aztec/constants-codegen@workspace:."
dependencies:
"@types/node": "npm:^22"
typescript: "npm:^5.7.0"
Expand Down
Loading