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
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,52 @@ use crate::macros::{
},
};

/// Generates the per-contract helper that builds public `self`.
///
/// Each public external function calls this helper instead of inlining the construction, so the same preamble does not
/// appear duplicated in every public function body. We let Noir's inliner decide whether to inline the helper at each
/// call site rather than forcing it via macro expansion.
///
/// The helper is generic over the calldata length `N` because `PublicContext::new` takes a closure that reads `N`
/// fields from calldata. Noir monomorphizes one copy per distinct `N`, so public functions with the same number of
/// serialized args reuse the same compiled code.
pub(crate) comptime fn generate_public_self_creator(m: Module) -> Quoted {
let (storage_type, storage_init) = if module_has_storage(m) {
(quote { Storage<aztec::context::PublicContext> }, quote { let storage = Storage::init(context); })
} else {
// Contract does not have Storage defined, so we set storage to the unit type `()`. ContractSelfPublic requires
// a storage struct in its constructor. Using an Option type would lead to worse developer experience and
// higher constraint counts so we use the unit type `()` instead.
(quote { () }, quote { let storage = (); })
};

quote {
#[contract_library_method]
unconstrained fn __aztec_nr_internals__create_public_self<let N: u32>() -> aztec::contract_self::ContractSelfPublic<
$storage_type,
CallSelf<aztec::context::PublicContext>,
CallSelfStatic<aztec::context::PublicContext>,
CallInternal<aztec::context::PublicContext>,
> {
// Unlike in the private case, in public the `context` does not need to receive the hash of the original
// params.
let context = aztec::context::PublicContext::new(|| {
// We start from 1 because we skip the selector for the dispatch function.
let serialized_args : [Field; N] = aztec::oracle::avm::calldata_copy(1, N);
aztec::hash::hash_args(serialized_args)
});
$storage_init
let self_address = context.this_address();
let call_self: CallSelf<aztec::context::PublicContext> = CallSelf { address: self_address, context };
let call_self_static: CallSelfStatic<aztec::context::PublicContext> = CallSelfStatic { address: self_address, context };
let internal: CallInternal<aztec::context::PublicContext> = CallInternal { context };
aztec::contract_self::ContractSelfPublic::new(context, storage, call_self, call_self_static, internal)
}
}
}

pub(crate) comptime fn generate_public_external(f: FunctionDefinition) -> Quoted {
let module_has_initializer = module_has_initializer(f.module());
let module_has_storage = module_has_storage(f.module());

// Public functions undergo a lot of transformations from their Aztec.nr form.
let original_params = f.parameters();
Expand All @@ -28,35 +71,9 @@ pub(crate) comptime fn generate_public_external(f: FunctionDefinition) -> Quoted
.join(quote {+})
};

let storage_init = if module_has_storage {
quote {
let storage = Storage::init(context);
}
} else {
// Contract does not have Storage defined, so we set storage to the unit type `()`. ContractSelfPublic requires
// a storage struct in its constructor. Using an Option type would lead to worse developer experience and
// higher constraint counts so we use the unit type `()` instead.
quote {
let storage = ();
}
};

// Unlike in the private case, in public the `context` does not need to receive the hash of the original params.
let contract_self_creation = quote {
#[allow(unused_variables)]
let mut self = {
let context = aztec::context::PublicContext::new(|| {
// We start from 1 because we skip the selector for the dispatch function.
let serialized_args : [Field; $args_len_quote] = aztec::oracle::avm::calldata_copy(1, $args_len_quote);
aztec::hash::hash_args(serialized_args)
});
$storage_init
let self_address = context.this_address();
let call_self: CallSelf<aztec::context::PublicContext> = CallSelf { address: self_address, context };
let call_self_static: CallSelfStatic<aztec::context::PublicContext> = CallSelfStatic { address: self_address, context };
let internal: CallInternal<aztec::context::PublicContext> = CallInternal { context };
aztec::contract_self::ContractSelfPublic::new(context, storage, call_self, call_self_static, internal)
};
let mut self = __aztec_nr_internals__create_public_self::<$args_len_quote>();
};

let original_function_name = f.name();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ pub(crate) mod internal;

use abi_export::create_fn_abi_export;
use external::{
private::generate_private_external, public::generate_public_external, utility::generate_utility_external,
private::generate_private_external,
public::{generate_public_external, generate_public_self_creator},
utility::generate_utility_external,
};
use internal::{generate_private_internal, generate_public_internal};

Expand Down Expand Up @@ -47,6 +49,15 @@ pub(crate) comptime fn process_functions(m: Module) -> Quoted {
let transformed_utility_functions =
utility_functions.map(|function| generate_utility_external(function)).join(quote {});

// Emit a contract-level helper that constructs `self` for public functions. Each transformed public function calls
// this helper rather than inlining the preamble. The helper is only useful for public external functions, so we
// skip emitting it when the contract has none.
let public_self_creator = if public_functions.len() > 0 {
generate_public_self_creator(m)
} else {
quote {}
};

// Now that we have generated quotes of the new functions based on the original function definitions, we replace
// the original functions' bodies with `static_assert(false, ...)` to prevent them from being called directly from
// within the contract. We also need to set the return type to `()` to avoid compilation errors.
Expand Down Expand Up @@ -84,6 +95,7 @@ pub(crate) comptime fn process_functions(m: Module) -> Quoted {

// We return the new functions' quotes to be injected into the contract.
quote {
$public_self_creator
$transformed_private_functions
$transformed_public_functions
$transformed_utility_functions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,7 @@ impl<let N: u32, let T: u32> CallPrivateOptions<N, T> {
self,
additional_scopes: [AztecAddress; N_2],
) -> CallPrivateOptions<N_2, T> {
CallPrivateOptions {
additional_scopes,
authorized_utility_call_targets: self.authorized_utility_call_targets,
}
CallPrivateOptions { additional_scopes, authorized_utility_call_targets: self.authorized_utility_call_targets }
}

/// Authorizes cross-contract utility calls to the given target contracts during this call.
Expand All @@ -173,10 +170,7 @@ impl<let N: u32, let T: u32> CallPrivateOptions<N, T> {
self,
targets: [AztecAddress; T_2],
) -> CallPrivateOptions<N, T_2> {
CallPrivateOptions {
additional_scopes: self.additional_scopes,
authorized_utility_call_targets: targets,
}
CallPrivateOptions { additional_scopes: self.additional_scopes, authorized_utility_call_targets: targets }
}
}

Expand Down Expand Up @@ -214,10 +208,7 @@ impl<let S: u32, let T: u32> ViewPrivateOptions<S, T> {
self,
additional_scopes: [AztecAddress; S2],
) -> ViewPrivateOptions<S2, T> {
ViewPrivateOptions {
additional_scopes,
authorized_utility_call_targets: self.authorized_utility_call_targets,
}
ViewPrivateOptions { additional_scopes, authorized_utility_call_targets: self.authorized_utility_call_targets }
}

/// Authorizes cross-contract utility calls to the given target contracts during this call.
Expand All @@ -228,10 +219,7 @@ impl<let S: u32, let T: u32> ViewPrivateOptions<S, T> {
self,
targets: [AztecAddress; T_2],
) -> ViewPrivateOptions<S, T_2> {
ViewPrivateOptions {
additional_scopes: self.additional_scopes,
authorized_utility_call_targets: targets,
}
ViewPrivateOptions { additional_scopes: self.additional_scopes, authorized_utility_call_targets: targets }
}
}

Expand Down Expand Up @@ -773,10 +761,7 @@ impl TestEnvironment {
/// let contract_addr = env.deploy("SampleContract").without_initializer();
/// let return_value = env.execute_utility(SampleContract::at(contract_addr).sample_utility_function());
/// ```
pub unconstrained fn execute_utility<let M: u32, let N: u32, T>(
self: Self,
call: UtilityCall<M, N, T>,
) -> T
pub unconstrained fn execute_utility<let M: u32, let N: u32, T>(self: Self, call: UtilityCall<M, N, T>) -> T
where
T: Deserialize,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ error: Argument from in function foo must be of type AztecAddress, but is of typ
2: aztec
at <repo>/noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21
3: process_functions
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:9
4: [T]::map
at std/vector.nr:67:33
5: process_functions
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:41
6: generate_public_external
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:114:9
7: create_authorize_once_check
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:72:9

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ error: Function foo does not have a from parameter. Please specify which one to
2: aztec
at <repo>/noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21
3: process_functions
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:9
4: [T]::map
at std/vector.nr:67:33
5: process_functions
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:41
6: generate_public_external
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:114:9
7: create_authorize_once_check
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:67:9

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ error: Function foo does not have a authwit_nonce. Please specify which one to u
2: aztec
at <repo>/noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21
3: process_functions
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:9
4: [T]::map
at std/vector.nr:67:33
5: process_functions
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:41
6: generate_public_external
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:114:9
7: create_authorize_once_check
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:81:9

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ error: Argument authwit_nonce in function foo must be of type Field, but is of t
2: aztec
at <repo>/noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21
3: process_functions
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:9
4: [T]::map
at std/vector.nr:67:33
5: process_functions
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:41
6: generate_public_external
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:114:9
7: create_authorize_once_check
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:86:9

Expand Down
Loading
Loading