Skip to content

Commit a79965c

Browse files
vezenovmAztecBot
authored andcommitted
chore(aztec-nr): Public self constructor function to prevent static byte code size blow up (#23062)
Resolves [F-637](https://linear.app/aztec-labs/issue/F-637/aztec-nr-macros-contain-self-construction-to-a-function-to-prevent) Stacks on #23061 - New `generate_public_self_creator` emits a per-contract `__aztec_nr_internals__create_public_self<let N: u32>()` helper - `generate_public_external` now emits a single call to it instead of inlining the preamble. This can be seen in the snapshots. - Helper is emitted from `process_functions` and gated on `public_functions.len() > 0` ~~Improvements tested locally:~~ I need to test further. Either way this is cleaner macro code.
1 parent 9693d6e commit a79965c

12 files changed

Lines changed: 302 additions & 1817 deletions

File tree

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

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,52 @@ use crate::macros::{
66
},
77
};
88

9+
/// Generates the per-contract helper that builds public `self`.
10+
///
11+
/// Each public external function calls this helper instead of inlining the construction, so the same preamble does not
12+
/// appear duplicated in every public function body. We let Noir's inliner decide whether to inline the helper at each
13+
/// call site rather than forcing it via macro expansion.
14+
///
15+
/// The helper is generic over the calldata length `N` because `PublicContext::new` takes a closure that reads `N`
16+
/// fields from calldata. Noir monomorphizes one copy per distinct `N`, so public functions with the same number of
17+
/// serialized args reuse the same compiled code.
18+
pub(crate) comptime fn generate_public_self_creator(m: Module) -> Quoted {
19+
let (storage_type, storage_init) = if module_has_storage(m) {
20+
(quote { Storage<aztec::context::PublicContext> }, quote { let storage = Storage::init(context); })
21+
} else {
22+
// Contract does not have Storage defined, so we set storage to the unit type `()`. ContractSelfPublic requires
23+
// a storage struct in its constructor. Using an Option type would lead to worse developer experience and
24+
// higher constraint counts so we use the unit type `()` instead.
25+
(quote { () }, quote { let storage = (); })
26+
};
27+
28+
quote {
29+
#[contract_library_method]
30+
unconstrained fn __aztec_nr_internals__create_public_self<let N: u32>() -> aztec::contract_self::ContractSelfPublic<
31+
$storage_type,
32+
CallSelf<aztec::context::PublicContext>,
33+
CallSelfStatic<aztec::context::PublicContext>,
34+
CallInternal<aztec::context::PublicContext>,
35+
> {
36+
// Unlike in the private case, in public the `context` does not need to receive the hash of the original
37+
// params.
38+
let context = aztec::context::PublicContext::new(|| {
39+
// We start from 1 because we skip the selector for the dispatch function.
40+
let serialized_args : [Field; N] = aztec::oracle::avm::calldata_copy(1, N);
41+
aztec::hash::hash_args(serialized_args)
42+
});
43+
$storage_init
44+
let self_address = context.this_address();
45+
let call_self: CallSelf<aztec::context::PublicContext> = CallSelf { address: self_address, context };
46+
let call_self_static: CallSelfStatic<aztec::context::PublicContext> = CallSelfStatic { address: self_address, context };
47+
let internal: CallInternal<aztec::context::PublicContext> = CallInternal { context };
48+
aztec::contract_self::ContractSelfPublic::new(context, storage, call_self, call_self_static, internal)
49+
}
50+
}
51+
}
52+
953
pub(crate) comptime fn generate_public_external(f: FunctionDefinition) -> Quoted {
1054
let module_has_initializer = module_has_initializer(f.module());
11-
let module_has_storage = module_has_storage(f.module());
1255

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

31-
let storage_init = if module_has_storage {
32-
quote {
33-
let storage = Storage::init(context);
34-
}
35-
} else {
36-
// Contract does not have Storage defined, so we set storage to the unit type `()`. ContractSelfPublic requires
37-
// a storage struct in its constructor. Using an Option type would lead to worse developer experience and
38-
// higher constraint counts so we use the unit type `()` instead.
39-
quote {
40-
let storage = ();
41-
}
42-
};
43-
44-
// Unlike in the private case, in public the `context` does not need to receive the hash of the original params.
4574
let contract_self_creation = quote {
4675
#[allow(unused_variables)]
47-
let mut self = {
48-
let context = aztec::context::PublicContext::new(|| {
49-
// We start from 1 because we skip the selector for the dispatch function.
50-
let serialized_args : [Field; $args_len_quote] = aztec::oracle::avm::calldata_copy(1, $args_len_quote);
51-
aztec::hash::hash_args(serialized_args)
52-
});
53-
$storage_init
54-
let self_address = context.this_address();
55-
let call_self: CallSelf<aztec::context::PublicContext> = CallSelf { address: self_address, context };
56-
let call_self_static: CallSelfStatic<aztec::context::PublicContext> = CallSelfStatic { address: self_address, context };
57-
let internal: CallInternal<aztec::context::PublicContext> = CallInternal { context };
58-
aztec::contract_self::ContractSelfPublic::new(context, storage, call_self, call_self_static, internal)
59-
};
76+
let mut self = __aztec_nr_internals__create_public_self::<$args_len_quote>();
6077
};
6178

6279
let original_function_name = f.name();

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ pub(crate) mod internal;
1212

1313
use abi_export::create_fn_abi_export;
1414
use external::{
15-
private::generate_private_external, public::generate_public_external, utility::generate_utility_external,
15+
private::generate_private_external,
16+
public::{generate_public_external, generate_public_self_creator},
17+
utility::generate_utility_external,
1618
};
1719
use internal::{generate_private_internal, generate_public_internal};
1820

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

52+
// Emit a contract-level helper that constructs `self` for public functions. Each transformed public function calls
53+
// this helper rather than inlining the preamble. The helper is only useful for public external functions, so we
54+
// skip emitting it when the contract has none.
55+
let public_self_creator = if public_functions.len() > 0 {
56+
generate_public_self_creator(m)
57+
} else {
58+
quote {}
59+
};
60+
5061
// Now that we have generated quotes of the new functions based on the original function definitions, we replace
5162
// the original functions' bodies with `static_assert(false, ...)` to prevent them from being called directly from
5263
// within the contract. We also need to set the return type to `()` to avoid compilation errors.
@@ -84,6 +95,7 @@ pub(crate) comptime fn process_functions(m: Module) -> Quoted {
8495

8596
// We return the new functions' quotes to be injected into the contract.
8697
quote {
98+
$public_self_creator
8799
$transformed_private_functions
88100
$transformed_public_functions
89101
$transformed_utility_functions

noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ error: Argument from in function foo must be of type AztecAddress, but is of typ
1414
2: aztec
1515
at <repo>/noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21
1616
3: process_functions
17-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9
17+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:9
1818
4: [T]::map
1919
at std/vector.nr:67:33
2020
5: process_functions
21-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41
21+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:41
2222
6: generate_public_external
23-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9
23+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:114:9
2424
7: create_authorize_once_check
2525
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:72:9
2626

noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ error: Function foo does not have a from parameter. Please specify which one to
1414
2: aztec
1515
at <repo>/noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21
1616
3: process_functions
17-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9
17+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:9
1818
4: [T]::map
1919
at std/vector.nr:67:33
2020
5: process_functions
21-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41
21+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:41
2222
6: generate_public_external
23-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9
23+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:114:9
2424
7: create_authorize_once_check
2525
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:67:9
2626

noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ error: Function foo does not have a authwit_nonce. Please specify which one to u
1414
2: aztec
1515
at <repo>/noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21
1616
3: process_functions
17-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9
17+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:9
1818
4: [T]::map
1919
at std/vector.nr:67:33
2020
5: process_functions
21-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41
21+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:41
2222
6: generate_public_external
23-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9
23+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:114:9
2424
7: create_authorize_once_check
2525
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:81:9
2626

noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ error: Argument authwit_nonce in function foo must be of type Field, but is of t
1414
2: aztec
1515
at <repo>/noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21
1616
3: process_functions
17-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9
17+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:9
1818
4: [T]::map
1919
at std/vector.nr:67:33
2020
5: process_functions
21-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41
21+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:48:41
2222
6: generate_public_external
23-
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9
23+
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:114:9
2424
7: create_authorize_once_check
2525
at <repo>/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:86:9
2626

0 commit comments

Comments
 (0)