Skip to content

Commit d2e940f

Browse files
committed
feat(canonical-contracts): autogen Noir interface stubs from compiled artifacts
1 parent 46466fd commit d2e940f

6 files changed

Lines changed: 436 additions & 25 deletions

File tree

noir-projects/aztec-nr/aztec/src/authwit/auth_registry_interface.nr

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
// GENERATED FILE - DO NOT EDIT
2+
//
3+
// Written by `yarn-project/canonical-contracts/src/scripts/generate_interfaces.ts` from the compiled
4+
// `AuthRegistry` artifact. Regenerate with
5+
// `yarn workspace @aztec/canonical-contracts run regen:canonical-interfaces`.
6+
//
7+
// The selectors below are derived via `comptime { FunctionSelector::from_signature(...) }` at
8+
// Noir compile time, with the signature string emitted from the artifact's parameter list. This
9+
// keeps the wrapper in lockstep with whatever the `#[aztec]` macro generates for the real
10+
// contract; any drift between the contract's external signatures and this file fails the
11+
// `generate_interfaces.test.ts` freshness gate.
12+
113
use crate::context::calls::{PublicCall, PublicStaticCall};
214
use crate::protocol::{abis::function_selector::FunctionSelector, address::AztecAddress, traits::ToField};
315

4-
/// Hand-written interface stub for the `AuthRegistry` canonical contract.
5-
///
6-
/// The `AuthRegistry` contract records public authentication witnesses
7-
/// (`set_authorized`, `set_reject_all`) and atomically consumes them at
8-
/// the consumer (`consume`). Consumer code in aztec-nr's `authwit::public`
9-
/// module calls into the registry via this interface.
10-
///
11-
/// The selectors are derived with `comptime { FunctionSelector::from_signature(...) }`,
12-
/// which matches exactly what the `#[aztec]` macro generates for the real contract.
1316
pub struct AuthRegistryInterface {
1417
pub target_contract: AztecAddress,
1518
}

noir-projects/aztec-nr/aztec/src/public_checks_interface.nr

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
// GENERATED FILE - DO NOT EDIT
2+
//
3+
// Written by `yarn-project/canonical-contracts/src/scripts/generate_interfaces.ts` from the compiled
4+
// `PublicChecks` artifact. Regenerate with
5+
// `yarn workspace @aztec/canonical-contracts run regen:canonical-interfaces`.
6+
//
7+
// The selectors below are derived via `comptime { FunctionSelector::from_signature(...) }` at
8+
// Noir compile time, with the signature string emitted from the artifact's parameter list. This
9+
// keeps the wrapper in lockstep with whatever the `#[aztec]` macro generates for the real
10+
// contract; any drift between the contract's external signatures and this file fails the
11+
// `generate_interfaces.test.ts` freshness gate.
12+
113
use crate::context::calls::PublicStaticCall;
2-
use crate::protocol::abis::function_selector::FunctionSelector;
3-
use crate::protocol::address::AztecAddress;
14+
use crate::protocol::{abis::function_selector::FunctionSelector, address::AztecAddress};
415

5-
/// Hand-written interface stub for the `PublicChecks` canonical contract.
6-
///
7-
/// The `PublicChecks` contract exposes two view functions that can be enqueued
8-
/// from private context via `enqueue_view_incognito` to assert timestamp or
9-
/// block-number constraints without revealing the calling contract address.
10-
///
11-
/// The selectors are derived with `comptime { FunctionSelector::from_signature(...) }`,
12-
/// which matches exactly what the `#[aztec]` macro generates for the real contract.
1316
pub struct PublicChecksInterface {
1417
pub target_contract: AztecAddress,
1518
}
@@ -19,22 +22,22 @@ impl PublicChecksInterface {
1922
Self { target_contract }
2023
}
2124

22-
pub fn check_timestamp(self, operation: u8, value: u64) -> PublicStaticCall<15, 2, ()> {
23-
let selector = comptime { FunctionSelector::from_signature("check_timestamp(u8,u64)") };
25+
pub fn check_block_number(self, operation: u8, value: u32) -> PublicStaticCall<18, 2, ()> {
26+
let selector = comptime { FunctionSelector::from_signature("check_block_number(u8,u32)") };
2427
PublicStaticCall::new(
2528
self.target_contract,
2629
selector,
27-
"check_timestamp",
30+
"check_block_number",
2831
[operation as Field, value as Field],
2932
)
3033
}
3134

32-
pub fn check_block_number(self, operation: u8, value: u32) -> PublicStaticCall<18, 2, ()> {
33-
let selector = comptime { FunctionSelector::from_signature("check_block_number(u8,u32)") };
35+
pub fn check_timestamp(self, operation: u8, value: u64) -> PublicStaticCall<15, 2, ()> {
36+
let selector = comptime { FunctionSelector::from_signature("check_timestamp(u8,u64)") };
3437
PublicStaticCall::new(
3538
self.target_contract,
3639
selector,
37-
"check_block_number",
40+
"check_timestamp",
3841
[operation as Field, value as Field],
3942
)
4043
}

yarn-project/canonical-contracts/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"generate": "yarn generate:data",
1818
"generate:data": "node --no-warnings --loader @swc-node/register/esm src/scripts/generate_data.ts",
1919
"regen:auth-registry-address": "node --experimental-vm-modules dest/scripts/derive_auth_registry.js",
20+
"regen:canonical-interfaces": "node --no-warnings --loader @swc-node/register/esm src/scripts/generate_interfaces.ts",
2021
"regen:multi-call-entrypoint-address": "node --experimental-vm-modules dest/scripts/derive_multi_call_entrypoint.js",
2122
"regen:public-checks-address": "node --experimental-vm-modules dest/scripts/derive_public_checks.js",
2223
"build:dev": "../scripts/tsc.sh --watch",
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { NoirCompiledContract } from '@aztec/stdlib/noir';
2+
3+
import { promises as fs } from 'node:fs';
4+
5+
import { ALL_INTERFACES, renderInterfaceFile } from './generate_interfaces.js';
6+
7+
const REGEN_HINT =
8+
'canonical interface stubs are stale; run `yarn workspace @aztec/canonical-contracts run regen:canonical-interfaces` and commit the result.';
9+
10+
describe('canonical interface stub freshness', () => {
11+
for (const spec of ALL_INTERFACES) {
12+
describe(spec.interfaceName, () => {
13+
let artifactExists = false;
14+
beforeAll(async () => {
15+
artifactExists = await fs
16+
.access(spec.artifactPath)
17+
.then(() => true)
18+
.catch(() => false);
19+
});
20+
21+
it('on-disk .gen.nr matches the freshly-rendered output', async () => {
22+
if (!artifactExists) {
23+
// Artifact is produced by `./bootstrap.sh build` (or `nargo compile` +
24+
// `bb aztec_process` for the noir-contracts package). Skip with a clear message
25+
// rather than fail when the artifact has not been built yet — the dedicated CI
26+
// job that runs this test ensures the artifact is on disk before invoking jest.
27+
console.warn(`Skipping ${spec.interfaceName}: ${spec.artifactPath} not found.`);
28+
return;
29+
}
30+
const artifact = JSON.parse(await fs.readFile(spec.artifactPath, 'utf8')) as NoirCompiledContract;
31+
const expected = renderInterfaceFile(spec, artifact);
32+
const actual = await fs.readFile(spec.outputPath, 'utf8');
33+
34+
if (actual !== expected) {
35+
throw new Error(REGEN_HINT);
36+
}
37+
});
38+
39+
it('render is deterministic for the same artifact', async () => {
40+
if (!artifactExists) {
41+
return;
42+
}
43+
const artifact = JSON.parse(await fs.readFile(spec.artifactPath, 'utf8')) as NoirCompiledContract;
44+
expect(renderInterfaceFile(spec, artifact)).toEqual(renderInterfaceFile(spec, artifact));
45+
});
46+
});
47+
}
48+
});

0 commit comments

Comments
 (0)