Skip to content

Commit ea2e122

Browse files
author
AztecBot
committed
Merge branch 'next' into merge-train/barretenberg
2 parents 8f5ff28 + 29f2d4e commit ea2e122

File tree

59 files changed

+599
-878
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+599
-878
lines changed

boxes/boxes/react/src/contracts/src/main.nr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ contract BoxReact {
66
macros::{functions::{external, initializer}, storage::storage},
77
messages::message_delivery::MessageDelivery,
88
protocol_types::address::AztecAddress,
9-
state_vars::PrivateMutable,
9+
state_vars::{Owned, PrivateMutable},
1010
};
1111
use value_note::value_note::ValueNote;
1212

1313
#[storage]
1414
struct Storage<Context> {
15-
numbers: PrivateMutable<ValueNote, Context>,
15+
numbers: Owned<PrivateMutable<ValueNote, Context>, Context>,
1616
}
1717

1818
#[external("private")]

boxes/boxes/vite/src/contracts/src/main.nr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ contract BoxReact {
66
macros::{functions::{external, initializer}, storage::storage},
77
messages::message_delivery::MessageDelivery,
88
protocol_types::address::AztecAddress,
9-
state_vars::PrivateMutable,
9+
state_vars::{Owned, PrivateMutable},
1010
};
1111
use value_note::value_note::ValueNote;
1212

1313
#[storage]
1414
struct Storage<Context> {
15-
numbers: PrivateMutable<ValueNote, Context>,
15+
numbers: Owned<PrivateMutable<ValueNote, Context>, Context>,
1616
}
1717

1818
#[external("private")]

docs/docs/developers/docs/resources/migration_notes.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,25 @@ where
9090
```
9191

9292
`PrivateImmutable`, `PrivateMutable` and `PrivateSet` got modified to directly contain the owner instead of implicitly "containing it" by including it in the storage slot via a `Map`.
93-
Now the `Map` is redundant and the relevant state variable should be moved out of it:
93+
These state variables now implement a newly introduced `OwnedStateVariable` trait (see docs of `OwnedStateVariable` for explanation of what it is).
94+
These changes make the state variables incompatible with `Map` and now instead these should be wrapped in new `Owned` state variable:
9495

9596
```diff
9697
#[storage]
9798
struct Storage<Context> {
9899
- private_nfts: Map<AztecAddress, PrivateSet<NFTNote, Context>, Context>,
99-
+ private_nfts: PrivateSet<NFTNote, Context>,
100+
+ private_nfts: Owned<PrivateSet<NFTNote, Context>, Context>,
100101
}
101102
```
102103

103-
Now we have an `at` method on the private state variables that scopes it to a given owner.
104-
Given that we used to call `at` on the map and now we call it directly on the set if you so the above change it should not be required of you to do any further changes in your contract.
104+
Note that even though the types of your state variables are changing from `Map<AztecAddress, T, Context>` to `Owned<T, Context>`, usage remains unchanged:
105+
106+
```
107+
let nft_notes = self.storage.private_nfts.at(from).pop_notes(NoteGetterOptions::new().select(NFTNote::properties().token_id, Comparator.EQ, token_id).set_limit(1));
108+
```
109+
110+
With this change the underlying notes will inherit the storage slot of the `Owned` state variable.
111+
This is unlike `Map` where the nested state variable got the storage slot computed as `hash([map_storage_slot, key])`.
105112

106113
if you had `PrivateImmutable` or `PrivateMutable` defined out of a `Map`, e.g.:
107114

@@ -113,12 +120,23 @@ struct Storage<Context> {
113120
```
114121

115122
you were most likely dealing with some kind of admin flow where only the admin can modify the state variable.
116-
Now, unfortunately, there is a bit of a regression and you will need to call `at` on the state var:
123+
Now, unfortunately, there is a bit of a regression and you will need to wrap the state variable in `Owned` and call `at` on the state var:
117124

118125
```diff
119-
- self.storage.signing_public_key.initialize(pub_key_note)
120-
+ self.storage.signing_public_key.at(self.address).initialize(pub_key_note)
121-
.emit(self.address, MessageDelivery.CONSTRAINED_ONCHAIN);
126+
+ use aztec::state_vars::Owned;
127+
128+
#[storage]
129+
struct Storage<Context> {
130+
- signing_public_key: PrivateImmutable<PublicKeyNote, Context>,
131+
+ signing_public_key: Owned<PrivateImmutable<PublicKeyNote, Context>, Context>,
132+
}
133+
134+
#[external("private")]
135+
fn my_external_function() {
136+
- self.storage.signing_public_key.initialize(pub_key_note)
137+
+ self.storage.signing_public_key.at(self.address).initialize(pub_key_note)
138+
.emit(self.address, MessageDelivery.CONSTRAINED_ONCHAIN);
139+
}
122140
```
123141

124142
We are likely to come up with a concept of admin state variables in the future.

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

Lines changed: 53 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ use poseidon::poseidon2::Poseidon2Hasher;
22
use std::{collections::umap::UHashMap, hash::BuildHasherDefault};
33

44
use super::utils::AsStrQuote;
5-
use super::utils::get_storage_size;
65

76
/// Stores a map from a module to the name of the struct that describes its storage layout.
87
/// This is then used when generating a `storage_layout()` getter on the contract struct.
98
pub comptime mut global STORAGE_LAYOUT_NAME: UHashMap<Module, Quoted, BuildHasherDefault<Poseidon2Hasher>> =
109
UHashMap::default();
1110

12-
/// Marks a struct as the one describing the storage layout of a contract.
13-
///
14-
/// The contract's storage is accessed via the `storage` variable, which will will automatically be made available in
15-
/// all functions as an instance of the struct this macro was applied to.
11+
/// This function
12+
/// - marks the contract as having storage, so that `macros::utils::module_has_storage` will return true,
13+
/// - marks the struct `s` as the one describing the storage layout of a contract,
14+
/// - generates an `impl` block for the storage struct with an `init` function (call to `init` is then injected at the
15+
/// beginning of every `#[external(...)]` and `#[internal]` contract function and the storage is then available as
16+
/// `self.storage`),
17+
/// - creates a `StorageLayout` struct that is is exposed via the `abi(storage)` macro in the contract artifact.
1618
///
1719
/// Only a single struct in the entire contract should have this macro (or `storage_no_init`) applied to it, and the
1820
/// struct has to be called 'Storage'.
@@ -29,56 +31,59 @@ pub comptime fn storage(s: TypeDefinition) -> Quoted {
2931
f"Only one of #[storage] and #[storage_no_init] can be applied to the Storage struct.",
3032
);
3133

32-
// This macro performs three things:
33-
// - it marks the contract as having storage, so that `macros::utils::module_has_storage` will return true and
34-
// functions will have the storage variable injected and initialized via the `init` function.
35-
// - it implements said `init` function by allocating appropriate storage slots to each state variable.
36-
// - it exposes the storage layout by creating a `StorageLayout` struct that is exposed via the `abi(storage)`
37-
// macro.
3834
let mut slot: u32 = 1;
3935
let mut storage_vars_constructors = &[];
40-
let mut storage_layout_fields = &[];
36+
let mut storage_layout_struct_members = &[];
4137
let mut storage_layout_constructors = &[];
4238

43-
// TODO(#8658): uncomment the code below to inject the Context type parameter.
44-
//let mut new_storage_fields = &[];
45-
//let context_generic = s.add_generic("Context");
46-
for field in s.fields_as_written() {
47-
// FIXME: This doesn't handle field types with generics
48-
let (name, typ, _) = field;
49-
let slot_field = slot as Field;
50-
let (storage_field_constructor, storage_size) =
51-
generate_storage_field_constructor(typ, quote { $slot_field });
52-
storage_vars_constructors =
53-
storage_vars_constructors.push_back(quote { $name: $storage_field_constructor });
39+
for storage_struct_member in s.fields_as_written() {
40+
let (name, typ, _) = storage_struct_member;
41+
42+
let maybe_storage_size = std::meta::typ::fresh_type_variable();
43+
let _maybe_context = std::meta::typ::fresh_type_variable();
44+
45+
if !typ.implements(
46+
quote { crate::state_vars::state_variable::StateVariable<$maybe_storage_size, $_maybe_context> }
47+
.as_trait_constraint(),
48+
) {
49+
let _maybe_owned_context = std::meta::typ::fresh_type_variable();
50+
if typ.implements(
51+
quote { crate::state_vars::owned_state_variable::OwnedStateVariable<$_maybe_owned_context> }
52+
.as_trait_constraint(),
53+
) {
54+
panic(
55+
f"Type {typ} implements OwnedStateVariable and hence cannot be placed in Storage struct without being wrapped in Owned. Define the type in storage as Owned<{typ}<..., Context>>, Context>.",
56+
)
57+
}
58+
59+
panic(
60+
f"Type {typ} does not implement StateVariable and hence cannot be placed in Storage struct.",
61+
)
62+
}
63+
64+
let storage_size = maybe_storage_size.as_constant().unwrap();
65+
let slot_as_field = slot as Field;
66+
67+
storage_vars_constructors = storage_vars_constructors.push_back(
68+
quote { $name: aztec::state_vars::state_variable::StateVariable::<$storage_size, Context>::new(context, $slot_as_field) },
69+
);
70+
5471
// We have `Storable` in a separate `.nr` file instead of defining it in the last quote of this function
5572
// because that way a dev gets a more reasonable error if he defines a struct with the same name in
5673
// a contract.
57-
storage_layout_fields = storage_layout_fields.push_back(
58-
quote { pub $name: dep::aztec::state_vars::storage::Storable },
74+
storage_layout_struct_members = storage_layout_struct_members.push_back(
75+
quote { pub $name: aztec::state_vars::storage::Storable },
5976
);
6077
storage_layout_constructors = storage_layout_constructors.push_back(
61-
quote { $name: dep::aztec::state_vars::storage::Storable { slot: $slot_field } },
78+
quote { $name: aztec::state_vars::storage::Storable { slot: $slot_as_field } },
6279
);
63-
//let with_context_generic = add_context_generic(typ, context_generic);
64-
//println(with_context_generic);
65-
//new_storage_fields = new_storage_fields.push_back((name, with_context_generic ));
80+
6681
slot += storage_size;
6782
}
6883

69-
//s.set_fields(new_storage_fields);
7084
let storage_vars_constructors = storage_vars_constructors.join(quote {,});
71-
let storage_impl = quote {
72-
impl<Context> Storage<Context> {
73-
fn init(context: Context) -> Self {
74-
Self {
75-
$storage_vars_constructors
76-
}
77-
}
78-
}
79-
};
8085

81-
let storage_layout_fields = storage_layout_fields.join(quote {,});
86+
let storage_layout_struct_members = storage_layout_struct_members.join(quote {,});
8287
let storage_layout_constructors = storage_layout_constructors.join(quote {,});
8388

8489
let module = s.module();
@@ -88,10 +93,16 @@ pub comptime fn storage(s: TypeDefinition) -> Quoted {
8893
STORAGE_LAYOUT_NAME.insert(module, storage_layout_name);
8994

9095
quote {
91-
$storage_impl
96+
impl<Context> Storage<Context> {
97+
fn init(context: Context) -> Self {
98+
Self {
99+
$storage_vars_constructors
100+
}
101+
}
102+
}
92103

93104
pub struct StorageLayoutFields {
94-
$storage_layout_fields
105+
$storage_layout_struct_members
95106
}
96107

97108
pub struct StorageLayout<let N: u32> {
@@ -135,62 +146,3 @@ pub comptime fn storage_no_init(s: TypeDefinition) {
135146
f"Only one of #[storage] and #[storage_no_init] can be applied to the Storage struct.",
136147
);
137148
}
138-
139-
/// Returns the expression required to initialize a state variable with a given slot, along with its serialization size,
140-
/// i.e. how many contiguous storage slots the variable requires.
141-
comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted) -> (Quoted, u32) {
142-
assert(
143-
typ.as_data_type().is_some(),
144-
"Storage containers must be generic structs of the form `Container<_, Context>`, or Map<Key, _, Context>",
145-
);
146-
let (container_struct, generics) = typ.as_data_type().unwrap();
147-
let struct_name = container_struct.name();
148-
149-
let constructor = if is_storage_map(typ) {
150-
// Map state variables recursively initialize their contents - this includes nested maps.
151-
let (value_constructor, _) =
152-
generate_storage_field_constructor(generics[1], quote { slot });
153-
154-
quote { $struct_name::new(context, $slot, | context, slot | { $value_constructor }) }
155-
} else {
156-
// We assume below that all state variables implement `fn new<Context>(context: Context, slot: Field) -> Self`.
157-
quote { $struct_name::new(context, $slot)}
158-
};
159-
160-
(constructor, get_storage_size(typ))
161-
}
162-
163-
/// Returns true if `typ` is `state_vars::map::Map`.
164-
comptime fn is_storage_map(typ: Type) -> bool {
165-
if typ.as_data_type().is_some() {
166-
let (def, generics) = typ.as_data_type().unwrap();
167-
let maybe_map = if (def.name() == quote { Map }) & (generics.len() == 3) {
168-
let maybe_key = generics[0];
169-
let maybe_value = generics[1];
170-
let maybe_context = generics[2];
171-
quote { crate::state_vars::map::Map<$maybe_key, $maybe_value, $maybe_context> }.as_type()
172-
} else {
173-
quote {()}.as_type()
174-
};
175-
typ == maybe_map
176-
} else {
177-
false
178-
}
179-
}
180-
181-
comptime fn add_context_generic(typ: Type, context_generic: Type) -> Type {
182-
let (def, mut generics) = typ.as_data_type().expect(
183-
f"Storage containers must be generic structs of the form `Container<..., Context>`",
184-
);
185-
let name = def.name();
186-
187-
if is_storage_map(typ) {
188-
generics[generics.len() - 2] = add_context_generic(generics[1], context_generic);
189-
generics[generics.len() - 1] = context_generic;
190-
} else {
191-
generics[generics.len() - 1] = context_generic;
192-
}
193-
194-
let generics = generics.map(|typ: Type| quote {$typ}).join(quote {,});
195-
quote { $name<$generics> }.as_type()
196-
}

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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -164,21 +164,6 @@ pub(crate) comptime fn compute_struct_selector(
164164
unquote!(computation_quote)
165165
}
166166

167-
/// Returns how many storage slots a type needs to reserve for itself. State variables must implement the Storage trait
168-
/// for slots to be allocated for them.
169-
pub(crate) comptime fn get_storage_size(typ: Type) -> u32 {
170-
// We create a type variable for the storage size. We can't simply read the value used in the implementation because
171-
// it may not be a constant (e.g. N + 1). We then bind it to the implementation of the Storage trait.
172-
let storage_size = std::meta::typ::fresh_type_variable();
173-
assert(
174-
typ.implements(quote { crate::state_vars::HasStorageSlot<$storage_size> }
175-
.as_trait_constraint()),
176-
f"Attempted to fetch storage size, but {typ} does not implement the HasStorageSlot trait",
177-
);
178-
179-
storage_size.as_constant().unwrap()
180-
}
181-
182167
pub(crate) comptime fn module_has_storage(m: Module) -> bool {
183168
m.structs().any(|s: TypeDefinition| {
184169
s.has_named_attribute("storage") | s.has_named_attribute("storage_no_init")

noir-projects/aztec-nr/aztec/src/state_vars/delayed_public_mutable.nr

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use dep::protocol_types::{
1010

1111
use crate::{
1212
context::{PrivateContext, PublicContext, UtilityContext},
13-
state_vars::storage::HasStorageSlot,
13+
state_vars::state_variable::StateVariable,
1414
utils::with_hash::WithHash,
1515
};
1616

@@ -21,17 +21,6 @@ pub struct DelayedPublicMutable<T, let InitialDelay: u64, Context> {
2121
storage_slot: Field,
2222
}
2323

24-
// This will make the Aztec macros require that T implements the Packable and Eq traits, and allocate `M + 1` storage
25-
// slots to this state variable.
26-
impl<T, let InitialDelay: u64, Context, let M: u32> HasStorageSlot<M + 1> for DelayedPublicMutable<T, InitialDelay, Context>
27-
where
28-
DelayedPublicMutableValues<T, InitialDelay>: Packable<N = M>,
29-
{
30-
fn get_storage_slot(self) -> Field {
31-
self.storage_slot
32-
}
33-
}
34-
3524
// DelayedPublicMutable<T> stores a value of type T that is:
3625
// - publicly known (i.e. unencrypted)
3726
// - mutable in public
@@ -43,11 +32,21 @@ where
4332
// too far into the future, so that they can guarantee the value will not have possibly changed by then (because of the
4433
// delay). The delay for changing a value is initially equal to InitialDelay, but can be changed by calling
4534
// `schedule_delay_change`.
46-
impl<T, let InitialDelay: u64, Context> DelayedPublicMutable<T, InitialDelay, Context> {
47-
pub fn new(context: Context, storage_slot: Field) -> Self {
35+
//
36+
// This implementation requires that T implements the Packable and Eq traits, and allocates `M + 1` storage slots to
37+
// this state variable.
38+
impl<T, let InitialDelay: u64, Context, let M: u32> StateVariable<M + 1, Context> for DelayedPublicMutable<T, InitialDelay, Context>
39+
where
40+
DelayedPublicMutableValues<T, InitialDelay>: Packable<N = M>,
41+
{
42+
fn new(context: Context, storage_slot: Field) -> Self {
4843
assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1.");
4944
Self { context, storage_slot }
5045
}
46+
47+
fn get_storage_slot(self) -> Field {
48+
self.storage_slot
49+
}
5150
}
5251

5352
impl<T, let InitialDelay: u64> DelayedPublicMutable<T, InitialDelay, PublicContext>

noir-projects/aztec-nr/aztec/src/state_vars/delayed_public_mutable/test.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
context::{PrivateContext, PublicContext, UtilityContext},
3-
state_vars::delayed_public_mutable::DelayedPublicMutable,
3+
state_vars::{delayed_public_mutable::DelayedPublicMutable, state_variable::StateVariable},
44
test::{helpers::test_environment::TestEnvironment, mocks::mock_struct::MockStruct},
55
};
66
use protocol_types::traits::Empty;

0 commit comments

Comments
 (0)