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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion noir-projects/aztec-nr/aztec/src/macros/functions/utils.nr
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,45 @@ pub(crate) comptime fn transform_public(f: FunctionDefinition) -> Quoted {
fn_abi
}

pub(crate) comptime fn transform_unconstrained(f: FunctionDefinition) {
pub(crate) comptime fn find_and_transform_top_level_unconstrained_fns(m: Module) {
// Top-level unconstrained fns are contract entrypoints, but they're not explicitly designated in any way. They're
// the fallback case for a function that matches no other rules.
// TODO(#12743): improve this

// We first find non-standard contract entrypoints, i.e. functions in the `contract` mod that are not private or
// public, but which *are* contract entrypoints (i.e. they're not opting out via the #[test] or
// #[contract_library_method] attributes). Ideally entrypoints would be explicitly designated instead.
let non_private_public_entrypoint_functions = m.functions().filter(|f: FunctionDefinition| {
!f.has_named_attribute("private")
& !f.has_named_attribute("public")
& !f.has_named_attribute("contract_library_method")
& !f.has_named_attribute("test")
});

// TODO: uncomment the code below and emit a warning once support for them is added to Noir (tracked in
// https://github.com/noir-lang/noir/issues/7714). We can't simply print a message since that'd otherwise break the
// output of utils such as `nargo test --list-tests`.
// // We don't expect to see any custom constrained entrypoints (i.e. private functions created outside of aztec-nr's
// // #[private] macro, possibly resulting in a non-standard interface).
// for f in non_private_public_entrypoint_functions.filter(|f: FunctionDefinition| {
// !f.is_unconstrained()
// }) {
// let name = f.name();
// warn(
// f"found private contract function '{name}' which does not have the #[private] attribute - make sure you know what you're doing!",
// );
// }

// An unconstrained contract entrypoints is what we call a top-level unconstrained function, to which we apply the
// appropriate transformation. Ideally these would be explicitly designated as such instead.
for f in non_private_public_entrypoint_functions.filter(|f: FunctionDefinition| {
f.is_unconstrained()
}) {
transform_top_level_unconstrained(f);
}
}

pub(crate) comptime fn transform_top_level_unconstrained(f: FunctionDefinition) {
let context_creation = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); };
let module_has_storage = module_has_storage(f.module());

Expand Down
13 changes: 6 additions & 7 deletions noir-projects/aztec-nr/aztec/src/macros/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ pub mod notes;
pub mod storage;
pub mod events;

use functions::{stub_registry, utils::{create_note_discovery_call, transform_unconstrained}};
use functions::{
stub_registry,
utils::{create_note_discovery_call, find_and_transform_top_level_unconstrained_fns},
};
use notes::{generate_note_export, NOTES};
use storage::STORAGE_LAYOUT_NAME;

Expand All @@ -19,12 +22,8 @@ use crate::discovery::MAX_NOTE_PACKED_LEN;
/// Note: This is a module annotation, so the returned quote gets injected inside the module (contract) itself.
pub comptime fn aztec(m: Module) -> Quoted {
let interface = generate_contract_interface(m);
let unconstrained_functions = m.functions().filter(|f: FunctionDefinition| {
f.is_unconstrained() & !f.has_named_attribute("test") & !f.has_named_attribute("public")
});
for f in unconstrained_functions {
transform_unconstrained(f);
}

find_and_transform_top_level_unconstrained_fns(m);

let contract_library_method_compute_note_hash_and_nullifier =
generate_contract_library_method_compute_note_hash_and_nullifier();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,13 @@ pub contract AvmTest {

#[public]
fn add_args_return(arg_a: Field, arg_b: Field) -> Field {
arg_a + arg_b
add(arg_a, arg_b)
}

// Auxiliary method to test usage of contract library methods in public fns
#[contract_library_method]
unconstrained fn add(lhs: Field, rhs: Field) -> Field {
lhs + rhs
}

/************************************************************************
Expand Down Expand Up @@ -210,10 +216,13 @@ pub contract AvmTest {
}

// Helper functions to demonstrate an internal call stack in error messages
#[contract_library_method]
fn inner_helper_with_failed_assertion() {
let not_true = false;
assert(not_true == true, "This assertion should fail!");
}

#[contract_library_method]
Comment on lines +219 to +225

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fcarreiro these functions were being called directly from public functions like any regular noir function, but any fn directly inside the contract mod gets made a contract entrypoint automatically (weird I know). We now detect and warn when we see these, so I added the contract_library_method attribute, which makes the fn not be an entrypoint (weird I know), which I assume is what you originally intended.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks yes! I guess they should be unconstrained as well? In any case if this works we can check later

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need, they'll be converted to unconstrained automatically if called from an unconstrained fn (like public fns are). We'd only need to make this helper unconstrained if we needed to use any of the unconstrained features (e.g. while or break).

fn helper_with_failed_assertion() {
inner_helper_with_failed_assertion();
}
Expand Down