Skip to content

Commit 5bdcdf3

Browse files
nchamoaztec-bot
authored andcommitted
feat(aztec-nr): add call_self stubs for utility functions (#22885)
1 parent 793dc23 commit 5bdcdf3

9 files changed

Lines changed: 86 additions & 22 deletions

File tree

noir-projects/aztec-nr/aztec/src/contract_self/contract_self_private.nr

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ use crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};
4848
/// - `CallSelfStatic`: Macro-generated type for calling contract's own view functions
4949
/// - `EnqueueSelfStatic`: Macro-generated type for enqueuing calls to the contract's own view functions
5050
/// - `CallInternal`: Macro-generated type for calling internal functions
51-
pub struct ContractSelfPrivate<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInternal> {
51+
/// - `CallSelfUtility`: Macro-generated type for calling the contract's own utility functions
52+
pub struct ContractSelfPrivate<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInternal, CallSelfUtility> {
5253
/// The address of this contract
5354
pub address: AztecAddress,
5455

@@ -110,17 +111,17 @@ pub struct ContractSelfPrivate<Storage, CallSelf, EnqueueSelf, CallSelfStatic, E
110111
/// ```
111112
pub internal: CallInternal,
112113

113-
/// Gateway for calling utility functions from this private context.
114+
/// A struct that allows for ergonomic calling of utility functions from this private context.
114115
///
115116
/// Example API:
116117
/// ```noir
117118
/// // Safety: result is unconstrained
118119
/// unsafe { self.utility.call(MyContract::at(address).my_utility_function(args)) }
119120
/// ```
120-
pub utility: PrivateUtility,
121+
pub utility: PrivateUtilityCalls<CallSelfUtility>,
121122
}
122123

123-
impl<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInternal> ContractSelfPrivate<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInternal> {
124+
impl<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInternal, CallSelfUtility> ContractSelfPrivate<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInternal, CallSelfUtility> {
124125
/// Creates a new `ContractSelfPrivate` instance for a private function.
125126
///
126127
/// This constructor is called automatically by the macro system and should not be called directly.
@@ -132,6 +133,7 @@ impl<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInte
132133
call_self_static: CallSelfStatic,
133134
enqueue_self_static: EnqueueSelfStatic,
134135
internal: CallInternal,
136+
utility: PrivateUtilityCalls<CallSelfUtility>,
135137
) -> Self {
136138
Self {
137139
context,
@@ -142,7 +144,7 @@ impl<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInte
142144
call_self_static,
143145
enqueue_self_static,
144146
internal,
145-
utility: PrivateUtility {},
147+
utility,
146148
}
147149
}
148150

@@ -407,16 +409,31 @@ impl<Storage, CallSelf, EnqueueSelf, CallSelfStatic, EnqueueSelfStatic, CallInte
407409
}
408410
}
409411

410-
/// Gateway for calling utility functions from a private context.
412+
/// A struct that allows for ergonomic calling of utility functions from a private context.
411413
///
412414
/// Accessible via `self.utility` in private functions. Results are not part of any circuit
413415
/// proof; use them to inform logic, not as inputs to constrained assertions.
414-
// Implemented as a separate empty struct because Noir does not allow passing `&mut PrivateContext`
415-
// (held by `ContractSelfPrivate`) into unconstrained code. This struct holds no mutable references,
416-
// so it can be passed freely into `unconstrained` functions.
417-
pub struct PrivateUtility {}
416+
///
417+
/// ## Type Parameters
418+
///
419+
/// - `CallSelf`: Macro-generated type for calling the contract's own utility functions (same type
420+
/// as `CallSelf` in \[`ContractSelfUtility`\])
421+
// Implemented as a separate struct (rather than inlined in ContractSelfPrivate) because Noir does
422+
// not allow passing `&mut PrivateContext` (held by `ContractSelfPrivate`) into unconstrained code.
423+
// This struct holds no mutable references, so it can be passed freely into `unconstrained`
424+
// functions.
425+
pub struct PrivateUtilityCalls<CallSelf> {
426+
/// Provides type-safe methods for calling this contract's own utility functions.
427+
///
428+
/// Example API:
429+
/// ```noir
430+
/// // Safety: result is unconstrained
431+
/// unsafe { self.utility.call_self.some_utility_function(args) }
432+
/// ```
433+
pub call_self: CallSelf,
434+
}
418435

419-
impl PrivateUtility {
436+
impl<CallSelf> PrivateUtilityCalls<CallSelf> {
420437
/// Makes a utility contract call from a private function.
421438
///
422439
/// Note: only same-contract utility calls are currently supported. See TODO(F-29).

noir-projects/aztec-nr/aztec/src/contract_self/contract_self_utility.nr

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use crate::protocol::{address::AztecAddress, traits::Deserialize};
1313
///
1414
/// - `Storage`: The contract's storage struct (defined with [`storage`](crate::macros::storage::storage), or `()` if
1515
/// the contract has no storage
16-
pub struct ContractSelfUtility<Storage> {
16+
/// - `CallSelf`: Macro-generated type for calling the contract's own utility functions (same type
17+
/// as `CallSelf` in \[`PrivateUtilityCalls`\])
18+
pub struct ContractSelfUtility<Storage, CallSelf> {
1719
/// The address of this contract
1820
pub address: AztecAddress,
1921

@@ -34,14 +36,22 @@ pub struct ContractSelfUtility<Storage> {
3436

3537
/// The utility execution context.
3638
pub context: UtilityContext,
39+
40+
/// Provides type-safe methods for calling this contract's own utility functions.
41+
///
42+
/// Example API:
43+
/// ```noir
44+
/// self.call_self.some_utility_function(args)
45+
/// ```
46+
pub call_self: CallSelf,
3747
}
3848

39-
impl<Storage> ContractSelfUtility<Storage> {
49+
impl<Storage, CallSelf> ContractSelfUtility<Storage, CallSelf> {
4050
/// Creates a new `ContractSelfUtility` instance for a utility function.
4151
///
4252
/// This constructor is called automatically by the macro system and should not be called directly.
43-
pub fn new(context: UtilityContext, storage: Storage) -> Self {
44-
Self { context, storage, address: context.this_address() }
53+
pub fn new(context: UtilityContext, storage: Storage, call_self: CallSelf) -> Self {
54+
Self { context, storage, address: context.this_address(), call_self }
4555
}
4656

4757
/// Makes a utility contract call from another utility function.

noir-projects/aztec-nr/aztec/src/contract_self/mod.nr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod contract_self_private;
22
pub mod contract_self_public;
33
pub mod contract_self_utility;
44

5+
pub use contract_self_private::PrivateUtilityCalls;
56
pub use contract_self_private::ContractSelfPrivate;
67
pub use contract_self_public::ContractSelfPublic;
78
pub use contract_self_utility::ContractSelfUtility;

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::macros::{
22
calls_generation::external_functions_stubs::{
33
create_private_self_call_stub, create_private_static_stub, create_private_stub,
44
create_public_self_call_static_stub, create_public_self_call_stub, create_public_self_enqueue_static_stub,
5-
create_public_self_enqueue_stub, create_public_static_stub, create_public_stub, create_utility_stub,
6-
create_utility_stub_from_parts,
5+
create_public_self_enqueue_stub, create_public_static_stub, create_public_stub, create_utility_self_call_stub,
6+
create_utility_stub, create_utility_stub_from_parts,
77
},
88
internals_functions_generation::external_functions_registry,
99
offchain_receive::{
@@ -77,6 +77,7 @@ comptime fn create_offchain_receive_stub() -> Quoted {
7777
pub(crate) comptime fn generate_external_function_self_calls_structs(m: Module) -> Quoted {
7878
let private_functions = external_functions_registry::get_private_functions(m);
7979
let public_functions = external_functions_registry::get_public_functions(m);
80+
let utility_functions = external_functions_registry::get_utility_functions(m);
8081

8182
let call_self_private_methods = private_functions
8283
.map(|function| {
@@ -138,6 +139,9 @@ pub(crate) comptime fn generate_external_function_self_calls_structs(m: Module)
138139
})
139140
.join(quote {});
140141

142+
let call_self_utility_methods =
143+
utility_functions.map(|function| create_utility_self_call_stub(function)).join(quote {});
144+
141145
quote {
142146
pub struct CallSelf<Context> {
143147
pub address: aztec::protocol::address::AztecAddress,
@@ -182,5 +186,13 @@ pub(crate) comptime fn generate_external_function_self_calls_structs(m: Module)
182186
impl EnqueueSelfStatic<&mut aztec::context::PrivateContext> {
183187
$enqueue_self_static_methods
184188
}
189+
190+
pub struct CallSelfUtility {
191+
pub address: aztec::protocol::address::AztecAddress,
192+
}
193+
194+
impl CallSelfUtility {
195+
$call_self_utility_methods
196+
}
185197
}
186198
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,24 @@ pub comptime fn create_public_self_enqueue_static_stub(f: FunctionDefinition) ->
259259
}
260260
}
261261

262+
/// Creates a stub for calling a utility function on the same contract (for CallSelfUtility).
263+
pub comptime fn create_utility_self_call_stub(f: FunctionDefinition) -> Quoted {
264+
let (fn_name, fn_parameters_list, serialized_args_array_construction, serialized_args_array_name, _, _, _, fn_selector) =
265+
create_stub_base(f);
266+
let fn_return_type = f.return_type();
267+
268+
quote {
269+
pub unconstrained fn $fn_name(self, $fn_parameters_list) -> $fn_return_type {
270+
$serialized_args_array_construction
271+
let selector = $FROM_FIELD($fn_selector);
272+
let returns = aztec::oracle::call_utility_function::call_utility_function(
273+
self.address, selector, $serialized_args_array_name,
274+
);
275+
aztec::protocol::traits::Deserialize::deserialize(returns)
276+
}
277+
}
278+
}
279+
262280
/// Creates a stub for enqueuing a public function from private context (for EnqueueSelf<&mut PrivateContext>)
263281
pub comptime fn create_public_self_enqueue_stub(f: FunctionDefinition) -> Quoted {
264282
let (fn_name, fn_parameters_list, serialized_args_array_construction, serialized_args_array_name, _serialized_args_array_len, _fn_name_str, _fn_name_len, fn_selector) =

noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/private.nr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ pub(crate) comptime fn generate_private_external(f: FunctionDefinition) -> Quote
5656
let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic { address: self_address, context: &mut context };
5757
let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic { address: self_address, context: &mut context };
5858
let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal { context: &mut context };
59-
aztec::contract_self::ContractSelfPrivate::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal)
59+
let call_self_utility = CallSelfUtility { address: self_address };
60+
let utility: aztec::contract_self::PrivateUtilityCalls<CallSelfUtility> = aztec::contract_self::PrivateUtilityCalls { call_self: call_self_utility };
61+
aztec::contract_self::ContractSelfPrivate::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility)
6062
};
6163
};
6264

noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/utility.nr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ pub(crate) comptime fn generate_utility_external(f: FunctionDefinition) -> Quote
2424
let mut self = {
2525
let context = aztec::context::UtilityContext::new();
2626
$storage_init
27-
aztec::contract_self::ContractSelfUtility::new(context, storage)
27+
let self_address = context.this_address();
28+
let call_self = CallSelfUtility { address: self_address };
29+
aztec::contract_self::ContractSelfUtility::new(context, storage, call_self)
2830
};
2931
};
3032

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ pub(crate) comptime fn generate_private_internal(f: FunctionDefinition) -> Quote
4242
let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic { address: self_address, context };
4343
let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic { address: self_address, context };
4444
let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal { context };
45-
aztec::contract_self::ContractSelfPrivate::new(context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal)
45+
let call_self_utility = CallSelfUtility { address: self_address };
46+
let utility: aztec::contract_self::PrivateUtilityCalls<CallSelfUtility> = aztec::contract_self::PrivateUtilityCalls { call_self: call_self_utility };
47+
aztec::contract_self::ContractSelfPrivate::new(context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility)
4648
};
4749

4850
$body

noir-projects/noir-contracts/contracts/test/nested_utility_contract/src/main.nr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub contract NestedUtility {
1212
if n == 0 {
1313
1
1414
} else {
15-
x * self.call(NestedUtility::at(self.address).pow_utility(x, n - 1))
15+
x * self.call_self.pow_utility(x, n - 1)
1616
}
1717
}
1818

@@ -21,7 +21,7 @@ pub contract NestedUtility {
2121
// Safety: this is a test contract; the unconstrained result is returned directly
2222
// and never used as input to a constrained assertion
2323
unsafe {
24-
self.utility.call(NestedUtility::at(self.address).pow_utility(x, n))
24+
self.utility.call_self.pow_utility(x, n)
2525
}
2626
}
2727
}

0 commit comments

Comments
 (0)