From 2fc31677b2d795757f2246df1764e20297ebfcf2 Mon Sep 17 00:00:00 2001 From: mverzilli Date: Tue, 14 Jul 2026 15:17:38 +0000 Subject: [PATCH 01/12] barebones constants-codegen project --- protocol/constants-codegen/README.md | 39 ++++++++ .../src/scripts/constants.in.test.ts | 94 +++++++++++++++++++ .../constants/src/scripts/constants.in.ts | 30 +++--- 3 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 protocol/constants-codegen/README.md create mode 100644 yarn-project/constants/src/scripts/constants.in.test.ts diff --git a/protocol/constants-codegen/README.md b/protocol/constants-codegen/README.md new file mode 100644 index 000000000000..3f8fd25255a2 --- /dev/null +++ b/protocol/constants-codegen/README.md @@ -0,0 +1,39 @@ +# Constants codegen + +This directory will contain the standalone cross-language generator for Aztec protocol constants. + +## Version 1 interface + +The command reads one Noir source file and writes any requested combination of the four outputs produced by the +existing generator. + +```text +constants-codegen \ + --input \ + [--typescript ] \ + [--cpp ] \ + [--pil ] \ + [--solidity ] +``` + +- `--input` is required. +- At least one output option is required, and any combination of output options may be used in one invocation. +- Relative paths are resolved from the caller's working directory. The tool does not infer paths from the monorepo + layout. +- Invalid arguments, an unreadable input, an unsupported expression, or an output failure produce a diagnostic on + stderr and a nonzero exit status. + +Version 1 preserves the existing renderer behavior, including each language's current embedded symbol allowlist. +TypeScript emits all parsed constants and domain separators; C++, PIL, and Solidity retain their current selected +subsets and formatting. + +## Compatibility target + +The implementation must preserve the symbols and values currently checked in at: + +- `yarn-project/constants/src/constants.gen.ts` +- `barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp` +- `barretenberg/cpp/pil/vm2/constants_gen.pil` +- `l1-contracts/src/core/libraries/ConstantsGen.sol` + +Generator instructions and formatter-only whitespace may change intentionally. diff --git a/yarn-project/constants/src/scripts/constants.in.test.ts b/yarn-project/constants/src/scripts/constants.in.test.ts new file mode 100644 index 000000000000..0e2313726b9d --- /dev/null +++ b/yarn-project/constants/src/scripts/constants.in.test.ts @@ -0,0 +1,94 @@ +import { jest } from '@jest/globals'; +import { mkdtempSync, readFileSync, rmSync } from 'fs'; +import { tmpdir } from 'os'; +import { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; + +import { + type ParsedContent, + evaluateExpressions, + generateCppConstants, + generatePilConstants, + generateSolidityConstants, + generateTypescriptConstants, + parseNoirFile, +} from './constants.in.js'; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const noirConstantsPath = join( + scriptDir, + '../../../../noir-projects/noir-protocol-circuits/crates/types/src/constants.nr', +); + +function parseCurrentNoirConstants(): ParsedContent { + const warning = jest.spyOn(console, 'warn').mockImplementation(() => undefined); + try { + const { constantsExpressions, domainSeparatorEnum } = parseNoirFile(readFileSync(noirConstantsPath, 'utf8')); + return { constants: evaluateExpressions(constantsExpressions), domainSeparatorEnum }; + } finally { + warning.mockRestore(); + } +} + +function generateToString(generate: (content: ParsedContent, targetPath: string) => void): string { + const tempDir = mkdtempSync(join(tmpdir(), 'constants-codegen-')); + const targetPath = join(tempDir, 'output'); + try { + generate(parseCurrentNoirConstants(), targetPath); + return readFileSync(targetPath, 'utf8'); + } finally { + rmSync(tempDir, { recursive: true, force: true }); + } +} + +function normalizeCppFormatting(content: string): string { + return content + .replace(/\\\r?\n\s*/g, ' ') + .split('\n') + .map(line => line.trim().replaceAll(/\s+/g, ' ')) + .join('\n') + .trim(); +} + +function normalizeSolidityFormatting(content: string): string { + return content + .replaceAll(/(?<=\d)_(?=\d)/g, '') + .replaceAll(/\s+/g, ' ') + .trim(); +} + +describe('current constants generator', () => { + it('reproduces the checked-in TypeScript output', () => { + const generated = generateToString(generateTypescriptConstants); + const checkedIn = readFileSync(join(scriptDir, '../constants.gen.ts'), 'utf8'); + + expect(generated).toBe(checkedIn); + }); + + it('reproduces the checked-in C++ symbols and values', () => { + const generated = generateToString(generateCppConstants); + const checkedIn = readFileSync( + join(scriptDir, '../../../../barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp'), + 'utf8', + ); + + expect(normalizeCppFormatting(generated)).toBe(normalizeCppFormatting(checkedIn)); + }); + + it('reproduces the checked-in PIL output', () => { + const generated = generateToString(generatePilConstants); + const checkedIn = readFileSync(join(scriptDir, '../../../../barretenberg/cpp/pil/vm2/constants_gen.pil'), 'utf8'); + + expect(generated).toBe(checkedIn); + }); + + it('reproduces the checked-in Solidity symbols and values', () => { + const generated = generateToString(generateSolidityConstants); + const checkedIn = readFileSync( + join(scriptDir, '../../../../l1-contracts/src/core/libraries/ConstantsGen.sol'), + 'utf8', + ); + + expect(normalizeSolidityFormatting(generated)).toBe(normalizeSolidityFormatting(checkedIn)); + }); +}); diff --git a/yarn-project/constants/src/scripts/constants.in.ts b/yarn-project/constants/src/scripts/constants.in.ts index c5df26e3385f..a42ddb05ec3f 100644 --- a/yarn-project/constants/src/scripts/constants.in.ts +++ b/yarn-project/constants/src/scripts/constants.in.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import { dirname, join } from 'path'; -import { fileURLToPath } from 'url'; +import { fileURLToPath, pathToFileURL } from 'url'; const NOIR_CONSTANTS_FILE = '../../../../noir-projects/noir-protocol-circuits/crates/types/src/constants.nr'; const TS_CONSTANTS_FILE = '../constants.gen.ts'; @@ -365,7 +365,7 @@ const SOLIDITY_CONSTANTS = [ /** * Parsed content. */ -interface ParsedContent { +export interface ParsedContent { /** * Constants of the form "CONSTANT_NAME: number_as_string". */ @@ -397,7 +397,7 @@ interface ParsedExpressions { * @param constants - An object containing key-value pairs representing constants. * @returns A string containing code that exports the constants as TypeScript constants. */ -function processConstantsTS(constants: { [key: string]: string }): string { +export function processConstantsTS(constants: { [key: string]: string }): string { const code: string[] = []; Object.entries(constants).forEach(([key, value]) => { code.push(`export const ${key} = ${+value > Number.MAX_SAFE_INTEGER ? value + 'n' : value};`); @@ -412,7 +412,7 @@ function processConstantsTS(constants: { [key: string]: string }): string { * @param constants - An object containing key-value pairs representing constants. * @returns A string containing code that exports the constants as cpp constants. */ -function processConstantsCpp( +export function processConstantsCpp( constants: { [key: string]: string }, generatorIndices: { [key: string]: number }, ): string { @@ -443,7 +443,7 @@ function processConstantsCpp( * @param constants - An object containing key-value pairs representing constants. * @returns A string containing code that exports the constants as cpp constants. */ -function processConstantsPil( +export function processConstantsPil( constants: { [key: string]: string }, generatorIndices: { [key: string]: number }, ): string { @@ -468,7 +468,7 @@ function processConstantsPil( * @param enumValues - An object containing key-value pairs representing enum values. * @returns A string containing code that exports the enum as a TypeScript enum. */ -function processEnumTS(enumName: string, enumValues: { [key: string]: number }): string { +export function processEnumTS(enumName: string, enumValues: { [key: string]: number }): string { const code: string[] = []; code.push(`export enum ${enumName} {`); @@ -489,7 +489,7 @@ function processEnumTS(enumName: string, enumValues: { [key: string]: number }): * @param prefix - A prefix to add to the constant names. * @returns A string containing code that exports the constants as Noir constants. */ -function processConstantsSolidity(constants: { [key: string]: string }, prefix = ''): string { +export function processConstantsSolidity(constants: { [key: string]: string }, prefix = ''): string { const code: string[] = []; Object.entries(constants).forEach(([key, value]) => { if (SOLIDITY_CONSTANTS.includes(key)) { @@ -502,7 +502,7 @@ function processConstantsSolidity(constants: { [key: string]: string }, prefix = /** * Generate the constants file in Typescript. */ -function generateTypescriptConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { +export function generateTypescriptConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { const result = [ '// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants', processConstantsTS(constants), @@ -515,7 +515,7 @@ function generateTypescriptConstants({ constants, domainSeparatorEnum }: ParsedC /** * Generate the constants file in C++. */ -function generateCppConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { +export function generateCppConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { const resultCpp: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants #pragma once @@ -528,7 +528,7 @@ ${processConstantsCpp(constants, domainSeparatorEnum)} /** * Generate the constants file in PIL. */ -function generatePilConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { +export function generatePilConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { const resultPil: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants namespace constants; ${processConstantsPil(constants, domainSeparatorEnum)} @@ -540,7 +540,7 @@ ${processConstantsPil(constants, domainSeparatorEnum)} /** * Generate the constants file in Solidity. */ -function generateSolidityConstants({ constants }: ParsedContent, targetPath: string) { +export function generateSolidityConstants({ constants }: ParsedContent, targetPath: string) { const resultSolidity: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants // SPDX-License-Identifier: Apache-2.0 // Copyright 2023 Aztec Labs. @@ -565,7 +565,7 @@ ${processConstantsSolidity(constants)} /** * Parse the content of the constants file in Noir. */ -function parseNoirFile( +export function parseNoirFile( fileContent: string, { stripLineComments = false }: { stripLineComments?: boolean } = {}, ): ParsedExpressions { @@ -640,7 +640,7 @@ function parseNoirFile( * For example: "CONSTANT_NAME: 2 + 2" or "CONSTANT_NAME: CONSTANT_A * CONSTANT_B". * @returns Parsed expressions of the form: "CONSTANT_NAME: number_as_string". */ -function evaluateExpressions(expressions: [string, string][]): { [key: string]: string } { +export function evaluateExpressions(expressions: [string, string][]): { [key: string]: string } { const constants: { [key: string]: string } = {}; const knownBigInts = ['AZTEC_EPOCH_DURATION', 'FEE_RECIPIENT_LENGTH']; @@ -739,4 +739,6 @@ function main(): void { generateSolidityConstants(parsedContent, solidityTargetPath); } -main(); +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + main(); +} From 2a5d95f05ae968af8d3e1107919551743290bafb Mon Sep 17 00:00:00 2001 From: mverzilli Date: Tue, 14 Jul 2026 16:08:45 +0000 Subject: [PATCH 02/12] npm package shell --- protocol/constants-codegen/.gitignore | 3 + protocol/constants-codegen/.yarnrc.yml | 1 + protocol/constants-codegen/package.json | 30 + protocol/constants-codegen/src/cli.ts | 65 ++ .../constants-codegen/src/generator.test.ts | 95 +++ protocol/constants-codegen/src/generator.ts | 648 ++++++++++++++++++ protocol/constants-codegen/tsconfig.json | 17 + protocol/constants-codegen/yarn.lock | 53 ++ 8 files changed, 912 insertions(+) create mode 100644 protocol/constants-codegen/.gitignore create mode 100644 protocol/constants-codegen/.yarnrc.yml create mode 100644 protocol/constants-codegen/package.json create mode 100644 protocol/constants-codegen/src/cli.ts create mode 100644 protocol/constants-codegen/src/generator.test.ts create mode 100644 protocol/constants-codegen/src/generator.ts create mode 100644 protocol/constants-codegen/tsconfig.json create mode 100644 protocol/constants-codegen/yarn.lock diff --git a/protocol/constants-codegen/.gitignore b/protocol/constants-codegen/.gitignore new file mode 100644 index 000000000000..bcc6a6c061de --- /dev/null +++ b/protocol/constants-codegen/.gitignore @@ -0,0 +1,3 @@ +dest/ +node_modules/ +.yarn/ diff --git a/protocol/constants-codegen/.yarnrc.yml b/protocol/constants-codegen/.yarnrc.yml new file mode 100644 index 000000000000..3186f3f0795a --- /dev/null +++ b/protocol/constants-codegen/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/protocol/constants-codegen/package.json b/protocol/constants-codegen/package.json new file mode 100644 index 000000000000..3f0cb7286771 --- /dev/null +++ b/protocol/constants-codegen/package.json @@ -0,0 +1,30 @@ +{ + "name": "@aztec-foundation/constants-codegen", + "version": "0.0.0", + "description": "Generate Aztec protocol constants from Noir definitions", + "license": "Apache-2.0", + "type": "module", + "bin": "./dest/cli.js", + "files": [ + "dest", + "!dest/*.test.d.ts", + "!dest/*.test.js", + "README.md" + ], + "scripts": { + "build": "tsc -p tsconfig.json", + "clean": "rm -rf dest", + "test": "yarn build && node --test dest/*.test.js" + }, + "devDependencies": { + "@types/node": "^22", + "typescript": "^5.6.3" + }, + "engines": { + "node": ">=20.10" + }, + "packageManager": "yarn@4.13.0", + "publishConfig": { + "access": "public" + } +} diff --git a/protocol/constants-codegen/src/cli.ts b/protocol/constants-codegen/src/cli.ts new file mode 100644 index 000000000000..985a64e11eb0 --- /dev/null +++ b/protocol/constants-codegen/src/cli.ts @@ -0,0 +1,65 @@ +#!/usr/bin/env node +import { mkdirSync, readFileSync } from 'node:fs'; +import { dirname } from 'node:path'; +import { parseArgs } from 'node:util'; + +import { + type ParsedContent, + generateCppConstants, + generatePilConstants, + generateSolidityConstants, + generateTypescriptConstants, + parseNoirFile, +} from './generator.js'; + +type GenerateOutput = (content: ParsedContent, targetPath: string) => void; + +interface RequestedOutput { + path: string; + generate: GenerateOutput; +} + +function run(args: string[]): void { + const { values } = parseArgs({ + args, + allowPositionals: false, + options: { + input: { type: 'string' }, + typescript: { type: 'string' }, + cpp: { type: 'string' }, + pil: { type: 'string' }, + solidity: { type: 'string' }, + }, + strict: true, + }); + + if (!values.input) { + throw new Error('--input is required'); + } + + const outputs = [ + values.typescript ? { path: values.typescript, generate: generateTypescriptConstants } : undefined, + values.cpp ? { path: values.cpp, generate: generateCppConstants } : undefined, + values.pil ? { path: values.pil, generate: generatePilConstants } : undefined, + values.solidity ? { path: values.solidity, generate: generateSolidityConstants } : undefined, + ].filter((output): output is RequestedOutput => output !== undefined); + + if (outputs.length === 0) { + throw new Error('at least one output option is required'); + } + + const parsedContent = parseNoirFile(readFileSync(values.input, 'utf8')); + + for (const output of outputs) { + mkdirSync(dirname(output.path), { recursive: true }); + output.generate(parsedContent, output.path); + } +} + +try { + run(process.argv.slice(2)); +} catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.error(`constants-codegen: ${message}`); + process.exitCode = 1; +} diff --git a/protocol/constants-codegen/src/generator.test.ts b/protocol/constants-codegen/src/generator.test.ts new file mode 100644 index 000000000000..e1a171bef2ab --- /dev/null +++ b/protocol/constants-codegen/src/generator.test.ts @@ -0,0 +1,95 @@ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { test } from 'node:test'; +import { fileURLToPath } from 'node:url'; + +import { + type ParsedContent, + generateCppConstants, + generatePilConstants, + generateSolidityConstants, + generateTypescriptConstants, + parseNoirFile, +} from './generator.js'; + +const noirFixture = ` +pub global MAX_FIELD_VALUE: Field = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; +pub global MAX_ETH_ADDRESS_VALUE: Field = 0xffffffffffffffffffffffffffffffffffffffff; +pub global ARCHIVE_HEIGHT: u32 = 30; +pub global DOM_SEP__MERKLE_HASH: u32 = 2982624097; +`; + +function generateToString(generate: (content: ParsedContent, targetPath: string) => void): string { + const tempDir = mkdtempSync(join(tmpdir(), 'constants-codegen-')); + const targetPath = join(tempDir, 'output'); + try { + generate(parseNoirFile(noirFixture), targetPath); + return readFileSync(targetPath, 'utf8'); + } finally { + rmSync(tempDir, { recursive: true, force: true }); + } +} + +test('generates TypeScript constants and domain separators', () => { + assert.equal( + generateToString(generateTypescriptConstants), + `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants +export const MAX_FIELD_VALUE = 21888242871839275222246405745257275088548364400416034343698204186575808495616n; +export const MAX_ETH_ADDRESS_VALUE = 1461501637330902918203684832716283019655932542975n; +export const ARCHIVE_HEIGHT = 30; +export enum DomainSeparator { + MERKLE_HASH = 2982624097, +}`, + ); +}); + +test('generates the existing C++ subset', () => { + const output = generateToString(generateCppConstants); + + assert.match(output, /#define MAX_ETH_ADDRESS_VALUE "0x0{24}f{40}"/); + assert.match(output, /#define ARCHIVE_HEIGHT 30/); + assert.match(output, /#define DOM_SEP__MERKLE_HASH 2982624097UL/); + assert.doesNotMatch(output, /MAX_FIELD_VALUE/); +}); + +test('generates the existing PIL subset', () => { + const output = generateToString(generatePilConstants); + + assert.match(output, /pol MAX_ETH_ADDRESS_VALUE = 1461501637330902918203684832716283019655932542975;/); + assert.match(output, /pol DOM_SEP__MERKLE_HASH = 2982624097;/); + assert.doesNotMatch(output, /ARCHIVE_HEIGHT/); +}); + +test('generates the existing Solidity subset', () => { + const output = generateToString(generateSolidityConstants); + + assert.match( + output, + /uint256 internal constant MAX_FIELD_VALUE = 21888242871839275222246405745257275088548364400416034343698204186575808495616;/, + ); + assert.doesNotMatch(output, /ARCHIVE_HEIGHT/); +}); + +test('the CLI generates multiple requested outputs', () => { + const tempDir = mkdtempSync(join(tmpdir(), 'constants-codegen-cli-')); + const inputPath = join(tempDir, 'constants.nr'); + const typescriptPath = join(tempDir, 'typescript', 'constants.ts'); + const cppPath = join(tempDir, 'cpp', 'constants.hpp'); + const cliPath = join(dirname(fileURLToPath(import.meta.url)), 'cli.js'); + + try { + writeFileSync(inputPath, noirFixture); + execFileSync(process.execPath, [cliPath, '--input', inputPath, '--typescript', typescriptPath, '--cpp', cppPath], { + stdio: 'pipe', + }); + + assert.match(readFileSync(typescriptPath, 'utf8'), /export const ARCHIVE_HEIGHT = 30;/); + assert.match(readFileSync(cppPath, 'utf8'), /#define ARCHIVE_HEIGHT 30/); + } finally { + rmSync(tempDir, { recursive: true, force: true }); + } +}); diff --git a/protocol/constants-codegen/src/generator.ts b/protocol/constants-codegen/src/generator.ts new file mode 100644 index 000000000000..8503dcdcede8 --- /dev/null +++ b/protocol/constants-codegen/src/generator.ts @@ -0,0 +1,648 @@ +import * as fs from 'node:fs'; + +// Whitelist of constants that will be copied to aztec_constants.hpp. +// We don't copy everything as just a handful are needed, and updating them breaks the cache and triggers expensive bb builds. +const CPP_CONSTANTS = [ + 'MAX_ETH_ADDRESS_BIT_SIZE', + 'MAX_ETH_ADDRESS_VALUE', + 'GENESIS_BLOCK_HEADER_HASH', + 'GENESIS_ARCHIVE_ROOT', + 'MEM_TAG_U1', + 'MEM_TAG_U8', + 'MEM_TAG_U16', + 'MEM_TAG_U32', + 'MEM_TAG_U64', + 'MEM_TAG_U128', + 'MEM_TAG_FF', + 'MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS', + 'CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS', + 'CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS', + 'FEE_JUICE_ADDRESS', + 'TX_DA_GAS_OVERHEAD', + 'FEE_JUICE_BALANCES_SLOT', + 'UPDATED_CLASS_IDS_SLOT', + 'UPDATES_DELAYED_PUBLIC_MUTABLE_VALUES_LEN', + 'PUBLIC_DATA_TREE_HEIGHT', + 'NULLIFIER_TREE_HEIGHT', + 'NULLIFIER_SUBTREE_HEIGHT', + 'NOTE_HASH_TREE_HEIGHT', + 'L1_TO_L2_MSG_TREE_HEIGHT', + 'ARCHIVE_HEIGHT', + 'TIMESTAMP_OF_CHANGE_BIT_SIZE', + 'UPDATES_DELAYED_PUBLIC_MUTABLE_METADATA_BIT_SIZE', + 'MAX_ENQUEUED_CALLS_PER_TX', + 'MAX_NOTE_HASHES_PER_TX', + 'MAX_NULLIFIERS_PER_TX', + 'MAX_L2_TO_L1_MSGS_PER_TX', + 'MAX_PROCESSABLE_L2_GAS', + 'MAX_PUBLIC_LOGS_PER_TX', + 'MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', + 'MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS', + 'MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', + 'MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_CHAIN_ID_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_VERSION_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_BLOCK_NUMBER_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_SLOT_NUMBER_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_TIMESTAMP_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_COINBASE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_FEE_RECIPIENT_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_GAS_FEES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PROTOCOL_CONTRACTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_GAS_USED_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GAS_SETTINGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_FEE_PAYER_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PUBLIC_SETUP_CALL_REQUESTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PUBLIC_APP_LOGIC_CALL_REQUESTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PUBLIC_TEARDOWN_CALL_REQUEST_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_GAS_USED_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NOTE_HASHES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NULLIFIERS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_L2_TO_L1_MSGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_LOGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_DATA_WRITES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_LOGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_DATA_WRITES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_TRANSACTION_FEE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX', + 'AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH', + 'AVM_NUM_PUBLIC_INPUT_COLUMNS', + 'AVM_PUBLIC_INPUTS_COLUMNS_COMBINED_LENGTH', + 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_HEIGHT', + 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_ROOT', + 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_SIZE', + 'NOTE_HASH_TREE_LEAF_COUNT', + 'L1_TO_L2_MSG_TREE_LEAF_COUNT', + 'FLAT_PUBLIC_LOGS_HEADER_LENGTH', + 'FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH', + 'PUBLIC_LOGS_LENGTH', + 'PUBLIC_LOG_HEADER_LENGTH', + 'MAX_PUBLIC_LOG_SIZE_IN_FIELDS', + 'PUBLIC_TX_L2_GAS_OVERHEAD', + 'MAX_PROTOCOL_CONTRACTS', + 'DEFAULT_MAX_DEBUG_LOG_MEMORY_READS', +]; + +const CPP_GENERATORS: string[] = [ + 'BLOCK_HEADER_HASH', + 'SALTED_INITIALIZATION_HASH', + 'PARTIAL_ADDRESS', + 'CONTRACT_ADDRESS_V2', + 'CONTRACT_CLASS_ID', + 'PUBLIC_KEYS_HASH', + 'SINGLE_PUBLIC_KEY_HASH', + 'NOTE_HASH_NONCE', + 'UNIQUE_NOTE_HASH', + 'SILOED_NOTE_HASH', + 'SILOED_NULLIFIER', + 'PUBLIC_LEAF_SLOT', + 'PUBLIC_STORAGE_MAP_SLOT', + 'PUBLIC_CALLDATA', + 'PUBLIC_BYTECODE', + 'MERKLE_HASH', + 'NULLIFIER_MERKLE', + 'PUBLIC_DATA_MERKLE', + 'WRITTEN_SLOTS_MERKLE', + 'RETRIEVED_BYTECODES_MERKLE', +]; + +const PIL_CONSTANTS = [ + 'MAX_ETH_ADDRESS_VALUE', + 'MEM_TAG_U1', + 'MEM_TAG_U8', + 'MEM_TAG_U16', + 'MEM_TAG_U32', + 'MEM_TAG_U64', + 'MEM_TAG_U128', + 'MEM_TAG_FF', + 'AVM_BITWISE_AND_OP_ID', + 'AVM_BITWISE_OR_OP_ID', + 'AVM_BITWISE_XOR_OP_ID', + 'AVM_KECCAKF1600_NUM_ROUNDS', + 'AVM_KECCAKF1600_STATE_SIZE', + 'AVM_TX_PHASE_VALUE_START', + 'AVM_TX_PHASE_VALUE_SETUP', + 'AVM_TX_PHASE_VALUE_LAST', + 'AVM_HIGHEST_MEM_ADDRESS', + 'AVM_MEMORY_NUM_BITS', + 'AVM_MEMORY_SIZE', + 'MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS', + 'MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', + 'MAX_NOTE_HASHES_PER_TX', + 'GRUMPKIN_ONE_X', + 'GRUMPKIN_ONE_Y', + 'AVM_PC_SIZE_IN_BITS', + 'PUBLIC_DATA_TREE_HEIGHT', + 'NULLIFIER_TREE_HEIGHT', + 'NOTE_HASH_TREE_HEIGHT', + 'L1_TO_L2_MSG_TREE_HEIGHT', + 'UPDATED_CLASS_IDS_SLOT', + 'UPDATES_DELAYED_PUBLIC_MUTABLE_VALUES_LEN', + 'CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS', + 'CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS', + 'FEE_JUICE_ADDRESS', + 'FEE_JUICE_BALANCES_SLOT', + 'TIMESTAMP_OF_CHANGE_BIT_SIZE', + 'UPDATES_DELAYED_PUBLIC_MUTABLE_METADATA_BIT_SIZE', + 'UPDATES_SHARED_MUTABLE_METADATA_BIT_SIZE', + 'MAX_ENQUEUED_CALLS_PER_TX', + 'MAX_NOTE_HASHES_PER_TX', + 'MAX_NULLIFIERS_PER_TX', + 'MAX_L2_TO_L1_MSGS_PER_TX', + 'MAX_PUBLIC_LOGS_PER_TX', + 'MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS', + 'MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', + 'MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_CHAIN_ID_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_VERSION_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_BLOCK_NUMBER_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_SLOT_NUMBER_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_TIMESTAMP_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_COINBASE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_FEE_RECIPIENT_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_GAS_FEES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PROTOCOL_CONTRACTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_START_GAS_USED_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GAS_SETTINGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GAS_SETTINGS_GAS_LIMITS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_GAS_SETTINGS_TEARDOWN_GAS_LIMITS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_FEE_PAYER_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PUBLIC_SETUP_CALL_REQUESTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PUBLIC_APP_LOGIC_CALL_REQUESTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PUBLIC_TEARDOWN_CALL_REQUEST_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_END_GAS_USED_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NOTE_HASHES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NULLIFIERS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_L2_TO_L1_MSGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_LOGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_DATA_WRITES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_LOGS_ROW_IDX', + 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_DATA_WRITES_ROW_IDX', + 'AVM_PUBLIC_INPUTS_TRANSACTION_FEE_ROW_IDX', + 'AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX', + 'AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH', + 'AVM_NUM_PUBLIC_INPUT_COLUMNS', + 'AVM_PUBLIC_INPUTS_COLUMNS_COMBINED_LENGTH', + 'AVM_SUBTRACE_ID_EXECUTION', + 'AVM_SUBTRACE_ID_ALU', + 'AVM_SUBTRACE_ID_CAST', + 'AVM_SUBTRACE_ID_SET', + 'AVM_SUBTRACE_ID_BITWISE', + 'AVM_SUBTRACE_ID_POSEIDON2_PERM', + 'AVM_SUBTRACE_ID_TO_RADIX', + 'AVM_SUBTRACE_ID_ECC', + 'AVM_SUBTRACE_ID_KECCAKF1600', + 'AVM_SUBTRACE_ID_CALLDATA_COPY', + 'AVM_SUBTRACE_ID_SHA256_COMPRESSION', + 'AVM_SUBTRACE_ID_RETURNDATA_COPY', + 'AVM_DYN_GAS_ID_CALLDATACOPY', + 'AVM_DYN_GAS_ID_RETURNDATACOPY', + 'AVM_DYN_GAS_ID_TORADIX', + 'AVM_DYN_GAS_ID_BITWISE', + 'AVM_DYN_GAS_ID_EMITPUBLICLOG', + 'AVM_DYN_GAS_ID_SSTORE', + 'AVM_SUBTRACE_ID_GETCONTRACTINSTANCE', + 'AVM_SUBTRACE_ID_EMITPUBLICLOG', + 'AVM_EXEC_OP_ID_GETENVVAR', + 'AVM_EXEC_OP_ID_MOV', + 'AVM_EXEC_OP_ID_JUMP', + 'AVM_EXEC_OP_ID_JUMPI', + 'AVM_EXEC_OP_ID_CALL', + 'AVM_EXEC_OP_ID_STATICCALL', + 'AVM_EXEC_OP_ID_INTERNALCALL', + 'AVM_EXEC_OP_ID_INTERNALRETURN', + 'AVM_EXEC_OP_ID_RETURN', + 'AVM_EXEC_OP_ID_REVERT', + 'AVM_EXEC_OP_ID_SUCCESSCOPY', + 'AVM_EXEC_OP_ID_ALU_ADD', + 'AVM_EXEC_OP_ID_ALU_SUB', + 'AVM_EXEC_OP_ID_ALU_MUL', + 'AVM_EXEC_OP_ID_ALU_DIV', + 'AVM_EXEC_OP_ID_ALU_FDIV', + 'AVM_EXEC_OP_ID_ALU_EQ', + 'AVM_EXEC_OP_ID_ALU_LT', + 'AVM_EXEC_OP_ID_ALU_LTE', + 'AVM_EXEC_OP_ID_ALU_NOT', + 'AVM_EXEC_OP_ID_ALU_SHL', + 'AVM_EXEC_OP_ID_ALU_SHR', + 'AVM_EXEC_OP_ID_ALU_TRUNCATE', + 'AVM_EXEC_OP_ID_RETURNDATASIZE', + 'AVM_EXEC_OP_ID_DEBUGLOG', + 'AVM_EXEC_OP_ID_SLOAD', + 'AVM_EXEC_OP_ID_SSTORE', + 'AVM_EXEC_OP_ID_NOTEHASH_EXISTS', + 'AVM_EXEC_OP_ID_EMIT_NOTEHASH', + 'AVM_EXEC_OP_ID_L1_TO_L2_MESSAGE_EXISTS', + 'AVM_EXEC_OP_ID_NULLIFIER_EXISTS', + 'AVM_EXEC_OP_ID_EMIT_NULLIFIER', + 'AVM_EXEC_OP_ID_SENDL2TOL1MSG', + 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_HEIGHT', + 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_ROOT', + 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_SIZE', + 'AVM_RETRIEVED_BYTECODES_TREE_HEIGHT', + 'AVM_RETRIEVED_BYTECODES_TREE_INITIAL_ROOT', + 'AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE', + 'NOTE_HASH_TREE_LEAF_COUNT', + 'L1_TO_L2_MSG_TREE_LEAF_COUNT', + 'FLAT_PUBLIC_LOGS_HEADER_LENGTH', + 'FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH', + 'PUBLIC_LOGS_LENGTH', + 'PUBLIC_LOG_HEADER_LENGTH', + 'MAX_PROTOCOL_CONTRACTS', +]; + +const PIL_GENERATORS: string[] = [ + 'SALTED_INITIALIZATION_HASH', + 'PARTIAL_ADDRESS', + 'CONTRACT_ADDRESS_V2', + 'CONTRACT_CLASS_ID', + 'PUBLIC_KEYS_HASH', + 'SINGLE_PUBLIC_KEY_HASH', + 'NOTE_HASH_NONCE', + 'UNIQUE_NOTE_HASH', + 'SILOED_NOTE_HASH', + 'SILOED_NULLIFIER', + 'PUBLIC_LEAF_SLOT', + 'PUBLIC_STORAGE_MAP_SLOT', + 'PUBLIC_CALLDATA', + 'PUBLIC_BYTECODE', + 'MERKLE_HASH', + 'NULLIFIER_MERKLE', + 'PUBLIC_DATA_MERKLE', + 'WRITTEN_SLOTS_MERKLE', + 'RETRIEVED_BYTECODES_MERKLE', +]; + +const SOLIDITY_CONSTANTS = [ + 'MAX_FIELD_VALUE', + 'MAX_L2_TO_L1_MSGS_PER_TX', + 'EMPTY_EPOCH_OUT_HASH', + 'L1_TO_L2_MSG_SUBTREE_HEIGHT', + 'NUM_MSGS_PER_BASE_PARITY', + 'NUM_BASE_PARITY_PER_ROOT_PARITY', + 'BLS12_POINT_COMPRESSED_BYTES', + 'ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH', + 'INITIAL_CHECKPOINT_NUMBER', + 'GENESIS_ARCHIVE_ROOT', + 'FEE_JUICE_ADDRESS', + 'MAX_CHECKPOINTS_PER_EPOCH', +]; + +/** + * Parsed content. + */ +export interface ParsedContent { + /** + * Constants of the form "CONSTANT_NAME: number_as_string". + */ + constants: { [key: string]: string }; + /** + * DomainSeparatorEnum. + */ + domainSeparatorEnum: { [key: string]: number }; +} + +/** + * Processes a collection of constants and generates code to export them as TypeScript constants. + * + * @param constants - An object containing key-value pairs representing constants. + * @returns A string containing code that exports the constants as TypeScript constants. + */ +export function processConstantsTS(constants: { [key: string]: string }): string { + const code: string[] = []; + Object.entries(constants).forEach(([key, value]) => { + code.push(`export const ${key} = ${+value > Number.MAX_SAFE_INTEGER ? value + 'n' : value};`); + }); + return code.join('\n'); +} + +/** + * Processes a collection of constants and generates code to export them as cpp constants. + * Required to ensure consistency between the constants used in pil and used in the vm witness generator. + * + * @param constants - An object containing key-value pairs representing constants. + * @returns A string containing code that exports the constants as cpp constants. + */ +export function processConstantsCpp( + constants: { [key: string]: string }, + generatorIndices: { [key: string]: number }, +): string { + const code: string[] = []; + Object.entries(constants).forEach(([key, value]) => { + if (CPP_CONSTANTS.includes(key) || key.startsWith('AVM_')) { + if (BigInt(value) <= 2n ** 31n - 1n) { + code.push(`#define ${key} ${value}`); + } else if (BigInt(value) <= 2n ** 64n - 1n) { + code.push(`#define ${key} 0x${BigInt(value).toString(16)}`); // hex literals + } else { + code.push(`#define ${key} "0x${BigInt(value).toString(16).padStart(64, '0')}"`); // stringify large numbers + } + } + }); + Object.entries(generatorIndices).forEach(([key, value]) => { + if (CPP_GENERATORS.includes(key)) { + code.push(`#define DOM_SEP__${key} ${value}UL`); + } + }); + return code.join('\n'); +} + +/** + * Processes a collection of constants and generates code to export them as PIL constants. + * Required to ensure consistency between the constants used in pil and used in the vm witness generator. + * + * @param constants - An object containing key-value pairs representing constants. + * @returns A string containing code that exports the constants as cpp constants. + */ +export function processConstantsPil( + constants: { [key: string]: string }, + generatorIndices: { [key: string]: number }, +): string { + const code: string[] = []; + Object.entries(constants).forEach(([key, value]) => { + if (PIL_CONSTANTS.includes(key)) { + code.push(` pol ${key} = ${value};`); + } + }); + Object.entries(generatorIndices).forEach(([key, value]) => { + if (PIL_GENERATORS.includes(key)) { + code.push(` pol DOM_SEP__${key} = ${value};`); + } + }); + + return code.join('\n'); +} +/** + * Processes an enum and generates code to export it as a TypeScript enum. + * + * @param enumName - The name of the enum. + * @param enumValues - An object containing key-value pairs representing enum values. + * @returns A string containing code that exports the enum as a TypeScript enum. + */ +export function processEnumTS(enumName: string, enumValues: { [key: string]: number }): string { + const code: string[] = []; + + code.push(`export enum ${enumName} {`); + + Object.entries(enumValues).forEach(([key, value]) => { + code.push(` ${key} = ${value},`); + }); + + code.push('}'); + + return code.join('\n'); +} + +/** + * Processes a collection of constants and generates code to export them as Solidity constants. + * + * @param constants - An object containing key-value pairs representing constants. + * @param prefix - A prefix to add to the constant names. + * @returns A string containing code that exports the constants as Noir constants. + */ +export function processConstantsSolidity(constants: { [key: string]: string }, prefix = ''): string { + const code: string[] = []; + Object.entries(constants).forEach(([key, value]) => { + if (SOLIDITY_CONSTANTS.includes(key)) { + code.push(` uint256 internal constant ${prefix}${key} = ${value};`); + } + }); + return code.join('\n'); +} + +/** + * Generate the constants file in Typescript. + */ +export function generateTypescriptConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { + const result = [ + '// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants', + processConstantsTS(constants), + processEnumTS('DomainSeparator', domainSeparatorEnum), + ].join('\n'); + + fs.writeFileSync(targetPath, result); +} + +/** + * Generate the constants file in C++. + */ +export function generateCppConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { + const resultCpp: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants +#pragma once + +${processConstantsCpp(constants, domainSeparatorEnum)} +`; + + fs.writeFileSync(targetPath, resultCpp); +} + +/** + * Generate the constants file in PIL. + */ +export function generatePilConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { + const resultPil: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants +namespace constants; +${processConstantsPil(constants, domainSeparatorEnum)} +\n`; + + fs.writeFileSync(targetPath, resultPil); +} + +/** + * Generate the constants file in Solidity. + */ +export function generateSolidityConstants({ constants }: ParsedContent, targetPath: string) { + const resultSolidity: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.27; + +/** + * @title Constants Library + * @author Aztec Labs + * @notice Library that contains constants used throughout the Aztec protocol + */ +library Constants { + // Prime field modulus + uint256 internal constant P = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + +${processConstantsSolidity(constants)} +}\n`; + + fs.writeFileSync(targetPath, resultSolidity); +} + +/** + * Parse the content of the constants file in Noir. + */ +export function parseNoirFile(fileContent: string): ParsedContent { + const constantsExpressions: [string, string][] = []; + const domainSeparatorEnum: { [key: string]: number } = {}; + + const emptyExpression = (): { name: string; content: string[] } => ({ name: '', content: [] }); + let expression = emptyExpression(); + fileContent.split('\n').forEach(l => { + const line = l.trim(); + + if (!line) { + // Empty line. + return; + } + + if (line.match(/^\/\/|^\s*\/?\*/)) { + // Comment. + return; + } + + { + const [, name, _type, value, end] = line.match(/global\s+(\w+)(\s*:\s*\w+)?\s*=\s*([^;]*)(;)?/) || []; + if (name && value) { + const [, indexName] = name.match(/DOM_SEP__(\w+)/) || []; + if (indexName) { + // Generator index. + domainSeparatorEnum[indexName] = +value; + } else if (end) { + // A single line of expression. + constantsExpressions.push([name, value]); + } else { + // The first line of an expression. + expression = { name, content: [value] }; + } + return; + } else if (name) { + // This case happens if we have only a name, with the value being on the next line + expression = { name, content: [] }; + return; + } + } + + if (expression.name) { + // The expression continues... + const [, content, end] = line.match(/\s*([^;]+)(;)?/) || []; + expression.content.push(content); + if (end) { + // The last line of an expression. + constantsExpressions.push([expression.name, expression.content.join('')]); + expression = emptyExpression(); + } + return; + } + + if (!line.includes('use crate')) { + // eslint-disable-next-line no-console + console.warn(`Unknown content: ${line}`); + } + }); + + const constants = evaluateExpressions(constantsExpressions); + + return { constants, domainSeparatorEnum }; +} + +/** + * Converts constants defined as expressions to constants with actual values. + * @param expressions Ordered list of expressions of the type: "CONSTANT_NAME: expression". + * where the expression is a string that can be evaluated to a number. + * For example: "CONSTANT_NAME: 2 + 2" or "CONSTANT_NAME: CONSTANT_A * CONSTANT_B". + * @returns Parsed expressions of the form: "CONSTANT_NAME: number_as_string". + */ +export function evaluateExpressions(expressions: [string, string][]): { [key: string]: string } { + const constants: { [key: string]: string } = {}; + + const knownBigInts = ['AZTEC_EPOCH_DURATION', 'FEE_RECIPIENT_LENGTH']; + + // Create JS expressions. It is not as easy as just evaluating the expression! + // We basically need to convert everything to BigInts, otherwise things don't fit. + // However, (1) the bigints need to be initialized from strings; (2) everything needs to + // be a bigint, even the actual constant values! + const prelude = expressions + .map(([name, rhs]) => { + const guardedRhs = rhs + // Remove 'as u8', 'as u32' and 'as u64' castings + .replaceAll(' as u8', '') + .replaceAll(' as u32', '') + .replaceAll(' as u64', '') + // Remove the 'AztecAddress::from_field(...)' pattern. + // Also copes with the noir formatter re-formatting over multiple lines. + .replace(/AztecAddress::from_field\(\s*(0x[a-fA-F0-9]+|\d+)\s*,?\s*\)/gs, '$1') + // We make some space around the parentheses, so that constant numbers are still split. + .replace(/\(/g, '( ') + .replace(/\)/g, ' )') + // We also make some space around common operators + .replace(/\+/g, ' + ') + .replace(/(? { + // Remove underscores from numeric literals (e.g., 6_000_000 -> 6000000) + const termWithoutUnderscores = term.replace(/_/g, ''); + return isNaN(+termWithoutUnderscores) ? term : `BigInt('${termWithoutUnderscores}')`; + }) + // .. also, we convert the known bigints to BigInts. + .map(term => (knownBigInts.includes(term) ? `BigInt(${term})` : term)) + // We join the terms back together. + .join(' '); + return `var ${name} = ${guardedRhs};`; + }) + .join('\n'); + + // Extract each value from the expressions. Observe that this will still be a string, + // so that we can then choose to express it as BigInt or Number depending on the size. + for (const [name, _] of expressions) { + constants[name] = eval(prelude + `; BigInt(${name}).toString()`); + } + + return constants; +} diff --git a/protocol/constants-codegen/tsconfig.json b/protocol/constants-codegen/tsconfig.json new file mode 100644 index 000000000000..269b602c4a6a --- /dev/null +++ b/protocol/constants-codegen/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true, + "noEmitOnError": true, + "outDir": "dest", + "rootDir": "src", + "lib": ["ES2022"], + "types": ["node"] + }, + "include": ["src"] +} diff --git a/protocol/constants-codegen/yarn.lock b/protocol/constants-codegen/yarn.lock new file mode 100644 index 000000000000..bdef6ad3ffa2 --- /dev/null +++ b/protocol/constants-codegen/yarn.lock @@ -0,0 +1,53 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@aztec-foundation/constants-codegen@workspace:.": + version: 0.0.0-use.local + resolution: "@aztec-foundation/constants-codegen@workspace:." + dependencies: + "@types/node": "npm:^22" + typescript: "npm:^5.6.3" + bin: + constants-codegen: ./dest/cli.js + languageName: unknown + linkType: soft + +"@types/node@npm:^22": + version: 22.20.1 + resolution: "@types/node@npm:22.20.1" + dependencies: + undici-types: "npm:~6.21.0" + checksum: 10c0/f2ba54d3d1fb92e1c57c78d32c3a17655b1e87363b707136f55c422b4838d4054901ce5d27f75bb0e5ecb7ebfee3804e0987822d22b473473008091857a09353 + languageName: node + linkType: hard + +"typescript@npm:^5.6.3": + version: 5.9.3 + resolution: "typescript@npm:5.9.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5 + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A^5.6.3#optional!builtin": + version: 5.9.3 + resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430 + languageName: node + linkType: hard + +"undici-types@npm:~6.21.0": + version: 6.21.0 + resolution: "undici-types@npm:6.21.0" + checksum: 10c0/c01ed51829b10aa72fc3ce64b747f8e74ae9b60eafa19a7b46ef624403508a54c526ffab06a14a26b3120d055e1104d7abe7c9017e83ced038ea5cf52f8d5e04 + languageName: node + linkType: hard From e91b07eb7c7582d0d587cb36fa83110865342948 Mon Sep 17 00:00:00 2001 From: mverzilli Date: Tue, 14 Jul 2026 16:23:37 +0000 Subject: [PATCH 03/12] move constant generators out of yarn-project/constants. replace them with a new remake-constants.sh that invokes the new cli --- protocol/constants-codegen/src/generator.ts | 22 +- yarn-project/constants/package.json | 2 +- .../constants/scripts/remake-constants.sh | 19 + .../src/scripts/constants.in.test.ts | 94 --- .../constants/src/scripts/constants.in.ts | 744 ------------------ 5 files changed, 36 insertions(+), 845 deletions(-) create mode 100755 yarn-project/constants/scripts/remake-constants.sh delete mode 100644 yarn-project/constants/src/scripts/constants.in.test.ts delete mode 100644 yarn-project/constants/src/scripts/constants.in.ts diff --git a/protocol/constants-codegen/src/generator.ts b/protocol/constants-codegen/src/generator.ts index 8503dcdcede8..1bc00fd7386f 100644 --- a/protocol/constants-codegen/src/generator.ts +++ b/protocol/constants-codegen/src/generator.ts @@ -92,6 +92,10 @@ const CPP_CONSTANTS = [ 'AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX', 'AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH', 'AVM_NUM_PUBLIC_INPUT_COLUMNS', + 'AVM_PUBLIC_INPUTS_COLUMN_0_LENGTH', + 'AVM_PUBLIC_INPUTS_COLUMN_1_LENGTH', + 'AVM_PUBLIC_INPUTS_COLUMN_2_LENGTH', + 'AVM_PUBLIC_INPUTS_COLUMN_3_LENGTH', 'AVM_PUBLIC_INPUTS_COLUMNS_COMBINED_LENGTH', 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_HEIGHT', 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_ROOT', @@ -232,7 +236,6 @@ const PIL_CONSTANTS = [ 'AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX', 'AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH', 'AVM_NUM_PUBLIC_INPUT_COLUMNS', - 'AVM_PUBLIC_INPUTS_COLUMNS_COMBINED_LENGTH', 'AVM_SUBTRACE_ID_EXECUTION', 'AVM_SUBTRACE_ID_ALU', 'AVM_SUBTRACE_ID_CAST', @@ -352,6 +355,12 @@ export interface ParsedContent { domainSeparatorEnum: { [key: string]: number }; } +/** Raw expressions parsed from Noir source before cross-file evaluation. */ +export interface ParsedExpressions { + constantsExpressions: [string, string][]; + domainSeparatorEnum: { [key: string]: number }; +} + /** * Processes a collection of constants and generates code to export them as TypeScript constants. * @@ -526,14 +535,17 @@ ${processConstantsSolidity(constants)} /** * Parse the content of the constants file in Noir. */ -export function parseNoirFile(fileContent: string): ParsedContent { +export function parseNoirFile( + fileContent: string, + { stripLineComments = false }: { stripLineComments?: boolean } = {}, +): ParsedExpressions { const constantsExpressions: [string, string][] = []; const domainSeparatorEnum: { [key: string]: number } = {}; const emptyExpression = (): { name: string; content: string[] } => ({ name: '', content: [] }); let expression = emptyExpression(); fileContent.split('\n').forEach(l => { - const line = l.trim(); + const line = (stripLineComments ? l.replace(/\/\/.*$/, '') : l).trim(); if (!line) { // Empty line. @@ -585,9 +597,7 @@ export function parseNoirFile(fileContent: string): ParsedContent { } }); - const constants = evaluateExpressions(constantsExpressions); - - return { constants, domainSeparatorEnum }; + return { constantsExpressions, domainSeparatorEnum }; } /** diff --git a/yarn-project/constants/package.json b/yarn-project/constants/package.json index f82369b09eb8..782bb11420fa 100644 --- a/yarn-project/constants/package.json +++ b/yarn-project/constants/package.json @@ -19,7 +19,7 @@ "build": "yarn clean && ../scripts/tsc.sh", "build:dev": "../scripts/tsc.sh --watch", "clean": "rm -rf ./dest .tsbuildinfo", - "remake-constants": "node --loader @swc-node/register/esm src/scripts/constants.in.ts && cd ../../l1-contracts && forge fmt", + "remake-constants": "./scripts/remake-constants.sh", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}" }, "dependencies": { diff --git a/yarn-project/constants/scripts/remake-constants.sh b/yarn-project/constants/scripts/remake-constants.sh new file mode 100755 index 000000000000..2f00c56d4dcd --- /dev/null +++ b/yarn-project/constants/scripts/remake-constants.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -eu + +repo_root=$(git rev-parse --show-toplevel) +codegen_dir="$repo_root/protocol/constants-codegen" +cpp_output="$repo_root/barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp" + +yarn --cwd "$codegen_dir" install --immutable +yarn --cwd "$codegen_dir" build +node "$codegen_dir/dest/cli.js" \ + --input "$repo_root/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr" \ + --typescript "$repo_root/yarn-project/constants/src/constants.gen.ts" \ + --cpp "$cpp_output" \ + --pil "$repo_root/barretenberg/cpp/pil/vm2/constants_gen.pil" \ + --solidity "$repo_root/l1-contracts/src/core/libraries/ConstantsGen.sol" + +clang-format-20 -i "$cpp_output" +(cd "$repo_root/l1-contracts" && forge fmt) diff --git a/yarn-project/constants/src/scripts/constants.in.test.ts b/yarn-project/constants/src/scripts/constants.in.test.ts deleted file mode 100644 index 0e2313726b9d..000000000000 --- a/yarn-project/constants/src/scripts/constants.in.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { jest } from '@jest/globals'; -import { mkdtempSync, readFileSync, rmSync } from 'fs'; -import { tmpdir } from 'os'; -import { dirname, join } from 'path'; -import { fileURLToPath } from 'url'; - -import { - type ParsedContent, - evaluateExpressions, - generateCppConstants, - generatePilConstants, - generateSolidityConstants, - generateTypescriptConstants, - parseNoirFile, -} from './constants.in.js'; - -const scriptDir = dirname(fileURLToPath(import.meta.url)); -const noirConstantsPath = join( - scriptDir, - '../../../../noir-projects/noir-protocol-circuits/crates/types/src/constants.nr', -); - -function parseCurrentNoirConstants(): ParsedContent { - const warning = jest.spyOn(console, 'warn').mockImplementation(() => undefined); - try { - const { constantsExpressions, domainSeparatorEnum } = parseNoirFile(readFileSync(noirConstantsPath, 'utf8')); - return { constants: evaluateExpressions(constantsExpressions), domainSeparatorEnum }; - } finally { - warning.mockRestore(); - } -} - -function generateToString(generate: (content: ParsedContent, targetPath: string) => void): string { - const tempDir = mkdtempSync(join(tmpdir(), 'constants-codegen-')); - const targetPath = join(tempDir, 'output'); - try { - generate(parseCurrentNoirConstants(), targetPath); - return readFileSync(targetPath, 'utf8'); - } finally { - rmSync(tempDir, { recursive: true, force: true }); - } -} - -function normalizeCppFormatting(content: string): string { - return content - .replace(/\\\r?\n\s*/g, ' ') - .split('\n') - .map(line => line.trim().replaceAll(/\s+/g, ' ')) - .join('\n') - .trim(); -} - -function normalizeSolidityFormatting(content: string): string { - return content - .replaceAll(/(?<=\d)_(?=\d)/g, '') - .replaceAll(/\s+/g, ' ') - .trim(); -} - -describe('current constants generator', () => { - it('reproduces the checked-in TypeScript output', () => { - const generated = generateToString(generateTypescriptConstants); - const checkedIn = readFileSync(join(scriptDir, '../constants.gen.ts'), 'utf8'); - - expect(generated).toBe(checkedIn); - }); - - it('reproduces the checked-in C++ symbols and values', () => { - const generated = generateToString(generateCppConstants); - const checkedIn = readFileSync( - join(scriptDir, '../../../../barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp'), - 'utf8', - ); - - expect(normalizeCppFormatting(generated)).toBe(normalizeCppFormatting(checkedIn)); - }); - - it('reproduces the checked-in PIL output', () => { - const generated = generateToString(generatePilConstants); - const checkedIn = readFileSync(join(scriptDir, '../../../../barretenberg/cpp/pil/vm2/constants_gen.pil'), 'utf8'); - - expect(generated).toBe(checkedIn); - }); - - it('reproduces the checked-in Solidity symbols and values', () => { - const generated = generateToString(generateSolidityConstants); - const checkedIn = readFileSync( - join(scriptDir, '../../../../l1-contracts/src/core/libraries/ConstantsGen.sol'), - 'utf8', - ); - - expect(normalizeSolidityFormatting(generated)).toBe(normalizeSolidityFormatting(checkedIn)); - }); -}); diff --git a/yarn-project/constants/src/scripts/constants.in.ts b/yarn-project/constants/src/scripts/constants.in.ts deleted file mode 100644 index a42ddb05ec3f..000000000000 --- a/yarn-project/constants/src/scripts/constants.in.ts +++ /dev/null @@ -1,744 +0,0 @@ -import * as fs from 'fs'; -import { dirname, join } from 'path'; -import { fileURLToPath, pathToFileURL } from 'url'; - -const NOIR_CONSTANTS_FILE = '../../../../noir-projects/noir-protocol-circuits/crates/types/src/constants.nr'; -const TS_CONSTANTS_FILE = '../constants.gen.ts'; -const CPP_AZTEC_CONSTANTS_FILE = '../../../../barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp'; -const PIL_AZTEC_CONSTANTS_FILE = '../../../../barretenberg/cpp/pil/vm2/constants_gen.pil'; -const SOLIDITY_CONSTANTS_FILE = '../../../../l1-contracts/src/core/libraries/ConstantsGen.sol'; - -// Additional Noir source files (outside constants.nr) to extract specific constants from, keyed by -// file path (relative to this script) and the exact constant names to pull from each. Used for -// constants that are defined alongside circuit code rather than in constants.nr, so they can be -// exported to the generated TS constants without duplicating their definition. The referenced -// constants may depend on constants.nr values, which are in scope because they are evaluated after -// the main file's constants. -const ADDITIONAL_NOIR_CONSTANT_FILES: { file: string; constants: string[] }[] = [ - { - file: '../../../../noir-projects/noir-protocol-circuits/crates/types/src/blob_data/tx_blob_data.nr', - constants: ['MAX_TX_BLOB_DATA_SIZE_IN_FIELDS'], - }, -]; - -// Whitelist of constants that will be copied to aztec_constants.hpp. -// We don't copy everything as just a handful are needed, and updating them breaks the cache and triggers expensive bb builds. -const CPP_CONSTANTS = [ - 'MAX_ETH_ADDRESS_BIT_SIZE', - 'MAX_ETH_ADDRESS_VALUE', - 'GENESIS_BLOCK_HEADER_HASH', - 'GENESIS_ARCHIVE_ROOT', - 'MEM_TAG_U1', - 'MEM_TAG_U8', - 'MEM_TAG_U16', - 'MEM_TAG_U32', - 'MEM_TAG_U64', - 'MEM_TAG_U128', - 'MEM_TAG_FF', - 'MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS', - 'CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS', - 'CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS', - 'FEE_JUICE_ADDRESS', - 'TX_DA_GAS_OVERHEAD', - 'FEE_JUICE_BALANCES_SLOT', - 'UPDATED_CLASS_IDS_SLOT', - 'UPDATES_DELAYED_PUBLIC_MUTABLE_VALUES_LEN', - 'PUBLIC_DATA_TREE_HEIGHT', - 'NULLIFIER_TREE_HEIGHT', - 'NULLIFIER_SUBTREE_HEIGHT', - 'NOTE_HASH_TREE_HEIGHT', - 'L1_TO_L2_MSG_TREE_HEIGHT', - 'ARCHIVE_HEIGHT', - 'TIMESTAMP_OF_CHANGE_BIT_SIZE', - 'UPDATES_DELAYED_PUBLIC_MUTABLE_METADATA_BIT_SIZE', - 'MAX_ENQUEUED_CALLS_PER_TX', - 'MAX_NOTE_HASHES_PER_TX', - 'MAX_NULLIFIERS_PER_TX', - 'MAX_L2_TO_L1_MSGS_PER_TX', - 'MAX_PROCESSABLE_L2_GAS', - 'MAX_PUBLIC_LOGS_PER_TX', - 'MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', - 'MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS', - 'MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', - 'MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_CHAIN_ID_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_VERSION_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_BLOCK_NUMBER_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_SLOT_NUMBER_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_TIMESTAMP_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_COINBASE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_FEE_RECIPIENT_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_GAS_FEES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PROTOCOL_CONTRACTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_GAS_USED_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GAS_SETTINGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_FEE_PAYER_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PUBLIC_SETUP_CALL_REQUESTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PUBLIC_APP_LOGIC_CALL_REQUESTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PUBLIC_TEARDOWN_CALL_REQUEST_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_GAS_USED_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NOTE_HASHES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NULLIFIERS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_L2_TO_L1_MSGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_LOGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_DATA_WRITES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_LOGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_DATA_WRITES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_TRANSACTION_FEE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX', - 'AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH', - 'AVM_NUM_PUBLIC_INPUT_COLUMNS', - 'AVM_PUBLIC_INPUTS_COLUMN_0_LENGTH', - 'AVM_PUBLIC_INPUTS_COLUMN_1_LENGTH', - 'AVM_PUBLIC_INPUTS_COLUMN_2_LENGTH', - 'AVM_PUBLIC_INPUTS_COLUMN_3_LENGTH', - 'AVM_PUBLIC_INPUTS_COLUMNS_COMBINED_LENGTH', - 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_HEIGHT', - 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_ROOT', - 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_SIZE', - 'NOTE_HASH_TREE_LEAF_COUNT', - 'L1_TO_L2_MSG_TREE_LEAF_COUNT', - 'FLAT_PUBLIC_LOGS_HEADER_LENGTH', - 'FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH', - 'PUBLIC_LOGS_LENGTH', - 'PUBLIC_LOG_HEADER_LENGTH', - 'MAX_PUBLIC_LOG_SIZE_IN_FIELDS', - 'PUBLIC_TX_L2_GAS_OVERHEAD', - 'MAX_PROTOCOL_CONTRACTS', - 'DEFAULT_MAX_DEBUG_LOG_MEMORY_READS', -]; - -const CPP_GENERATORS: string[] = [ - 'BLOCK_HEADER_HASH', - 'SALTED_INITIALIZATION_HASH', - 'PARTIAL_ADDRESS', - 'CONTRACT_ADDRESS_V2', - 'CONTRACT_CLASS_ID', - 'PUBLIC_KEYS_HASH', - 'SINGLE_PUBLIC_KEY_HASH', - 'NOTE_HASH_NONCE', - 'UNIQUE_NOTE_HASH', - 'SILOED_NOTE_HASH', - 'SILOED_NULLIFIER', - 'PUBLIC_LEAF_SLOT', - 'PUBLIC_STORAGE_MAP_SLOT', - 'PUBLIC_CALLDATA', - 'PUBLIC_BYTECODE', - 'MERKLE_HASH', - 'NULLIFIER_MERKLE', - 'PUBLIC_DATA_MERKLE', - 'WRITTEN_SLOTS_MERKLE', - 'RETRIEVED_BYTECODES_MERKLE', -]; - -const PIL_CONSTANTS = [ - 'MAX_ETH_ADDRESS_VALUE', - 'MEM_TAG_U1', - 'MEM_TAG_U8', - 'MEM_TAG_U16', - 'MEM_TAG_U32', - 'MEM_TAG_U64', - 'MEM_TAG_U128', - 'MEM_TAG_FF', - 'AVM_BITWISE_AND_OP_ID', - 'AVM_BITWISE_OR_OP_ID', - 'AVM_BITWISE_XOR_OP_ID', - 'AVM_KECCAKF1600_NUM_ROUNDS', - 'AVM_KECCAKF1600_STATE_SIZE', - 'AVM_TX_PHASE_VALUE_START', - 'AVM_TX_PHASE_VALUE_SETUP', - 'AVM_TX_PHASE_VALUE_LAST', - 'AVM_HIGHEST_MEM_ADDRESS', - 'AVM_MEMORY_NUM_BITS', - 'AVM_MEMORY_SIZE', - 'MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS', - 'MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', - 'MAX_NOTE_HASHES_PER_TX', - 'GRUMPKIN_ONE_X', - 'GRUMPKIN_ONE_Y', - 'AVM_PC_SIZE_IN_BITS', - 'PUBLIC_DATA_TREE_HEIGHT', - 'NULLIFIER_TREE_HEIGHT', - 'NOTE_HASH_TREE_HEIGHT', - 'L1_TO_L2_MSG_TREE_HEIGHT', - 'UPDATED_CLASS_IDS_SLOT', - 'UPDATES_DELAYED_PUBLIC_MUTABLE_VALUES_LEN', - 'CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS', - 'CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS', - 'FEE_JUICE_ADDRESS', - 'FEE_JUICE_BALANCES_SLOT', - 'TIMESTAMP_OF_CHANGE_BIT_SIZE', - 'UPDATES_DELAYED_PUBLIC_MUTABLE_METADATA_BIT_SIZE', - 'UPDATES_SHARED_MUTABLE_METADATA_BIT_SIZE', - 'MAX_ENQUEUED_CALLS_PER_TX', - 'MAX_NOTE_HASHES_PER_TX', - 'MAX_NULLIFIERS_PER_TX', - 'MAX_L2_TO_L1_MSGS_PER_TX', - 'MAX_PUBLIC_LOGS_PER_TX', - 'MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS', - 'MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', - 'MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_CHAIN_ID_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_VERSION_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_BLOCK_NUMBER_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_SLOT_NUMBER_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_TIMESTAMP_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_COINBASE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_FEE_RECIPIENT_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_GAS_FEES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PROTOCOL_CONTRACTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_START_GAS_USED_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GAS_SETTINGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GAS_SETTINGS_GAS_LIMITS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_GAS_SETTINGS_TEARDOWN_GAS_LIMITS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_FEE_PAYER_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PUBLIC_SETUP_CALL_REQUESTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PUBLIC_APP_LOGIC_CALL_REQUESTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PUBLIC_TEARDOWN_CALL_REQUEST_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_PREVIOUS_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_END_GAS_USED_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NOTE_HASHES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_NULLIFIERS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_L2_TO_L1_MSGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_LOGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_DATA_WRITES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NOTE_HASHES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_LOGS_ROW_IDX', - 'AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_DATA_WRITES_ROW_IDX', - 'AVM_PUBLIC_INPUTS_TRANSACTION_FEE_ROW_IDX', - 'AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX', - 'AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH', - 'AVM_NUM_PUBLIC_INPUT_COLUMNS', - 'AVM_SUBTRACE_ID_EXECUTION', - 'AVM_SUBTRACE_ID_ALU', - 'AVM_SUBTRACE_ID_CAST', - 'AVM_SUBTRACE_ID_SET', - 'AVM_SUBTRACE_ID_BITWISE', - 'AVM_SUBTRACE_ID_POSEIDON2_PERM', - 'AVM_SUBTRACE_ID_TO_RADIX', - 'AVM_SUBTRACE_ID_ECC', - 'AVM_SUBTRACE_ID_KECCAKF1600', - 'AVM_SUBTRACE_ID_CALLDATA_COPY', - 'AVM_SUBTRACE_ID_SHA256_COMPRESSION', - 'AVM_SUBTRACE_ID_RETURNDATA_COPY', - 'AVM_DYN_GAS_ID_CALLDATACOPY', - 'AVM_DYN_GAS_ID_RETURNDATACOPY', - 'AVM_DYN_GAS_ID_TORADIX', - 'AVM_DYN_GAS_ID_BITWISE', - 'AVM_DYN_GAS_ID_EMITPUBLICLOG', - 'AVM_DYN_GAS_ID_SSTORE', - 'AVM_SUBTRACE_ID_GETCONTRACTINSTANCE', - 'AVM_SUBTRACE_ID_EMITPUBLICLOG', - 'AVM_EXEC_OP_ID_GETENVVAR', - 'AVM_EXEC_OP_ID_MOV', - 'AVM_EXEC_OP_ID_JUMP', - 'AVM_EXEC_OP_ID_JUMPI', - 'AVM_EXEC_OP_ID_CALL', - 'AVM_EXEC_OP_ID_STATICCALL', - 'AVM_EXEC_OP_ID_INTERNALCALL', - 'AVM_EXEC_OP_ID_INTERNALRETURN', - 'AVM_EXEC_OP_ID_RETURN', - 'AVM_EXEC_OP_ID_REVERT', - 'AVM_EXEC_OP_ID_SUCCESSCOPY', - 'AVM_EXEC_OP_ID_ALU_ADD', - 'AVM_EXEC_OP_ID_ALU_SUB', - 'AVM_EXEC_OP_ID_ALU_MUL', - 'AVM_EXEC_OP_ID_ALU_DIV', - 'AVM_EXEC_OP_ID_ALU_FDIV', - 'AVM_EXEC_OP_ID_ALU_EQ', - 'AVM_EXEC_OP_ID_ALU_LT', - 'AVM_EXEC_OP_ID_ALU_LTE', - 'AVM_EXEC_OP_ID_ALU_NOT', - 'AVM_EXEC_OP_ID_ALU_SHL', - 'AVM_EXEC_OP_ID_ALU_SHR', - 'AVM_EXEC_OP_ID_ALU_TRUNCATE', - 'AVM_EXEC_OP_ID_RETURNDATASIZE', - 'AVM_EXEC_OP_ID_DEBUGLOG', - 'AVM_EXEC_OP_ID_SLOAD', - 'AVM_EXEC_OP_ID_SSTORE', - 'AVM_EXEC_OP_ID_NOTEHASH_EXISTS', - 'AVM_EXEC_OP_ID_EMIT_NOTEHASH', - 'AVM_EXEC_OP_ID_L1_TO_L2_MESSAGE_EXISTS', - 'AVM_EXEC_OP_ID_NULLIFIER_EXISTS', - 'AVM_EXEC_OP_ID_EMIT_NULLIFIER', - 'AVM_EXEC_OP_ID_SENDL2TOL1MSG', - 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_HEIGHT', - 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_ROOT', - 'AVM_WRITTEN_PUBLIC_DATA_SLOTS_TREE_INITIAL_SIZE', - 'AVM_RETRIEVED_BYTECODES_TREE_HEIGHT', - 'AVM_RETRIEVED_BYTECODES_TREE_INITIAL_ROOT', - 'AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE', - 'NOTE_HASH_TREE_LEAF_COUNT', - 'L1_TO_L2_MSG_TREE_LEAF_COUNT', - 'FLAT_PUBLIC_LOGS_HEADER_LENGTH', - 'FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH', - 'PUBLIC_LOGS_LENGTH', - 'PUBLIC_LOG_HEADER_LENGTH', - 'MAX_PROTOCOL_CONTRACTS', -]; - -const PIL_GENERATORS: string[] = [ - 'SALTED_INITIALIZATION_HASH', - 'PARTIAL_ADDRESS', - 'CONTRACT_ADDRESS_V2', - 'CONTRACT_CLASS_ID', - 'PUBLIC_KEYS_HASH', - 'SINGLE_PUBLIC_KEY_HASH', - 'NOTE_HASH_NONCE', - 'UNIQUE_NOTE_HASH', - 'SILOED_NOTE_HASH', - 'SILOED_NULLIFIER', - 'PUBLIC_LEAF_SLOT', - 'PUBLIC_STORAGE_MAP_SLOT', - 'PUBLIC_CALLDATA', - 'PUBLIC_BYTECODE', - 'MERKLE_HASH', - 'NULLIFIER_MERKLE', - 'PUBLIC_DATA_MERKLE', - 'WRITTEN_SLOTS_MERKLE', - 'RETRIEVED_BYTECODES_MERKLE', -]; - -const SOLIDITY_CONSTANTS = [ - 'MAX_FIELD_VALUE', - 'MAX_L2_TO_L1_MSGS_PER_TX', - 'EMPTY_EPOCH_OUT_HASH', - 'L1_TO_L2_MSG_SUBTREE_HEIGHT', - 'NUM_MSGS_PER_BASE_PARITY', - 'NUM_BASE_PARITY_PER_ROOT_PARITY', - 'BLS12_POINT_COMPRESSED_BYTES', - 'ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH', - 'INITIAL_CHECKPOINT_NUMBER', - 'GENESIS_ARCHIVE_ROOT', - 'FEE_JUICE_ADDRESS', - 'MAX_CHECKPOINTS_PER_EPOCH', -]; - -/** - * Parsed content. - */ -export interface ParsedContent { - /** - * Constants of the form "CONSTANT_NAME: number_as_string". - */ - constants: { [key: string]: string }; - /** - * DomainSeparatorEnum. - */ - domainSeparatorEnum: { [key: string]: number }; -} - -/** - * Raw expressions parsed from a Noir file, prior to evaluation. Keeping expressions unevaluated lets - * us merge constants from multiple files and resolve cross-file references in a single evaluation pass. - */ -interface ParsedExpressions { - /** - * Ordered list of "CONSTANT_NAME: expression" pairs. - */ - constantsExpressions: [string, string][]; - /** - * DomainSeparatorEnum. - */ - domainSeparatorEnum: { [key: string]: number }; -} - -/** - * Processes a collection of constants and generates code to export them as TypeScript constants. - * - * @param constants - An object containing key-value pairs representing constants. - * @returns A string containing code that exports the constants as TypeScript constants. - */ -export function processConstantsTS(constants: { [key: string]: string }): string { - const code: string[] = []; - Object.entries(constants).forEach(([key, value]) => { - code.push(`export const ${key} = ${+value > Number.MAX_SAFE_INTEGER ? value + 'n' : value};`); - }); - return code.join('\n'); -} - -/** - * Processes a collection of constants and generates code to export them as cpp constants. - * Required to ensure consistency between the constants used in pil and used in the vm witness generator. - * - * @param constants - An object containing key-value pairs representing constants. - * @returns A string containing code that exports the constants as cpp constants. - */ -export function processConstantsCpp( - constants: { [key: string]: string }, - generatorIndices: { [key: string]: number }, -): string { - const code: string[] = []; - Object.entries(constants).forEach(([key, value]) => { - if (CPP_CONSTANTS.includes(key) || key.startsWith('AVM_')) { - if (BigInt(value) <= 2n ** 31n - 1n) { - code.push(`#define ${key} ${value}`); - } else if (BigInt(value) <= 2n ** 64n - 1n) { - code.push(`#define ${key} 0x${BigInt(value).toString(16)}`); // hex literals - } else { - code.push(`#define ${key} "0x${BigInt(value).toString(16).padStart(64, '0')}"`); // stringify large numbers - } - } - }); - Object.entries(generatorIndices).forEach(([key, value]) => { - if (CPP_GENERATORS.includes(key)) { - code.push(`#define DOM_SEP__${key} ${value}UL`); - } - }); - return code.join('\n'); -} - -/** - * Processes a collection of constants and generates code to export them as PIL constants. - * Required to ensure consistency between the constants used in pil and used in the vm witness generator. - * - * @param constants - An object containing key-value pairs representing constants. - * @returns A string containing code that exports the constants as cpp constants. - */ -export function processConstantsPil( - constants: { [key: string]: string }, - generatorIndices: { [key: string]: number }, -): string { - const code: string[] = []; - Object.entries(constants).forEach(([key, value]) => { - if (PIL_CONSTANTS.includes(key)) { - code.push(` pol ${key} = ${value};`); - } - }); - Object.entries(generatorIndices).forEach(([key, value]) => { - if (PIL_GENERATORS.includes(key)) { - code.push(` pol DOM_SEP__${key} = ${value};`); - } - }); - - return code.join('\n'); -} -/** - * Processes an enum and generates code to export it as a TypeScript enum. - * - * @param enumName - The name of the enum. - * @param enumValues - An object containing key-value pairs representing enum values. - * @returns A string containing code that exports the enum as a TypeScript enum. - */ -export function processEnumTS(enumName: string, enumValues: { [key: string]: number }): string { - const code: string[] = []; - - code.push(`export enum ${enumName} {`); - - Object.entries(enumValues).forEach(([key, value]) => { - code.push(` ${key} = ${value},`); - }); - - code.push('}'); - - return code.join('\n'); -} - -/** - * Processes a collection of constants and generates code to export them as Solidity constants. - * - * @param constants - An object containing key-value pairs representing constants. - * @param prefix - A prefix to add to the constant names. - * @returns A string containing code that exports the constants as Noir constants. - */ -export function processConstantsSolidity(constants: { [key: string]: string }, prefix = ''): string { - const code: string[] = []; - Object.entries(constants).forEach(([key, value]) => { - if (SOLIDITY_CONSTANTS.includes(key)) { - code.push(` uint256 internal constant ${prefix}${key} = ${value};`); - } - }); - return code.join('\n'); -} - -/** - * Generate the constants file in Typescript. - */ -export function generateTypescriptConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { - const result = [ - '// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants', - processConstantsTS(constants), - processEnumTS('DomainSeparator', domainSeparatorEnum), - ].join('\n'); - - fs.writeFileSync(targetPath, result); -} - -/** - * Generate the constants file in C++. - */ -export function generateCppConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { - const resultCpp: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants -#pragma once - -${processConstantsCpp(constants, domainSeparatorEnum)} -`; - - fs.writeFileSync(targetPath, resultCpp); -} - -/** - * Generate the constants file in PIL. - */ -export function generatePilConstants({ constants, domainSeparatorEnum }: ParsedContent, targetPath: string) { - const resultPil: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants -namespace constants; -${processConstantsPil(constants, domainSeparatorEnum)} -\n`; - - fs.writeFileSync(targetPath, resultPil); -} - -/** - * Generate the constants file in Solidity. - */ -export function generateSolidityConstants({ constants }: ParsedContent, targetPath: string) { - const resultSolidity: string = `// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in yarn-project/constants -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. -pragma solidity >=0.8.27; - -/** - * @title Constants Library - * @author Aztec Labs - * @notice Library that contains constants used throughout the Aztec protocol - */ -library Constants { - // Prime field modulus - uint256 internal constant P = - 21888242871839275222246405745257275088548364400416034343698204186575808495617; - -${processConstantsSolidity(constants)} -}\n`; - - fs.writeFileSync(targetPath, resultSolidity); -} - -/** - * Parse the content of the constants file in Noir. - */ -export function parseNoirFile( - fileContent: string, - { stripLineComments = false }: { stripLineComments?: boolean } = {}, -): ParsedExpressions { - const constantsExpressions: [string, string][] = []; - const domainSeparatorEnum: { [key: string]: number } = {}; - - const emptyExpression = (): { name: string; content: string[] } => ({ name: '', content: [] }); - let expression = emptyExpression(); - fileContent.split('\n').forEach(l => { - // Strip trailing `//` line comments so multi-line expressions with inline comments (e.g. - // MAX_TX_BLOB_DATA_SIZE_IN_FIELDS) parse correctly. Disabled for constants.nr to keep its - // existing parsing behavior byte-for-byte unchanged. - const line = (stripLineComments ? l.replace(/\/\/.*$/, '') : l).trim(); - - if (!line) { - // Empty line. - return; - } - - if (line.match(/^\/\/|^\s*\/?\*/)) { - // Comment. - return; - } - - { - const [, name, _type, value, end] = line.match(/global\s+(\w+)(\s*:\s*\w+)?\s*=\s*([^;]*)(;)?/) || []; - if (name && value) { - const [, indexName] = name.match(/DOM_SEP__(\w+)/) || []; - if (indexName) { - // Generator index. - domainSeparatorEnum[indexName] = +value; - } else if (end) { - // A single line of expression. - constantsExpressions.push([name, value]); - } else { - // The first line of an expression. - expression = { name, content: [value] }; - } - return; - } else if (name) { - // This case happens if we have only a name, with the value being on the next line - expression = { name, content: [] }; - return; - } - } - - if (expression.name) { - // The expression continues... - const [, content, end] = line.match(/\s*([^;]+)(;)?/) || []; - expression.content.push(content); - if (end) { - // The last line of an expression. - constantsExpressions.push([expression.name, expression.content.join('')]); - expression = emptyExpression(); - } - return; - } - - if (!line.includes('use crate')) { - // eslint-disable-next-line no-console - console.warn(`Unknown content: ${line}`); - } - }); - - return { constantsExpressions, domainSeparatorEnum }; -} - -/** - * Converts constants defined as expressions to constants with actual values. - * @param expressions Ordered list of expressions of the type: "CONSTANT_NAME: expression". - * where the expression is a string that can be evaluated to a number. - * For example: "CONSTANT_NAME: 2 + 2" or "CONSTANT_NAME: CONSTANT_A * CONSTANT_B". - * @returns Parsed expressions of the form: "CONSTANT_NAME: number_as_string". - */ -export function evaluateExpressions(expressions: [string, string][]): { [key: string]: string } { - const constants: { [key: string]: string } = {}; - - const knownBigInts = ['AZTEC_EPOCH_DURATION', 'FEE_RECIPIENT_LENGTH']; - - // Create JS expressions. It is not as easy as just evaluating the expression! - // We basically need to convert everything to BigInts, otherwise things don't fit. - // However, (1) the bigints need to be initialized from strings; (2) everything needs to - // be a bigint, even the actual constant values! - const prelude = expressions - .map(([name, rhs]) => { - const guardedRhs = rhs - // Remove 'as u8', 'as u32' and 'as u64' castings - .replaceAll(' as u8', '') - .replaceAll(' as u32', '') - .replaceAll(' as u64', '') - // Remove the 'AztecAddress::from_field(...)' pattern. - // Also copes with the noir formatter re-formatting over multiple lines. - .replace(/AztecAddress::from_field\(\s*(0x[a-fA-F0-9]+|\d+)\s*,?\s*\)/gs, '$1') - // We make some space around the parentheses, so that constant numbers are still split. - .replace(/\(/g, '( ') - .replace(/\)/g, ' )') - // We also make some space around common operators - .replace(/\+/g, ' + ') - .replace(/(? { - // Remove underscores from numeric literals (e.g., 6_000_000 -> 6000000) - const termWithoutUnderscores = term.replace(/_/g, ''); - return isNaN(+termWithoutUnderscores) ? term : `BigInt('${termWithoutUnderscores}')`; - }) - // .. also, we convert the known bigints to BigInts. - .map(term => (knownBigInts.includes(term) ? `BigInt(${term})` : term)) - // We join the terms back together. - .join(' '); - return `var ${name} = ${guardedRhs};`; - }) - .join('\n'); - - // Extract each value from the expressions. Observe that this will still be a string, - // so that we can then choose to express it as BigInt or Number depending on the size. - for (const [name, _] of expressions) { - constants[name] = eval(prelude + `; BigInt(${name}).toString()`); - } - - return constants; -} - -/** - * Convert the Noir constants to TypeScript and Solidity. - */ -function main(): void { - const __dirname = dirname(fileURLToPath(import.meta.url)); - - const noirConstantsFile = join(__dirname, NOIR_CONSTANTS_FILE); - const noirConstants = fs.readFileSync(noirConstantsFile, 'utf-8'); - const { constantsExpressions, domainSeparatorEnum } = parseNoirFile(noirConstants); - - // Pull in explicitly-listed constants defined outside constants.nr (e.g. alongside circuit code). - // They are appended after the main constants so they can reference them when evaluated together. - for (const { file, constants: names } of ADDITIONAL_NOIR_CONSTANT_FILES) { - const additionalContent = fs.readFileSync(join(__dirname, file), 'utf-8'); - const { constantsExpressions: additionalExpressions } = parseNoirFile(additionalContent, { - stripLineComments: true, - }); - for (const name of names) { - const expression = additionalExpressions.find(([exprName]) => exprName === name); - if (!expression) { - throw new Error(`Constant ${name} not found in ${file}`); - } - constantsExpressions.push(expression); - } - } - - const parsedContent: ParsedContent = { - constants: evaluateExpressions(constantsExpressions), - domainSeparatorEnum, - }; - - // Typescript - const tsTargetPath = join(__dirname, TS_CONSTANTS_FILE); - generateTypescriptConstants(parsedContent, tsTargetPath); - - // Cpp - const cppTargetPath = join(__dirname, CPP_AZTEC_CONSTANTS_FILE); - generateCppConstants(parsedContent, cppTargetPath); - - // PIL - const pilTargetPath = join(__dirname, PIL_AZTEC_CONSTANTS_FILE); - generatePilConstants(parsedContent, pilTargetPath); - - // Solidity - const solidityTargetPath = join(__dirname, SOLIDITY_CONSTANTS_FILE); - fs.mkdirSync(dirname(solidityTargetPath), { recursive: true }); - generateSolidityConstants(parsedContent, solidityTargetPath); -} - -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { - main(); -} From 5c34f7b5c3b63328fea1a4387b14a552f2b8a794 Mon Sep 17 00:00:00 2001 From: mverzilli Date: Wed, 15 Jul 2026 09:11:25 +0000 Subject: [PATCH 04/12] keep downstream tests in constants package --- Makefile | 15 ++++- protocol/constants-codegen/bootstrap.sh | 32 +++++++++ yarn-project/bootstrap.sh | 3 + yarn-project/constants/.rebuild_patterns | 10 +++ .../constants/scripts/remake-constants.sh | 66 ++++++++++++++++--- 5 files changed, 116 insertions(+), 10 deletions(-) create mode 100755 protocol/constants-codegen/bootstrap.sh create mode 100644 yarn-project/constants/.rebuild_patterns diff --git a/Makefile b/Makefile index 3f65d4bc9d29..5b3e4bc61f7a 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ endef # Fast bootstrap. fast: release-image barretenberg boxes playground docs aztec-up \ - 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 + 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 # Full bootstrap. 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 bb-full-tests: bb-cpp-wasm-threads-tests bb-cpp-asan-tests bb-cpp-smt-tests +#============================================================================== +# Protocol Constants Codegen +#============================================================================== + +.PHONY: constants-codegen constants-codegen-tests +constants-codegen: + $(call build,$@,protocol/constants-codegen) + +constants-codegen-tests: constants-codegen + $(call test,$@,protocol/constants-codegen) + #============================================================================== # IPC Codegen #============================================================================== @@ -421,7 +432,7 @@ l1-contracts-tests: l1-contracts-verifier # Yarn Project - TypeScript monorepo with all TS packages #============================================================================== -yarn-project: bb-ts noir-projects l1-contracts wsdb bb-avm-sim +yarn-project: bb-ts noir-projects l1-contracts wsdb bb-avm-sim constants-codegen $(call build,$@,yarn-project) yarn-project-tests: yarn-project diff --git a/protocol/constants-codegen/bootstrap.sh b/protocol/constants-codegen/bootstrap.sh new file mode 100755 index 000000000000..17367a3095c2 --- /dev/null +++ b/protocol/constants-codegen/bootstrap.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +source $(git rev-parse --show-toplevel)/ci3/source_bootstrap + +hash=$(cache_content_hash .) + +function build { + echo_header "constants-codegen build" + npm_install_deps + yarn build +} + +function test_cmds { + echo "$hash cd protocol/constants-codegen && node --test dest/*.test.js" +} + +function test { + echo_header "constants-codegen test" + test_cmds | filter_test_cmds | parallelize +} + +case "$cmd" in + "") + build + ;; + hash) + echo "$hash" + ;; + *) + default_cmd_handler "$@" + ;; +esac diff --git a/yarn-project/bootstrap.sh b/yarn-project/bootstrap.sh index 6bafe40ef585..bd4373c2bae2 100755 --- a/yarn-project/bootstrap.sh +++ b/yarn-project/bootstrap.sh @@ -174,6 +174,9 @@ function build { function test_cmds { local hash=$(hash) + local constants_hash=$(cache_content_hash constants/.rebuild_patterns) + + echo "$constants_hash yarn-project/constants/scripts/remake-constants.sh --check" # Exclusions: # end-to-end: e2e tests handled separately with end-to-end/bootstrap.sh. diff --git a/yarn-project/constants/.rebuild_patterns b/yarn-project/constants/.rebuild_patterns new file mode 100644 index 000000000000..f526e02984e4 --- /dev/null +++ b/yarn-project/constants/.rebuild_patterns @@ -0,0 +1,10 @@ +^protocol/constants-codegen/ +^noir-projects/noir-protocol-circuits/crates/types/src/constants\.nr$ +^yarn-project/constants/\.rebuild_patterns$ +^yarn-project/constants/src/constants\.gen\.ts$ +^yarn-project/constants/scripts/remake-constants\.sh$ +^barretenberg/cpp/\.clang-format$ +^barretenberg/cpp/src/barretenberg/aztec/aztec_constants\.hpp$ +^barretenberg/cpp/pil/vm2/constants_gen\.pil$ +^l1-contracts/foundry\.toml$ +^l1-contracts/src/core/libraries/ConstantsGen\.sol$ diff --git a/yarn-project/constants/scripts/remake-constants.sh b/yarn-project/constants/scripts/remake-constants.sh index 2f00c56d4dcd..fcbc65e22831 100755 --- a/yarn-project/constants/scripts/remake-constants.sh +++ b/yarn-project/constants/scripts/remake-constants.sh @@ -1,19 +1,69 @@ #!/usr/bin/env bash -set -eu +set -euo pipefail + +if [ "$#" -gt 1 ]; then + echo "Usage: $0 [--check]" >&2 + exit 1 +fi + +check=0 +case "${1:-}" in + "") ;; + --check) check=1 ;; + *) + echo "Usage: $0 [--check]" >&2 + exit 1 + ;; +esac repo_root=$(git rev-parse --show-toplevel) codegen_dir="$repo_root/protocol/constants-codegen" +typescript_output="$repo_root/yarn-project/constants/src/constants.gen.ts" cpp_output="$repo_root/barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp" +pil_output="$repo_root/barretenberg/cpp/pil/vm2/constants_gen.pil" +solidity_output="$repo_root/l1-contracts/src/core/libraries/ConstantsGen.sol" + +temp_dir="" +if [ "$check" -eq 1 ]; then + temp_dir=$(mktemp -d) + trap 'rm -rf "$temp_dir"' EXIT + typescript_output="$temp_dir/constants.gen.ts" + cpp_output="$temp_dir/aztec_constants.hpp" + pil_output="$temp_dir/constants_gen.pil" + solidity_output="$temp_dir/ConstantsGen.sol" +fi + +if [ "$check" -eq 0 ]; then + (cd "$codegen_dir" && yarn install --immutable && yarn build) +elif [ ! -f "$codegen_dir/dest/cli.js" ]; then + echo "constants-codegen must be built before running --check" >&2 + exit 1 +fi -yarn --cwd "$codegen_dir" install --immutable -yarn --cwd "$codegen_dir" build node "$codegen_dir/dest/cli.js" \ --input "$repo_root/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr" \ - --typescript "$repo_root/yarn-project/constants/src/constants.gen.ts" \ + --typescript "$typescript_output" \ --cpp "$cpp_output" \ - --pil "$repo_root/barretenberg/cpp/pil/vm2/constants_gen.pil" \ - --solidity "$repo_root/l1-contracts/src/core/libraries/ConstantsGen.sol" + --pil "$pil_output" \ + --solidity "$solidity_output" + +clang-format-20 --style="file:$repo_root/barretenberg/cpp/.clang-format" -i "$cpp_output" +(cd "$repo_root/l1-contracts" && forge fmt "$solidity_output") -clang-format-20 -i "$cpp_output" -(cd "$repo_root/l1-contracts" && forge fmt) +if [ "$check" -eq 1 ]; then + failed=0 + if ! diff -u "$repo_root/yarn-project/constants/src/constants.gen.ts" "$typescript_output"; then + failed=1 + fi + if ! diff -u "$repo_root/barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp" "$cpp_output"; then + failed=1 + fi + if ! diff -u "$repo_root/barretenberg/cpp/pil/vm2/constants_gen.pil" "$pil_output"; then + failed=1 + fi + if ! diff -u "$repo_root/l1-contracts/src/core/libraries/ConstantsGen.sol" "$solidity_output"; then + failed=1 + fi + exit "$failed" +fi From 68602b1ad710bb5d7956966f0a2423f6c61627da Mon Sep 17 00:00:00 2001 From: mverzilli Date: Wed, 15 Jul 2026 09:25:57 +0000 Subject: [PATCH 05/12] fix(constants-codegen): preserve additional Noir constants --- protocol/constants-codegen/README.md | 6 ++-- protocol/constants-codegen/src/cli.ts | 30 +++++++++++++++++- .../constants-codegen/src/generator.test.ts | 31 ++++++++++++++++--- protocol/constants-codegen/src/generator.ts | 7 ++++- yarn-project/constants/.rebuild_patterns | 1 + .../constants/scripts/remake-constants.sh | 2 ++ 6 files changed, 69 insertions(+), 8 deletions(-) diff --git a/protocol/constants-codegen/README.md b/protocol/constants-codegen/README.md index 3f8fd25255a2..382a70f43568 100644 --- a/protocol/constants-codegen/README.md +++ b/protocol/constants-codegen/README.md @@ -4,12 +4,13 @@ This directory will contain the standalone cross-language generator for Aztec pr ## Version 1 interface -The command reads one Noir source file and writes any requested combination of the four outputs produced by the -existing generator. +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. ```text constants-codegen \ --input \ + [--include :]... \ [--typescript ] \ [--cpp ] \ [--pil ] \ @@ -17,6 +18,7 @@ constants-codegen \ ``` - `--input` is required. +- `--include` adds one named constant from another Noir file before evaluating expressions. It may be repeated. - At least one output option is required, and any combination of output options may be used in one invocation. - Relative paths are resolved from the caller's working directory. The tool does not infer paths from the monorepo layout. diff --git a/protocol/constants-codegen/src/cli.ts b/protocol/constants-codegen/src/cli.ts index 985a64e11eb0..9d409bca94df 100644 --- a/protocol/constants-codegen/src/cli.ts +++ b/protocol/constants-codegen/src/cli.ts @@ -5,6 +5,7 @@ import { parseArgs } from 'node:util'; import { type ParsedContent, + evaluateExpressions, generateCppConstants, generatePilConstants, generateSolidityConstants, @@ -19,12 +20,23 @@ interface RequestedOutput { generate: GenerateOutput; } +function parseIncludedConstant(value: string): { path: string; symbol: string } { + const separatorIndex = value.lastIndexOf(':'); + const path = value.slice(0, separatorIndex); + const symbol = value.slice(separatorIndex + 1); + if (separatorIndex <= 0 || !/^\w+$/.test(symbol)) { + throw new Error(`invalid --include value '${value}', expected :`); + } + return { path, symbol }; +} + function run(args: string[]): void { const { values } = parseArgs({ args, allowPositionals: false, options: { input: { type: 'string' }, + include: { type: 'string', multiple: true }, typescript: { type: 'string' }, cpp: { type: 'string' }, pil: { type: 'string' }, @@ -48,7 +60,23 @@ function run(args: string[]): void { throw new Error('at least one output option is required'); } - const parsedContent = parseNoirFile(readFileSync(values.input, 'utf8')); + const { constantsExpressions, domainSeparatorEnum } = parseNoirFile(readFileSync(values.input, 'utf8')); + for (const value of values.include ?? []) { + const { path, symbol } = parseIncludedConstant(value); + const { constantsExpressions: includedExpressions } = parseNoirFile(readFileSync(path, 'utf8'), { + stripLineComments: true, + }); + const expression = includedExpressions.find(([name]) => name === symbol); + if (!expression) { + throw new Error(`constant '${symbol}' not found in ${path}`); + } + constantsExpressions.push(expression); + } + + const parsedContent: ParsedContent = { + constants: evaluateExpressions(constantsExpressions), + domainSeparatorEnum, + }; for (const output of outputs) { mkdirSync(dirname(output.path), { recursive: true }); diff --git a/protocol/constants-codegen/src/generator.test.ts b/protocol/constants-codegen/src/generator.test.ts index e1a171bef2ab..546a54347222 100644 --- a/protocol/constants-codegen/src/generator.test.ts +++ b/protocol/constants-codegen/src/generator.test.ts @@ -8,6 +8,7 @@ import { fileURLToPath } from 'node:url'; import { type ParsedContent, + evaluateExpressions, generateCppConstants, generatePilConstants, generateSolidityConstants, @@ -27,7 +28,8 @@ function generateToString(generate: (content: ParsedContent, targetPath: string) const tempDir = mkdtempSync(join(tmpdir(), 'constants-codegen-')); const targetPath = join(tempDir, 'output'); try { - generate(parseNoirFile(noirFixture), targetPath); + const { constantsExpressions, domainSeparatorEnum } = parseNoirFile(noirFixture); + generate({ constants: evaluateExpressions(constantsExpressions), domainSeparatorEnum }, targetPath); return readFileSync(targetPath, 'utf8'); } finally { rmSync(tempDir, { recursive: true, force: true }); @@ -77,17 +79,38 @@ test('generates the existing Solidity subset', () => { test('the CLI generates multiple requested outputs', () => { const tempDir = mkdtempSync(join(tmpdir(), 'constants-codegen-cli-')); const inputPath = join(tempDir, 'constants.nr'); + const includedInputPath = join(tempDir, 'additional.nr'); const typescriptPath = join(tempDir, 'typescript', 'constants.ts'); const cppPath = join(tempDir, 'cpp', 'constants.hpp'); const cliPath = join(dirname(fileURLToPath(import.meta.url)), 'cli.js'); try { writeFileSync(inputPath, noirFixture); - execFileSync(process.execPath, [cliPath, '--input', inputPath, '--typescript', typescriptPath, '--cpp', cppPath], { - stdio: 'pipe', - }); + writeFileSync( + includedInputPath, + `pub global INCLUDED_CONSTANT: u32 = ARCHIVE_HEIGHT + 1; // selected for export +pub global EXCLUDED_CONSTANT: u32 = 100; +`, + ); + execFileSync( + process.execPath, + [ + cliPath, + '--input', + inputPath, + '--include', + `${includedInputPath}:INCLUDED_CONSTANT`, + '--typescript', + typescriptPath, + '--cpp', + cppPath, + ], + { stdio: 'pipe' }, + ); assert.match(readFileSync(typescriptPath, 'utf8'), /export const ARCHIVE_HEIGHT = 30;/); + assert.match(readFileSync(typescriptPath, 'utf8'), /export const INCLUDED_CONSTANT = 31;/); + assert.doesNotMatch(readFileSync(typescriptPath, 'utf8'), /EXCLUDED_CONSTANT/); assert.match(readFileSync(cppPath, 'utf8'), /#define ARCHIVE_HEIGHT 30/); } finally { rmSync(tempDir, { recursive: true, force: true }); diff --git a/protocol/constants-codegen/src/generator.ts b/protocol/constants-codegen/src/generator.ts index 1bc00fd7386f..daad3e49504d 100644 --- a/protocol/constants-codegen/src/generator.ts +++ b/protocol/constants-codegen/src/generator.ts @@ -355,9 +355,14 @@ export interface ParsedContent { domainSeparatorEnum: { [key: string]: number }; } -/** Raw expressions parsed from Noir source before cross-file evaluation. */ +/** + * Raw expressions parsed from a Noir file, prior to evaluation. Keeping expressions unevaluated lets callers merge + * constants from multiple files and resolve cross-file references in a single evaluation pass. + */ export interface ParsedExpressions { + /** Ordered list of constant name and expression pairs. */ constantsExpressions: [string, string][]; + /** DomainSeparatorEnum members. */ domainSeparatorEnum: { [key: string]: number }; } diff --git a/yarn-project/constants/.rebuild_patterns b/yarn-project/constants/.rebuild_patterns index f526e02984e4..7667045c9566 100644 --- a/yarn-project/constants/.rebuild_patterns +++ b/yarn-project/constants/.rebuild_patterns @@ -1,5 +1,6 @@ ^protocol/constants-codegen/ ^noir-projects/noir-protocol-circuits/crates/types/src/constants\.nr$ +^noir-projects/noir-protocol-circuits/crates/types/src/blob_data/tx_blob_data\.nr$ ^yarn-project/constants/\.rebuild_patterns$ ^yarn-project/constants/src/constants\.gen\.ts$ ^yarn-project/constants/scripts/remake-constants\.sh$ diff --git a/yarn-project/constants/scripts/remake-constants.sh b/yarn-project/constants/scripts/remake-constants.sh index fcbc65e22831..7d5e1ba48ad7 100755 --- a/yarn-project/constants/scripts/remake-constants.sh +++ b/yarn-project/constants/scripts/remake-constants.sh @@ -19,6 +19,7 @@ esac repo_root=$(git rev-parse --show-toplevel) codegen_dir="$repo_root/protocol/constants-codegen" +additional_input="$repo_root/noir-projects/noir-protocol-circuits/crates/types/src/blob_data/tx_blob_data.nr:MAX_TX_BLOB_DATA_SIZE_IN_FIELDS" typescript_output="$repo_root/yarn-project/constants/src/constants.gen.ts" cpp_output="$repo_root/barretenberg/cpp/src/barretenberg/aztec/aztec_constants.hpp" pil_output="$repo_root/barretenberg/cpp/pil/vm2/constants_gen.pil" @@ -43,6 +44,7 @@ fi node "$codegen_dir/dest/cli.js" \ --input "$repo_root/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr" \ + --include "$additional_input" \ --typescript "$typescript_output" \ --cpp "$cpp_output" \ --pil "$pil_output" \ From 078164afba495b5e1edc3482dc4b992de8623877 Mon Sep 17 00:00:00 2001 From: mverzilli Date: Wed, 15 Jul 2026 10:01:55 +0000 Subject: [PATCH 06/12] fix(constants-codegen): build before packaging --- protocol/constants-codegen/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/protocol/constants-codegen/package.json b/protocol/constants-codegen/package.json index 3f0cb7286771..b37cef67b06f 100644 --- a/protocol/constants-codegen/package.json +++ b/protocol/constants-codegen/package.json @@ -14,6 +14,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "clean": "rm -rf dest", + "prepack": "yarn build", "test": "yarn build && node --test dest/*.test.js" }, "devDependencies": { From 21f48d8c941570ae370f908afa1ddca796c893de Mon Sep 17 00:00:00 2001 From: mverzilli Date: Wed, 15 Jul 2026 10:23:23 +0000 Subject: [PATCH 07/12] feat(constants-codegen): publish release package --- bootstrap.sh | 21 +++++++------ protocol/constants-codegen/bootstrap.sh | 7 ++++- protocol/constants-codegen/package.json | 2 +- .../constants-codegen/scripts/test-package.sh | 30 +++++++++++++++++++ 4 files changed, 49 insertions(+), 11 deletions(-) create mode 100755 protocol/constants-codegen/scripts/test-package.sh diff --git a/bootstrap.sh b/bootstrap.sh index 42e87fc8eb47..d2903bb09b7a 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -579,6 +579,7 @@ function release { noir l1-contracts noir-projects/aztec-nr + protocol/constants-codegen yarn-project boxes aztec-up @@ -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. @@ -619,15 +621,16 @@ function private_release { ci3/gcp_artifact_login set +x # Never echo the access token. export NPM_TOKEN=$(gcloud auth print-access-token) - # Route our scope to the internal npm registry; public deps still resolve from the default registry - # (npmjs), so publishes and yarn-project's install smoke-test both work. Everything we publish is - # @aztec-scoped — the noir packages are renamed @noir-lang/* -> @aztec/noir-* on release. Exported so - # deploy_npm and that smoke-test share one config. + # Route our scopes to the internal npm registry; public deps still resolve from the default registry + # (npmjs), so publishes and yarn-project's install smoke-test both work. Everything we publish uses + # either the @aztec or @aztec-foundation scope — the noir packages are renamed @noir-lang/* -> + # @aztec/noir-* on release. Exported so deploy_npm and that smoke-test share one config. local npmrc reg reg="${INTERNAL_NPM_REGISTRY%/}/" npmrc=$(mktemp) (umask 077; { echo "@aztec:registry=$reg" + echo "@aztec-foundation:registry=$reg" echo "${reg#https:}:_authToken=\${NPM_TOKEN}" } > "$npmrc") export NPM_CONFIG_GLOBALCONFIG="$npmrc" @@ -671,7 +674,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 diff --git a/protocol/constants-codegen/bootstrap.sh b/protocol/constants-codegen/bootstrap.sh index 17367a3095c2..bbf7dca2c295 100755 --- a/protocol/constants-codegen/bootstrap.sh +++ b/protocol/constants-codegen/bootstrap.sh @@ -11,7 +11,7 @@ function build { } function test_cmds { - echo "$hash cd protocol/constants-codegen && node --test dest/*.test.js" + echo "$hash cd protocol/constants-codegen && node --test dest/*.test.js && ./scripts/test-package.sh" } function test { @@ -19,6 +19,11 @@ function test { test_cmds | filter_test_cmds | parallelize } +function release { + npm_install_deps + retry "deploy_npm ${REF_NAME#v}" +} + case "$cmd" in "") build diff --git a/protocol/constants-codegen/package.json b/protocol/constants-codegen/package.json index b37cef67b06f..6d9df2b6c856 100644 --- a/protocol/constants-codegen/package.json +++ b/protocol/constants-codegen/package.json @@ -15,7 +15,7 @@ "build": "tsc -p tsconfig.json", "clean": "rm -rf dest", "prepack": "yarn build", - "test": "yarn build && node --test dest/*.test.js" + "test": "yarn build && node --test dest/*.test.js && ./scripts/test-package.sh" }, "devDependencies": { "@types/node": "^22", diff --git a/protocol/constants-codegen/scripts/test-package.sh b/protocol/constants-codegen/scripts/test-package.sh new file mode 100755 index 000000000000..3a27895622f7 --- /dev/null +++ b/protocol/constants-codegen/scripts/test-package.sh @@ -0,0 +1,30 @@ +#!/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 --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" +output="$work_dir/constants.ts" +printf 'pub global ARCHIVE_HEIGHT: u32 = 30;\n' > "$input" + +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 "$output" +) + +grep -Fq 'export const ARCHIVE_HEIGHT = 30;' "$output" From 62dd20b4023e749fcd5939b089cfdf4aee0feb75 Mon Sep 17 00:00:00 2001 From: mverzilli Date: Wed, 15 Jul 2026 10:33:58 +0000 Subject: [PATCH 08/12] test(constants-codegen): keep package smoke test read-only --- protocol/constants-codegen/scripts/test-package.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/protocol/constants-codegen/scripts/test-package.sh b/protocol/constants-codegen/scripts/test-package.sh index 3a27895622f7..b328c95c3cb8 100755 --- a/protocol/constants-codegen/scripts/test-package.sh +++ b/protocol/constants-codegen/scripts/test-package.sh @@ -6,7 +6,7 @@ package_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) work_dir=$(mktemp -d) trap 'rm -rf "$work_dir"' EXIT -(cd "$package_dir" && npm pack --pack-destination "$work_dir" --quiet >/dev/null) +(cd "$package_dir" && npm pack --ignore-scripts --pack-destination "$work_dir" --quiet >/dev/null) shopt -s nullglob tarballs=("$work_dir"/*.tgz) @@ -27,4 +27,8 @@ mkdir "$work_dir/consumer" ./node_modules/.bin/constants-codegen --input "$input" --typescript "$output" ) -grep -Fq 'export const ARCHIVE_HEIGHT = 30;' "$output" +if ! grep -Fq 'export const ARCHIVE_HEIGHT = 30;' "$output"; then + echo "installed constants-codegen produced unexpected TypeScript output:" >&2 + cat "$output" >&2 + exit 1 +fi From 7a1127c1beb7abda3689564b3f2f6900fd2dde19 Mon Sep 17 00:00:00 2001 From: mverzilli Date: Tue, 21 Jul 2026 11:15:06 +0000 Subject: [PATCH 09/12] publish to @aztec --- bootstrap.sh | 9 ++++----- protocol/constants-codegen/package.json | 2 +- protocol/constants-codegen/yarn.lock | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index d2903bb09b7a..ba62a9aa5166 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -621,16 +621,15 @@ function private_release { ci3/gcp_artifact_login set +x # Never echo the access token. export NPM_TOKEN=$(gcloud auth print-access-token) - # Route our scopes to the internal npm registry; public deps still resolve from the default registry - # (npmjs), so publishes and yarn-project's install smoke-test both work. Everything we publish uses - # either the @aztec or @aztec-foundation scope — the noir packages are renamed @noir-lang/* -> - # @aztec/noir-* on release. Exported so deploy_npm and that smoke-test share one config. + # Route our scope to the internal npm registry; public deps still resolve from the default registry + # (npmjs), so publishes and yarn-project's install smoke-test both work. Everything we publish is + # @aztec-scoped — the noir packages are renamed @noir-lang/* -> @aztec/noir-* on release. Exported so + # deploy_npm and that smoke-test share one config. local npmrc reg reg="${INTERNAL_NPM_REGISTRY%/}/" npmrc=$(mktemp) (umask 077; { echo "@aztec:registry=$reg" - echo "@aztec-foundation:registry=$reg" echo "${reg#https:}:_authToken=\${NPM_TOKEN}" } > "$npmrc") export NPM_CONFIG_GLOBALCONFIG="$npmrc" diff --git a/protocol/constants-codegen/package.json b/protocol/constants-codegen/package.json index 6d9df2b6c856..309c1a9a1a2d 100644 --- a/protocol/constants-codegen/package.json +++ b/protocol/constants-codegen/package.json @@ -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", diff --git a/protocol/constants-codegen/yarn.lock b/protocol/constants-codegen/yarn.lock index bdef6ad3ffa2..674272fd6033 100644 --- a/protocol/constants-codegen/yarn.lock +++ b/protocol/constants-codegen/yarn.lock @@ -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.6.3" From 8362f44d9377bc9e7524550c289e703a64c0c7f4 Mon Sep 17 00:00:00 2001 From: mverzilli Date: Tue, 21 Jul 2026 11:21:48 +0000 Subject: [PATCH 10/12] add package tests for c++, solidity, pil --- .../constants-codegen/scripts/test-package.sh | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/protocol/constants-codegen/scripts/test-package.sh b/protocol/constants-codegen/scripts/test-package.sh index b328c95c3cb8..7c19edc5ed5f 100755 --- a/protocol/constants-codegen/scripts/test-package.sh +++ b/protocol/constants-codegen/scripts/test-package.sh @@ -16,19 +16,37 @@ if [ "${#tarballs[@]}" -ne 1 ]; then fi input="$work_dir/constants.nr" -output="$work_dir/constants.ts" -printf 'pub global ARCHIVE_HEIGHT: u32 = 30;\n' > "$input" +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 "$output" + ./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" ) -if ! grep -Fq 'export const ARCHIVE_HEIGHT = 30;' "$output"; then - echo "installed constants-codegen produced unexpected TypeScript output:" >&2 - cat "$output" >&2 - exit 1 -fi +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;' From b8a057fac8011fb76c4236470bab9786b9145163 Mon Sep 17 00:00:00 2001 From: mverzilli Date: Tue, 21 Jul 2026 11:47:35 +0000 Subject: [PATCH 11/12] add support for rust --- protocol/constants-codegen/README.md | 8 +++- .../constants-codegen/scripts/test-package.sh | 4 +- protocol/constants-codegen/src/cli.ts | 3 ++ .../constants-codegen/src/generator.test.ts | 16 ++++++++ protocol/constants-codegen/src/generator.ts | 37 +++++++++++++++++++ 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/protocol/constants-codegen/README.md b/protocol/constants-codegen/README.md index 382a70f43568..e1d911abd0f8 100644 --- a/protocol/constants-codegen/README.md +++ b/protocol/constants-codegen/README.md @@ -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 \ @@ -14,7 +14,8 @@ constants-codegen \ [--typescript ] \ [--cpp ] \ [--pil ] \ - [--solidity ] + [--solidity ] \ + [--rust ] ``` - `--input` is required. @@ -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: diff --git a/protocol/constants-codegen/scripts/test-package.sh b/protocol/constants-codegen/scripts/test-package.sh index 7c19edc5ed5f..3bdbf78d7f69 100755 --- a/protocol/constants-codegen/scripts/test-package.sh +++ b/protocol/constants-codegen/scripts/test-package.sh @@ -33,7 +33,8 @@ mkdir "$work_dir/consumer" --typescript "$work_dir/constants.ts" \ --cpp "$work_dir/constants.hpp" \ --pil "$work_dir/constants.pil" \ - --solidity "$work_dir/Constants.sol" + --solidity "$work_dir/Constants.sol" \ + --rust "$work_dir/constants.rs" ) function check_output { @@ -50,3 +51,4 @@ 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;' diff --git a/protocol/constants-codegen/src/cli.ts b/protocol/constants-codegen/src/cli.ts index 42838e64c626..8bf4ca063481 100644 --- a/protocol/constants-codegen/src/cli.ts +++ b/protocol/constants-codegen/src/cli.ts @@ -8,6 +8,7 @@ import { evaluateExpressions, generateCppConstants, generatePilConstants, + generateRustConstants, generateSolidityConstants, generateTypescriptConstants, parseNoirFile, @@ -41,6 +42,7 @@ function run(args: string[]): void { cpp: { type: 'string' }, pil: { type: 'string' }, solidity: { type: 'string' }, + rust: { type: 'string' }, }, strict: true, }); @@ -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) { diff --git a/protocol/constants-codegen/src/generator.test.ts b/protocol/constants-codegen/src/generator.test.ts index 5449afc10a9b..ddb6e62bab22 100644 --- a/protocol/constants-codegen/src/generator.test.ts +++ b/protocol/constants-codegen/src/generator.test.ts @@ -11,6 +11,7 @@ import { evaluateExpressions, generateCppConstants, generatePilConstants, + generateRustConstants, generateSolidityConstants, generateTypescriptConstants, parseNoirFile, @@ -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); diff --git a/protocol/constants-codegen/src/generator.ts b/protocol/constants-codegen/src/generator.ts index daad3e49504d..e69e69307be8 100644 --- a/protocol/constants-codegen/src/generator.ts +++ b/protocol/constants-codegen/src/generator.ts @@ -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. */ @@ -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. */ From 545fb01f45be55445b40083384e7dfb42c6cb1fd Mon Sep 17 00:00:00 2001 From: mverzilli Date: Tue, 21 Jul 2026 11:50:40 +0000 Subject: [PATCH 12/12] emit each test cmd in its own line --- protocol/constants-codegen/bootstrap.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/constants-codegen/bootstrap.sh b/protocol/constants-codegen/bootstrap.sh index e2ba21659299..cc7fe43c409d 100755 --- a/protocol/constants-codegen/bootstrap.sh +++ b/protocol/constants-codegen/bootstrap.sh @@ -14,7 +14,8 @@ function build { } function test_cmds { - echo "$hash cd protocol/constants-codegen && node --test src/*.test.ts && ./scripts/test-package.sh" + echo "$hash cd protocol/constants-codegen && node --test src/*.test.ts" + echo "$hash cd protocol/constants-codegen && ./scripts/test-package.sh" } function test {