Skip to content

Commit 69eb040

Browse files
committed
feat: utility function
1 parent f16b70e commit 69eb040

File tree

10 files changed

+60
-52
lines changed

10 files changed

+60
-52
lines changed

cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,12 @@
9797
"doesnt",
9898
"dont",
9999
"ecdh",
100+
"ecdsasecp",
100101
"elif",
101102
"endgroup",
102103
"enrs",
103104
"entrypoints",
104105
"erc",
105-
"ecdsasecp",
106106
"falsey",
107107
"fargate",
108108
"Fieldable",
@@ -155,6 +155,7 @@
155155
"libp",
156156
"linkability",
157157
"lmdb",
158+
"macroified",
158159
"maddiaa",
159160
"mcache",
160161
"memdown",

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
dispatch::generate_public_dispatch,
55
functions::{
66
stub_registry,
7-
utils::{create_message_discovery_call, find_and_transform_top_level_unconstrained_fns},
7+
utils::{check_each_fn_macroified, create_message_discovery_call},
88
},
99
notes::{generate_note_export, NOTES},
1010
storage::STORAGE_LAYOUT_NAME,
@@ -18,7 +18,9 @@ use crate::{
1818
pub comptime fn aztec(m: Module) -> Quoted {
1919
let interface = generate_contract_interface(m);
2020

21-
find_and_transform_top_level_unconstrained_fns(m);
21+
// Functions that don't have #[private], #[public], #[utility], #[contract_library_method], or #[test] are not
22+
//allowed in contracts.
23+
check_each_fn_macroified(m);
2224

2325
let contract_library_method_compute_note_hash_and_nullifier =
2426
generate_contract_library_method_compute_note_hash_and_nullifier();

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub(crate) mod initialization_utils;
44
pub(crate) mod stub_registry;
55
pub(crate) mod utils;
66

7-
use utils::{transform_private, transform_public};
7+
use utils::{transform_private, transform_public, transform_utility};
88

99
// Functions can have multiple attributes applied to them, e.g. a single function can have #[public], #[view] and
1010
// #[internal]. However. the order in which this will be evaluated is unknown, which makes combining them tricky.
@@ -55,3 +55,10 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted {
5555
transform_public(f)
5656
}
5757
}
58+
59+
/// Utility functions are standalone unconstrained functions that cannot be called from within a contract. They are
60+
/// typically used either to obtain some information from the contract (e.g. token balance of a user) or to modify
61+
/// internal contract-related state of PXE (e,g, processing logs in Aztec.nr during sync).
62+
pub comptime fn utility(f: FunctionDefinition) {
63+
transform_utility(f);
64+
}

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

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use crate::macros::{
22
functions::{abi_export::create_fn_abi_export, call_interface_stubs::stub_fn, stub_registry},
33
notes::NOTES,
44
utils::{
5-
add_to_hasher, fn_has_noinitcheck, get_fn_visibility, is_fn_initializer, is_fn_internal,
6-
is_fn_private, is_fn_public, is_fn_view, modify_fn_body, module_has_initializer,
7-
module_has_storage,
5+
add_to_hasher, fn_has_noinitcheck, get_fn_visibility, is_fn_contract_library_method,
6+
is_fn_initializer, is_fn_internal, is_fn_private, is_fn_public, is_fn_test, is_fn_utility,
7+
is_fn_view, modify_fn_body, module_has_initializer, module_has_storage,
88
},
99
};
1010
use protocol_types::meta::generate_serialize_to_fields;
@@ -272,45 +272,7 @@ pub(crate) comptime fn transform_public(f: FunctionDefinition) -> Quoted {
272272
fn_abi
273273
}
274274

275-
pub(crate) comptime fn find_and_transform_top_level_unconstrained_fns(m: Module) {
276-
// Top-level unconstrained fns are contract entrypoints, but they're not explicitly designated in any way. They're
277-
// the fallback case for a function that matches no other rules.
278-
// TODO(#12743): improve this
279-
280-
// We first find non-standard contract entrypoints, i.e. functions in the `contract` mod that are not private or
281-
// public, but which *are* contract entrypoints (i.e. they're not opting out via the #[test] or
282-
// #[contract_library_method] attributes). Ideally entrypoints would be explicitly designated instead.
283-
let non_private_public_entrypoint_functions = m.functions().filter(|f: FunctionDefinition| {
284-
!is_fn_private(f)
285-
& !is_fn_public(f)
286-
& !f.has_named_attribute("contract_library_method")
287-
& !f.has_named_attribute("test")
288-
});
289-
290-
// TODO: uncomment the code below and emit a warning once support for them is added to Noir (tracked in
291-
// https://github.com/noir-lang/noir/issues/7714). We can't simply print a message since that'd otherwise break the
292-
// output of utils such as `nargo test --list-tests`.
293-
// // We don't expect to see any custom constrained entrypoints (i.e. private functions created outside of aztec-nr's
294-
// // #[private] macro, possibly resulting in a non-standard interface).
295-
// for f in non_private_public_entrypoint_functions.filter(|f: FunctionDefinition| {
296-
// !f.is_unconstrained()
297-
// }) {
298-
// let name = f.name();
299-
// warn(
300-
// f"found private contract function '{name}' which does not have the #[private] attribute - make sure you know what you're doing!",
301-
// );
302-
// }
303-
304-
// An unconstrained contract entrypoints is what we call a top-level unconstrained function, to which we apply the
305-
// appropriate transformation. Ideally these would be explicitly designated as such instead.
306-
for f in non_private_public_entrypoint_functions.filter(|f: FunctionDefinition| {
307-
f.is_unconstrained()
308-
}) {
309-
transform_top_level_unconstrained(f);
310-
}
311-
}
312-
313-
pub(crate) comptime fn transform_top_level_unconstrained(f: FunctionDefinition) {
275+
pub(crate) comptime fn transform_utility(f: FunctionDefinition) {
314276
let context_creation = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); };
315277
let module_has_storage = module_has_storage(f.module());
316278

@@ -395,3 +357,20 @@ pub(crate) comptime fn create_message_discovery_call() -> Quoted {
395357
};
396358
}
397359
}
360+
361+
/// Checks if each function in the module is marked with either #[private], #[public], #[utility],
362+
/// #[contract_library_method], or #[test]. Non-macroified functions are not allowed in contracts.
363+
pub(crate) comptime fn check_each_fn_macroified(m: Module) {
364+
for f in m.functions() {
365+
let name = f.name();
366+
if !is_fn_private(f)
367+
& !is_fn_public(f)
368+
& !is_fn_utility(f)
369+
& !is_fn_contract_library_method(f)
370+
& !is_fn_test(f) {
371+
panic(
372+
f"Function {name} must be marked as either #[private], #[public], #[utility], #[contract_library_method], or #[test]",
373+
);
374+
}
375+
}
376+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ pub(crate) comptime fn is_fn_public(f: FunctionDefinition) -> bool {
1818
f.has_named_attribute("public")
1919
}
2020

21+
pub(crate) comptime fn is_fn_utility(f: FunctionDefinition) -> bool {
22+
f.has_named_attribute("utility")
23+
}
24+
25+
pub(crate) comptime fn is_fn_contract_library_method(f: FunctionDefinition) -> bool {
26+
f.has_named_attribute("contract_library_method")
27+
}
28+
29+
pub(crate) comptime fn is_fn_test(f: FunctionDefinition) -> bool {
30+
f.has_named_attribute("test")
31+
}
32+
2133
pub(crate) comptime fn is_fn_view(f: FunctionDefinition) -> bool {
2234
f.has_named_attribute("view")
2335
}

noir-projects/noir-contracts/contracts/amm_contract/src/main.nr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub contract AMM {
3939
lib::{get_amount_in, get_amount_out, get_amounts_on_remove, get_amounts_to_add},
4040
};
4141
use dep::aztec::{
42-
macros::{functions::{initializer, internal, private, public}, storage::storage},
42+
macros::{functions::{initializer, internal, private, public, utility}, storage::storage},
4343
prelude::{AztecAddress, PublicImmutable},
4444
};
4545

@@ -461,6 +461,7 @@ pub contract AMM {
461461
);
462462
}
463463

464+
#[utility]
464465
unconstrained fn get_amount_out_for_exact_in(
465466
balance_in: u128,
466467
balance_out: u128,
@@ -470,6 +471,7 @@ pub contract AMM {
470471
get_amount_out(amount_in, balance_in, balance_out)
471472
}
472473

474+
#[utility]
473475
unconstrained fn get_amount_in_for_exact_out(
474476
balance_in: u128,
475477
balance_out: u128,

noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub contract AppSubscription {
1111
use authwit::auth::assert_current_call_valid_authwit;
1212
use aztec::{
1313
encrypted_logs::log_assembly_strategies::default_aes128::note::encode_and_encrypt_note,
14-
macros::{functions::{initializer, private, public}, storage::storage},
14+
macros::{functions::{initializer, private, public, utility}, storage::storage},
1515
prelude::{AztecAddress, Map, PrivateMutable, PublicImmutable},
1616
protocol_types::{constants::MAX_FIELD_VALUE, traits::ToField},
1717
utils::comparison::Comparator,
@@ -115,6 +115,7 @@ pub contract AppSubscription {
115115
);
116116
}
117117

118+
#[utility]
118119
unconstrained fn is_initialized(subscriber: AztecAddress) -> pub bool {
119120
storage.subscriptions.at(subscriber).is_initialized()
120121
}

noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub contract AuthRegistry {
66
assert_current_call_valid_authwit, compute_authwit_message_hash, IS_VALID_SELECTOR,
77
};
88
use dep::aztec::{
9-
macros::{functions::{internal, private, public, view}, storage::storage},
9+
macros::{functions::{internal, private, public, utility, view}, storage::storage},
1010
protocol_types::address::AztecAddress,
1111
state_vars::{Map, PublicMutable},
1212
};
@@ -128,6 +128,7 @@ pub contract AuthRegistry {
128128
storage.approved_actions.at(on_behalf_of).at(message_hash).read()
129129
}
130130

131+
#[utility]
131132
unconstrained fn unconstrained_is_consumable(
132133
on_behalf_of: AztecAddress,
133134
message_hash: Field,

noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub contract CardGame {
1212

1313
use crate::cards::{Card, compute_deck_strength, Deck, get_pack_cards};
1414
use crate::game::{Game, PLAYABLE_CARDS, PlayerEntry};
15-
use dep::aztec::macros::{functions::{internal, private, public}, storage::storage};
15+
use dep::aztec::macros::{functions::{internal, private, public, utility}, storage::storage};
1616

1717
use dep::aztec::protocol_types::traits::{FromField, ToField};
1818

@@ -134,6 +134,7 @@ pub contract CardGame {
134134
game_storage.write(game_data);
135135
}
136136

137+
#[utility]
137138
unconstrained fn view_collection_cards(
138139
owner: AztecAddress,
139140
offset: u32,
@@ -142,6 +143,7 @@ pub contract CardGame {
142143
collection.view_cards(offset)
143144
}
144145

146+
#[utility]
145147
unconstrained fn view_game_cards(
146148
game: u32,
147149
player: AztecAddress,
@@ -152,6 +154,7 @@ pub contract CardGame {
152154
game_deck.view_cards(offset)
153155
}
154156

157+
#[utility]
155158
unconstrained fn view_game(game: u32) -> pub Game {
156159
storage.games.at(game as Field).read()
157160
}

noir-projects/noir-contracts/contracts/token_contract/src/main.nr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub contract Token {
2727
event::event_interface::EventInterface,
2828
macros::{
2929
events::event,
30-
functions::{initializer, internal, private, public, view},
30+
functions::{initializer, internal, private, public, utility, view},
3131
storage::storage,
3232
},
3333
prelude::{AztecAddress, Map, PublicContext, PublicImmutable, PublicMutable},
@@ -618,8 +618,8 @@ pub contract Token {
618618
}
619619
// docs:end:reduce_total_supply
620620

621-
/// Unconstrained ///
622621
// docs:start:balance_of_private
622+
#[utility]
623623
pub(crate) unconstrained fn balance_of_private(owner: AztecAddress) -> pub u128 {
624624
storage.balances.at(owner).balance_of()
625625
}

0 commit comments

Comments
 (0)