Skip to content

Commit 5250359

Browse files
committed
refactor: cleaning up macros::functions::utils
This PR was quite a journey: ## Step 1 When trying to figure out how to rename the incorrectly named `get_fn_visibility` in a PR down the stack I realized that it's better to just drop it because: - it was only used by `create_assert_correct_initializer_args`, `create_mark_as_initialized` and `create_init_check` functions which in turn where only called in `transfrom_private` and `transform_public`, - these functions contained only 2 lines of code. Because of this ^ it's better to just directly inline contents of these funcs into the `transform_*` functions. When I finished this I checked where are the is `is_fn_private` and `is_fn_public` utils used which led me to step 2: ## Step 2 When checking when are the above mentioned functions used I realized that we use them in `create_authorize_once_check` and in the `stub_fn`. In both of these cases the code was just terrible because these functions are called from `transform_private` and `transform_public` functions hence the flow was: `transform_private` --> `stub_fn` --> are we in private? --> if yes call `create_private_stub` which I could replace with: `transform_private` --> `create_private_stub` So I dropped the `stub_fn` and just called the `create_private_stub` directly. The similar was the case for `create_authorize_once_check` where I could simply pass in an `is_private` arg to the function and get rid of the `is_fn_private` dependency. ## Step 3 Once I did this I realized that I don't need the `EXTERNAL_REGISTRY` I introduced in the PR down the stack at all, removing a lot of the sad ugly complexity I needed to introduce there 🎉 ## Future work - The whole `noir-projects/aztec-nr/aztec/src/macros/functions` directory is very messy and I plan on move the code around into more logical places in the dir once this stack of PRs is merged. - I think the `stub` name is non-descriptive enough so will try to come up with something better. Co-authored-by: Jan Beneš <[email protected]>
1 parent be597f9 commit 5250359

File tree

6 files changed

+76
-144
lines changed

6 files changed

+76
-144
lines changed

noir-projects/aztec-nr/aztec/src/macros/functions/call_interface_stubs.nr

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// This file generates call interface stub functions for Aztec contract methods.
2-
// It creates wrapper functions that serialize arguments and return appropriate call interfaces
3-
// for invoking contract functions across different contexts (private, public, static, utility).
4-
5-
use crate::macros::utils::{
6-
AsStrQuote, compute_fn_selector, is_fn_private, is_fn_public, is_fn_view,
7-
};
1+
//! Stubs are auto-generated wrapper functions that provide an ergonomic interface for cross-contract calls.
2+
//! Instead of manually serializing arguments and creating call interfaces, stubs allow natural syntax, e.g. for
3+
//! enqueuing calls to public functions:
4+
//!
5+
//! ExternalContract.at(address).some_method(arg1, arg2).enqueue()
6+
7+
use crate::macros::utils::{AsStrQuote, compute_fn_selector, is_fn_view};
8+
use super::stub_registry;
89
use protocol_types::meta::utils::derive_serialization_quotes;
910
use std::meta::unquote;
1011

@@ -18,24 +19,27 @@ comptime global FROM_FIELD: TypedExpr = {
1819
.as_typed_expr()
1920
};
2021

21-
pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted {
22-
let is_static_call = is_fn_view(f);
22+
pub comptime fn register_private_fn_stub(f: FunctionDefinition) {
23+
let stub = if is_fn_view(f) {
24+
create_private_static_stub(f)
25+
} else {
26+
create_private_stub(f)
27+
};
28+
stub_registry::register(f.module(), stub);
29+
}
2330

24-
if is_fn_private(f) {
25-
if is_static_call {
26-
create_private_static_stub(f)
27-
} else {
28-
create_private_stub(f)
29-
}
30-
} else if is_fn_public(f) {
31-
if is_static_call {
32-
create_public_static_stub(f)
33-
} else {
34-
create_public_stub(f)
35-
}
31+
pub comptime fn register_public_fn_stub(f: FunctionDefinition) {
32+
let stub = if is_fn_view(f) {
33+
create_public_static_stub(f)
3634
} else {
37-
create_utility_stub(f)
38-
}
35+
create_public_stub(f)
36+
};
37+
stub_registry::register(f.module(), stub);
38+
}
39+
40+
pub comptime fn register_utility_fn_stub(f: FunctionDefinition) {
41+
let stub = create_utility_stub(f);
42+
stub_registry::register(f.module(), stub);
3943
}
4044

4145
/// Utility function creating stubs used by all the stub functions in this file.

noir-projects/aztec-nr/aztec/src/macros/functions/external_registry.nr

Lines changed: 0 additions & 24 deletions
This file was deleted.

noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ pub(crate) mod call_interface_stubs;
55
pub mod initialization_utils;
66
pub(crate) mod stub_registry;
77
pub(crate) mod auth_registry;
8-
pub(crate) mod external_registry;
98
pub(crate) mod utils;
109

1110
use crate::macros::{
@@ -134,9 +133,6 @@ pub comptime fn authorize_once(
134133
/// Same as in Solidity external functions are functions that our callable from outside the contract. External
135134
/// functions can be either private, public, or utility.
136135
pub comptime fn external(f: FunctionDefinition, f_type: CtString) -> Quoted {
137-
// Register the function type in the global registry so helper functions can check it
138-
external_registry::register(f, f_type);
139-
140136
if f_type.eq("private") {
141137
private(f)
142138
} else if f_type.eq("public") {

noir-projects/aztec-nr/aztec/src/macros/functions/stub_registry.nr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// This file provides a registry for storing and retrieving function stubs generated by macros.
22
// It maintains a global hashmap that maps modules to their generated stub functions,
33
// allowing the macro system to collect and organize contract interface stubs.
4+
// See the call_interface_stubs module for more details on what stubs are and how they are generated.
45

56
use poseidon::poseidon2::Poseidon2Hasher;
67
use std::{collections::umap::UHashMap, hash::BuildHasherDefault};

noir-projects/aztec-nr/aztec/src/macros/functions/utils.nr

Lines changed: 48 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
use crate::macros::{
22
functions::{
3-
auth_registry::AUTHORIZE_ONCE_REGISTRY, call_interface_stubs::stub_fn, stub_registry,
3+
auth_registry::AUTHORIZE_ONCE_REGISTRY,
4+
call_interface_stubs::{
5+
register_private_fn_stub, register_public_fn_stub, register_utility_fn_stub,
6+
},
47
},
58
notes::NOTES,
69
utils::{
7-
fn_has_authorize_once, fn_has_noinitcheck, get_fn_visibility, is_fn_contract_library_method,
8-
is_fn_external, is_fn_initializer, is_fn_internal, is_fn_private, is_fn_test, is_fn_view,
9-
modify_fn_body, module_has_initializer, module_has_storage,
10+
fn_has_authorize_once, fn_has_noinitcheck, is_fn_contract_library_method, is_fn_external,
11+
is_fn_initializer, is_fn_internal, is_fn_test, is_fn_view, modify_fn_body,
12+
module_has_initializer, module_has_storage,
1013
},
1114
};
1215
use dep::protocol_types::meta::utils::derive_serialization_quotes;
1316
use std::meta::{ctstring::AsCtString, type_of};
1417

1518
pub(crate) comptime fn transform_private(f: FunctionDefinition) {
16-
let fn_stub = stub_fn(f);
17-
stub_registry::register(f.module(), fn_stub);
19+
register_private_fn_stub(f);
1820

1921
let module_has_initializer = module_has_initializer(f.module());
2022
let module_has_storage = module_has_storage(f.module());
@@ -43,21 +45,29 @@ pub(crate) comptime fn transform_private(f: FunctionDefinition) {
4345
let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hash);
4446
};
4547

48+
let function_name = f.name();
49+
4650
// Modifications introduced by the different marker attributes.
4751
let internal_check = if is_fn_internal(f) {
48-
create_internal_check(f)
52+
let assertion_message = f"Function {function_name} can only be called internally";
53+
quote { assert(context.msg_sender().unwrap() == context.this_address(), $assertion_message); }
4954
} else {
5055
quote {}
5156
};
5257

5358
let view_check = if is_fn_view(f) {
54-
create_view_check(f)
59+
let assertion_message =
60+
f"Function {function_name} can only be called statically".as_ctstring().as_quoted_str();
61+
quote { assert(context.inputs.call_context.is_static_call, $assertion_message); }
5562
} else {
5663
quote {}
5764
};
5865

5966
let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) {
60-
(create_assert_correct_initializer_args(f), create_mark_as_initialized(f))
67+
(
68+
quote { aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_private(context); },
69+
quote { aztec::macros::functions::initialization_utils::mark_as_initialized_private(&mut context); },
70+
)
6171
} else {
6272
(quote {}, quote {})
6373
};
@@ -75,7 +85,7 @@ pub(crate) comptime fn transform_private(f: FunctionDefinition) {
7585

7686
// Initialization checks are not included in contracts that don't have initializers.
7787
let init_check = if module_has_initializer & !is_fn_initializer(f) & !fn_has_noinitcheck(f) {
78-
create_init_check(f)
88+
quote { aztec::macros::functions::initialization_utils::assert_is_initialized_private(&mut context); }
7989
} else {
8090
quote {}
8191
};
@@ -92,7 +102,7 @@ pub(crate) comptime fn transform_private(f: FunctionDefinition) {
92102

93103
// Inject the authwit check if the function is marked with #[authorize_once].
94104
let authorize_once_check = if fn_has_authorize_once(f) {
95-
create_authorize_once_check(f)
105+
create_authorize_once_check(f, true)
96106
} else {
97107
quote {}
98108
};
@@ -167,8 +177,7 @@ pub(crate) comptime fn transform_private(f: FunctionDefinition) {
167177
}
168178

169179
pub(crate) comptime fn transform_public(f: FunctionDefinition) {
170-
let fn_stub = stub_fn(f);
171-
stub_registry::register(f.module(), fn_stub);
180+
register_public_fn_stub(f);
172181

173182
let module_has_initializer = module_has_initializer(f.module());
174183
let module_has_storage = module_has_storage(f.module());
@@ -199,21 +208,29 @@ pub(crate) comptime fn transform_public(f: FunctionDefinition) {
199208
});
200209
};
201210

211+
let name = f.name();
202212
// Modifications introduced by the different marker attributes.
203213
let internal_check = if is_fn_internal(f) {
204-
create_internal_check(f)
214+
let assertion_message = f"Function {name} can only be called internally";
215+
quote { assert(context.msg_sender().unwrap() == context.this_address(), $assertion_message); }
205216
} else {
206217
quote {}
207218
};
208219

209220
let view_check = if is_fn_view(f) {
210-
create_view_check(f)
221+
let name = f.name();
222+
let assertion_message =
223+
f"Function {name} can only be called statically".as_ctstring().as_quoted_str();
224+
quote { assert(context.is_static_call(), $assertion_message); }
211225
} else {
212226
quote {}
213227
};
214228

215229
let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) {
216-
(create_assert_correct_initializer_args(f), create_mark_as_initialized(f))
230+
(
231+
quote { aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_public(context); },
232+
quote { aztec::macros::functions::initialization_utils::mark_as_initialized_public(&mut context); },
233+
)
217234
} else {
218235
(quote {}, quote {})
219236
};
@@ -231,14 +248,14 @@ pub(crate) comptime fn transform_public(f: FunctionDefinition) {
231248

232249
// Initialization checks are not included in contracts that don't have initializers.
233250
let init_check = if module_has_initializer & !fn_has_noinitcheck(f) & !is_fn_initializer(f) {
234-
create_init_check(f)
251+
quote { aztec::macros::functions::initialization_utils::assert_is_initialized_public(&mut context); }
235252
} else {
236253
quote {}
237254
};
238255

239256
// Inject the authwit check if the function is marked with #[authorize_once].
240257
let authorize_once_check = if fn_has_authorize_once(f) {
241-
create_authorize_once_check(f)
258+
create_authorize_once_check(f, false)
242259
} else {
243260
quote {}
244261
};
@@ -269,8 +286,7 @@ pub(crate) comptime fn transform_public(f: FunctionDefinition) {
269286
}
270287

271288
pub(crate) comptime fn transform_utility(f: FunctionDefinition) {
272-
let fn_stub = stub_fn(f);
273-
stub_registry::register(f.module(), fn_stub);
289+
register_utility_fn_stub(f);
274290

275291
// Create utility context
276292
let context_creation =
@@ -307,42 +323,6 @@ pub(crate) comptime fn transform_utility(f: FunctionDefinition) {
307323
f.set_return_public(true);
308324
}
309325

310-
comptime fn create_internal_check(f: FunctionDefinition) -> Quoted {
311-
let name = f.name();
312-
let assertion_message = f"Function {name} can only be called internally";
313-
quote { assert(context.msg_sender().unwrap() == context.this_address(), $assertion_message); }
314-
}
315-
316-
comptime fn create_view_check(f: FunctionDefinition) -> Quoted {
317-
let name = f.name();
318-
let assertion_message = f"Function {name} can only be called statically";
319-
if is_fn_private(f) {
320-
// Here `context` is of type context::PrivateContext
321-
quote { assert(context.inputs.call_context.is_static_call, $assertion_message); }
322-
} else {
323-
// Here `context` is of type context::PublicContext
324-
quote { assert(context.is_static_call(), $assertion_message); }
325-
}
326-
}
327-
328-
comptime fn create_assert_correct_initializer_args(f: FunctionDefinition) -> Quoted {
329-
let fn_visibility = get_fn_visibility(f);
330-
f"dep::aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_{fn_visibility}(context);"
331-
.quoted_contents()
332-
}
333-
334-
comptime fn create_mark_as_initialized(f: FunctionDefinition) -> Quoted {
335-
let fn_visibility = get_fn_visibility(f);
336-
f"dep::aztec::macros::functions::initialization_utils::mark_as_initialized_{fn_visibility}(&mut context);"
337-
.quoted_contents()
338-
}
339-
340-
comptime fn create_init_check(f: FunctionDefinition) -> Quoted {
341-
let fn_visibility = get_fn_visibility(f);
342-
f"dep::aztec::macros::functions::initialization_utils::assert_is_initialized_{fn_visibility}(&mut context);"
343-
.quoted_contents()
344-
}
345-
346326
/// Injects a call to `aztec::messages::discovery::discover_new_messages`, causing for new notes to be added to PXE and made
347327
/// available for the current execution.
348328
pub(crate) comptime fn create_message_discovery_call() -> Quoted {
@@ -369,7 +349,17 @@ pub(crate) comptime fn create_message_discovery_call() -> Quoted {
369349
/// where `from` and `authwit_nonce` are the names of the parameters that are expected to be present in the function definition.
370350
/// This check is injected by the `#[authorize_once("from_arg_name", "nonce_arg_name")]`, which allows the user to define
371351
/// which parameters to use.
372-
pub(crate) comptime fn create_authorize_once_check(f: FunctionDefinition) -> Quoted {
352+
///
353+
/// # Arguments
354+
/// * `f` - The function definition to inject the authwit verification check into. The function must have parameters
355+
/// matching the names specified in the `#[authorize_once]` attribute.
356+
/// * `is_private` - Whether the function is a private function (`true`) or a public function (`false`). This determines
357+
/// which authwit verification method to use: `assert_current_call_valid_authwit` for private functions
358+
/// or `assert_current_call_valid_authwit_public` for public functions.
359+
pub(crate) comptime fn create_authorize_once_check(
360+
f: FunctionDefinition,
361+
is_private: bool,
362+
) -> Quoted {
373363
let maybe_authorize_once_args = AUTHORIZE_ONCE_REGISTRY.get(f);
374364
let authorize_once_args = if maybe_authorize_once_args.is_some() {
375365
maybe_authorize_once_args.unwrap()
@@ -417,7 +407,7 @@ pub(crate) comptime fn create_authorize_once_check(f: FunctionDefinition) -> Quo
417407

418408
let nonce_check_quote = f"{nonce_arg_name_quoted} == 0".quoted_contents();
419409

420-
let fn_call = if is_fn_private(f) {
410+
let fn_call = if is_private {
421411
// At this point, the original args of the fn have already been altered by the macro
422412
// to include PrivateContextInputs, so we need to adjust the args_len accordingly.
423413
let args_len = f.parameters().len() - 1;

noir-projects/aztec-nr/aztec/src/macros/utils.nr

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,10 @@
1-
use crate::macros::functions::external_registry;
21
use dep::protocol_types::meta::derive_serialize;
32
use std::meta::unquote;
43

5-
pub(crate) comptime fn get_fn_visibility(f: FunctionDefinition) -> Quoted {
6-
let maybe_external_type = external_registry::get(f);
7-
if maybe_external_type.is_some() {
8-
let external_type = maybe_external_type.unwrap();
9-
if external_type.eq("private") {
10-
quote { private }
11-
} else if external_type.eq("public") {
12-
quote { public }
13-
} else {
14-
panic(f"Function is neither private nor public")
15-
}
16-
} else {
17-
panic(f"Function is neither private nor public")
18-
}
19-
}
20-
214
pub(crate) comptime fn is_fn_external(f: FunctionDefinition) -> bool {
225
f.has_named_attribute("external")
236
}
247

25-
pub(crate) comptime fn is_fn_private(f: FunctionDefinition) -> bool {
26-
let maybe_external_type = external_registry::get(f);
27-
if maybe_external_type.is_some() {
28-
maybe_external_type.unwrap_unchecked().eq("private")
29-
} else {
30-
false
31-
}
32-
}
33-
34-
pub(crate) comptime fn is_fn_public(f: FunctionDefinition) -> bool {
35-
let maybe_external_type = external_registry::get(f);
36-
if maybe_external_type.is_some() {
37-
maybe_external_type.unwrap_unchecked().eq("public")
38-
} else {
39-
false
40-
}
41-
}
42-
438
pub(crate) comptime fn is_fn_contract_library_method(f: FunctionDefinition) -> bool {
449
f.has_named_attribute("contract_library_method")
4510
}

0 commit comments

Comments
 (0)