From 52f87c501cc987d09077053ae62a9753e429b377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 15 May 2024 21:06:51 +0000 Subject: [PATCH 01/15] Remove Context, make state variables generic instead --- noir-projects/aztec-nr/authwit/src/account.nr | 69 +++------ noir-projects/aztec-nr/authwit/src/auth.nr | 2 +- noir-projects/aztec-nr/aztec/src/context.nr | 24 --- .../aztec-nr/aztec/src/state_vars/map.nr | 7 +- .../aztec/src/state_vars/private_immutable.nr | 40 ++--- .../aztec/src/state_vars/private_mutable.nr | 52 ++++--- .../aztec/src/state_vars/private_set.nr | 36 +++-- .../aztec/src/state_vars/public_immutable.nr | 60 +++++++- .../aztec/src/state_vars/public_mutable.nr | 40 ++++- .../aztec/src/state_vars/shared_immutable.nr | 30 ++-- .../shared_mutable/shared_mutable.nr | 144 +++++++++--------- .../shared_mutable_private_getter.nr | 2 +- .../src/easy_private_uint.nr | 17 +-- .../aztec-nr/value-note/src/balance_utils.nr | 4 +- .../aztec-nr/value-note/src/utils.nr | 8 +- .../app_subscription_contract/src/main.nr | 30 ++-- .../contracts/auth_contract/src/main.nr | 6 +- .../avm_initializer_test_contract/src/main.nr | 4 +- .../src/main.nr | 4 +- .../contracts/avm_test_contract/src/main.nr | 8 +- .../benchmarking_contract/src/main.nr | 8 +- .../contracts/card_game_contract/src/cards.nr | 15 +- .../contracts/card_game_contract/src/main.nr | 10 +- .../contracts/child_contract/src/main.nr | 10 +- .../contracts/claim_contract/src/main.nr | 6 +- .../contracts/counter_contract/src/main.nr | 5 +- .../crowdfunding_contract/src/main.nr | 10 +- .../delegated_on_contract/src/main.nr | 6 +- .../contracts/delegator_contract/src/main.nr | 6 +- .../docs_example_contract/src/main.nr | 27 ++-- .../src/types/card_note.nr | 8 +- .../easy_private_token_contract/src/main.nr | 4 +- .../easy_private_voting_contract/src/main.nr | 9 +- .../ecdsa_account_contract/src/main.nr | 15 +- .../contracts/escrow_contract/src/main.nr | 6 +- .../contracts/fpc_contract/src/main.nr | 6 +- .../contracts/gas_token_contract/src/main.nr | 6 +- .../inclusion_proofs_contract/src/main.nr | 10 +- .../key_registry_contract/src/main.nr | 18 +-- .../contracts/lending_contract/src/main.nr | 14 +- .../pending_note_hashes_contract/src/main.nr | 5 +- .../contracts/price_feed_contract/src/main.nr | 5 +- .../schnorr_account_contract/src/main.nr | 17 +-- .../src/main.nr | 8 +- .../src/main.nr | 8 +- .../stateful_test_contract/src/main.nr | 9 +- .../contracts/test_contract/src/main.nr | 8 +- .../token_blacklist_contract/src/main.nr | 12 +- .../src/types/balances_map.nr | 12 +- .../token_bridge_contract/src/main.nr | 6 +- .../contracts/token_contract/src/main.nr | 32 ++-- .../token_contract/src/types/balances_map.nr | 13 +- .../contracts/uniswap_contract/src/main.nr | 8 +- .../crates/types/src/constants.nr | 6 +- .../aztec_macros/src/transforms/functions.rs | 27 ++-- .../aztec_macros/src/transforms/storage.rs | 46 +++--- 56 files changed, 516 insertions(+), 492 deletions(-) diff --git a/noir-projects/aztec-nr/authwit/src/account.nr b/noir-projects/aztec-nr/authwit/src/account.nr index eb926315a65..766a467c55e 100644 --- a/noir-projects/aztec-nr/authwit/src/account.nr +++ b/noir-projects/aztec-nr/authwit/src/account.nr @@ -1,17 +1,17 @@ -use dep::aztec::context::{PrivateContext, PublicContext, Context}; +use dep::aztec::context::{PrivateContext, PublicContext}; use dep::aztec::state_vars::{Map, PublicMutable}; use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector, hash::pedersen_hash}; use crate::entrypoint::{app::AppPayload, fee::FeePayload}; use crate::auth::{IS_VALID_SELECTOR, compute_outer_authwit_hash}; -struct AccountActions { +struct AccountActions { context: Context, is_valid_impl: fn(&mut PrivateContext, Field) -> bool, - approved_action: Map>, + approved_action: Map, Context>, } -impl AccountActions { +impl AccountActions { pub fn init( context: Context, approved_action_storage_slot: Field, @@ -29,81 +29,58 @@ impl AccountActions { ) } } +} - pub fn private( - context: &mut PrivateContext, - approved_action_storage_slot: Field, - is_valid_impl: fn(&mut PrivateContext, Field) -> bool - ) -> Self { - AccountActions::init( - Context::private(context), - approved_action_storage_slot, - is_valid_impl - ) - } - - pub fn public( - context: &mut PublicContext, - approved_action_storage_slot: Field, - is_valid_impl: fn(&mut PrivateContext, Field) -> bool - ) -> Self { - AccountActions::init( - Context::public(context), - approved_action_storage_slot, - is_valid_impl - ) - } - +impl AccountActions<&mut PrivateContext> { // docs:start:entrypoint pub fn entrypoint(self, app_payload: AppPayload, fee_payload: FeePayload) { let valid_fn = self.is_valid_impl; - let mut private_context = self.context.private.unwrap(); let fee_hash = fee_payload.hash(); - assert(valid_fn(private_context, fee_hash)); - fee_payload.execute_calls(private_context); - private_context.end_setup(); + assert(valid_fn(self.context, fee_hash)); + fee_payload.execute_calls(self.context); + self.context.end_setup(); let app_hash = app_payload.hash(); - assert(valid_fn(private_context, app_hash)); - app_payload.execute_calls(private_context); + assert(valid_fn(self.context, app_hash)); + app_payload.execute_calls(self.context); } // docs:end:entrypoint // docs:start:spend_private_authwit pub fn spend_private_authwit(self, inner_hash: Field) -> Field { - let context = self.context.private.unwrap(); // The `inner_hash` is "siloed" with the `msg_sender` to ensure that only it can // consume the message. // This ensures that contracts cannot consume messages that are not intended for them. let message_hash = compute_outer_authwit_hash( - context.msg_sender(), - context.chain_id(), - context.version(), + self.context.msg_sender(), + self.context.chain_id(), + self.context.version(), inner_hash ); let valid_fn = self.is_valid_impl; - assert(valid_fn(context, message_hash) == true, "Message not authorized by account"); - context.push_new_nullifier(message_hash, 0); + assert(valid_fn(self.context, message_hash) == true, "Message not authorized by account"); + self.context.push_new_nullifier(message_hash, 0); IS_VALID_SELECTOR } // docs:end:spend_private_authwit +} +impl AccountActions<&mut PublicContext> { // docs:start:spend_public_authwit pub fn spend_public_authwit(self, inner_hash: Field) -> Field { - let context = self.context.public.unwrap(); // The `inner_hash` is "siloed" with the `msg_sender` to ensure that only it can // consume the message. // This ensures that contracts cannot consume messages that are not intended for them. let message_hash = compute_outer_authwit_hash( - context.msg_sender(), - context.chain_id(), - context.version(), + self.context.msg_sender(), + self.context.chain_id(), + self.context.version(), inner_hash ); let is_valid = self.approved_action.at(message_hash).read(); assert(is_valid == true, "Message not authorized by account"); - context.push_new_nullifier(message_hash, 0); + self.context.push_new_nullifier(message_hash, 0); IS_VALID_SELECTOR } // docs:end:spend_public_authwit @@ -113,4 +90,4 @@ impl AccountActions { self.approved_action.at(message_hash).write(true); } // docs:end:approve_public_authwit -} +} \ No newline at end of file diff --git a/noir-projects/aztec-nr/authwit/src/auth.nr b/noir-projects/aztec-nr/authwit/src/auth.nr index 55c15acec77..49aa118622a 100644 --- a/noir-projects/aztec-nr/authwit/src/auth.nr +++ b/noir-projects/aztec-nr/authwit/src/auth.nr @@ -5,7 +5,7 @@ use dep::aztec::protocol_types::{ use dep::aztec::{ prelude::Deserialize, context::{ - PrivateContext, PublicContext, Context, gas::GasOpts, + PrivateContext, PublicContext, gas::GasOpts, interface::{ContextInterface, PublicContextInterface} }, hash::hash_args_array diff --git a/noir-projects/aztec-nr/aztec/src/context.nr b/noir-projects/aztec-nr/aztec/src/context.nr index c7d79f2e24b..3d97b62223e 100644 --- a/noir-projects/aztec-nr/aztec/src/context.nr +++ b/noir-projects/aztec-nr/aztec/src/context.nr @@ -16,27 +16,3 @@ use private_context::PackedReturns; use public_context::PublicContext; use public_context::FunctionReturns; use avm_context::AvmContext; - -struct Context { - private: Option<&mut PrivateContext>, - public: Option<&mut PublicContext>, - avm: Option<&mut AvmContext>, -} - -impl Context { - pub fn private(context: &mut PrivateContext) -> Context { - Context { private: Option::some(context), public: Option::none(), avm: Option::none() } - } - - pub fn public(context: &mut PublicContext) -> Context { - Context { public: Option::some(context), private: Option::none(), avm: Option::none() } - } - - pub fn avm(context: &mut AvmContext) -> Context { - Context { avm: Option::some(context), public: Option::none(), private: Option::none() } - } - - pub fn none() -> Context { - Context { public: Option::none(), private: Option::none(), avm: Option::none() } - } -} diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/map.nr b/noir-projects/aztec-nr/aztec/src/state_vars/map.nr index c075578db3f..da09954a436 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/map.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/map.nr @@ -1,18 +1,17 @@ -use crate::context::{PrivateContext, PublicContext, Context}; use dep::protocol_types::{hash::pedersen_hash, traits::ToField}; use crate::state_vars::storage::Storage; // docs:start:map -struct Map { +struct Map { context: Context, storage_slot: Field, state_var_constructor: fn(Context, Field) -> V, } // docs:end:map -impl Storage for Map {} +impl Storage for Map {} -impl Map { +impl Map { // docs:start:new pub fn new( context: Context, diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 67a0268f58b..f6b1778b039 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -1,6 +1,6 @@ use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, hash::pedersen_hash}; -use crate::context::{PrivateContext, Context}; +use crate::context::PrivateContext; use crate::note::{ lifecycle::create_note, note_getter::{get_note, view_notes}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions @@ -9,19 +9,19 @@ use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; // docs:start:struct -struct PrivateImmutable { - context: Option<&mut PrivateContext>, +struct PrivateImmutable { + context: Context, storage_slot: Field, } // docs:end:struct -impl Storage for PrivateImmutable {} +impl Storage for PrivateImmutable {} -impl PrivateImmutable { +impl PrivateImmutable { // docs:start:new pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Self { context: context.private, storage_slot } + Self { context, storage_slot } } // docs:end:new @@ -37,34 +37,36 @@ impl PrivateImmutable { GENERATOR_INDEX__INITIALIZATION_NULLIFIER ) } +} - // docs:start:is_initialized - unconstrained pub fn is_initialized(self) -> bool { - let nullifier = self.compute_initialization_nullifier(); - check_nullifier_exists(nullifier) - } - // docs:end:is_initialized - +impl PrivateImmutable { // docs:start:initialize pub fn initialize(self, note: &mut Note, broadcast: bool) where Note: NoteInterface { - let context = self.context.unwrap(); - // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); - context.push_new_nullifier(nullifier, 0); + self.context.push_new_nullifier(nullifier, 0); - create_note(context, self.storage_slot, note, broadcast); + create_note(self.context, self.storage_slot, note, broadcast); } // docs:end:initialize // docs:start:get_note pub fn get_note(self) -> Note where Note: NoteInterface { - let context = self.context.unwrap(); let storage_slot = self.storage_slot; - get_note(context, storage_slot) + get_note(self.context, storage_slot) } // docs:end:get_note +} + +impl PrivateImmutable { + // docs:start:is_initialized + unconstrained pub fn is_initialized(self) -> bool { + let nullifier = self.compute_initialization_nullifier(); + check_nullifier_exists(nullifier) + } + // docs:end:is_initialized + // view_note does not actually use the context, but it calls oracles that are only available in private // docs:start:view_note unconstrained pub fn view_note(self) -> Note where Note: NoteInterface { let mut options = NoteViewerOptions::new(); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index 06942a2cbd0..2830894648f 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -1,6 +1,6 @@ use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, hash::pedersen_hash}; -use crate::context::{PrivateContext, PublicContext, Context}; +use crate::context::PrivateContext; use crate::note::{ lifecycle::{create_note, destroy_note}, note_getter::{get_note, view_notes}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions @@ -9,22 +9,26 @@ use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; // docs:start:struct -struct PrivateMutable { - context: Option<&mut PrivateContext>, +struct PrivateMutable { + context: Context, storage_slot: Field } // docs:end:struct -impl Storage for PrivateMutable {} +impl Storage for PrivateMutable {} -impl PrivateMutable { +impl PrivateMutable { // docs:start:new pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - Self { context: context.private, storage_slot } + Self { context, storage_slot } } // docs:end:new + pub fn to_unconstrained(self) -> PrivateMutable { + PrivateMutable { context: (), storage_slot: self.storage_slot } + } + // The following computation is leaky, in that it doesn't hide the storage slot that has been initialized, nor does it hide the contract address of this contract. // When this initialization nullifier is emitted, an observer could do a dictionary or rainbow attack to learn the preimage of this nullifier to deduce the storage slot and contract address. // For some applications, leaking the details that a particular state variable of a particular contract has been initialized will be unacceptable. @@ -39,54 +43,52 @@ impl PrivateMutable { GENERATOR_INDEX__INITIALIZATION_NULLIFIER ) } +} - // docs:start:is_initialized - unconstrained pub fn is_initialized(self) -> bool { - let nullifier = self.compute_initialization_nullifier(); - check_nullifier_exists(nullifier) - } - // docs:end:is_initialized - +impl PrivateMutable { // docs:start:initialize pub fn initialize(self, note: &mut Note, broadcast: bool) where Note: NoteInterface { - let context = self.context.unwrap(); - // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); - context.push_new_nullifier(nullifier, 0); + self.context.push_new_nullifier(nullifier, 0); - create_note(context, self.storage_slot, note, broadcast); + create_note(self.context, self.storage_slot, note, broadcast); } // docs:end:initialize // docs:start:replace pub fn replace(self, new_note: &mut Note, broadcast: bool) where Note: NoteInterface { - let context = self.context.unwrap(); - let prev_note: Note = get_note(context, self.storage_slot); + let prev_note: Note = get_note(self.context, self.storage_slot); // Nullify previous note. - destroy_note(context, prev_note); + destroy_note(self.context, prev_note); // Add replacement note. - create_note(context, self.storage_slot, new_note, broadcast); + create_note(self.context, self.storage_slot, new_note, broadcast); } // docs:end:replace // docs:start:get_note pub fn get_note(self, broadcast: bool) -> Note where Note: NoteInterface { - let context = self.context.unwrap(); - let mut note = get_note(context, self.storage_slot); + let mut note = get_note(self.context, self.storage_slot); // Nullify current note to make sure it's reading the latest note. - destroy_note(context, note); + destroy_note(self.context, note); // Add the same note again. // Because a nonce is added to every note in the kernel, its nullifier will be different. - create_note(context, self.storage_slot, &mut note, broadcast); + create_note(self.context, self.storage_slot, &mut note, broadcast); note } // docs:end:get_note +} + +impl PrivateMutable { + unconstrained pub fn is_initialized(self) -> bool { + let nullifier = self.compute_initialization_nullifier(); + check_nullifier_exists(nullifier) + } // docs:start:view_note unconstrained pub fn view_note(self) -> Note where Note: NoteInterface { diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index 716a6588355..60bb80b940a 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -1,5 +1,5 @@ use dep::protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, abis::read_request::ReadRequest}; -use crate::context::{PrivateContext, PublicContext, Context}; +use crate::context::{PrivateContext, PublicContext}; use crate::note::{ constants::MAX_NOTES_PER_PAGE, lifecycle::{create_note, create_note_hash_from_public, destroy_note}, note_getter::{get_notes, view_notes}, note_getter_options::NoteGetterOptions, @@ -9,25 +9,36 @@ use crate::note::{ use crate::state_vars::storage::Storage; // docs:start:struct -struct PrivateSet { +struct PrivateSet { context: Context, storage_slot: Field, } // docs:end:struct -impl Storage for PrivateSet {} +impl Storage for PrivateSet {} -impl PrivateSet { +impl PrivateSet { // docs:start:new pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); PrivateSet { context, storage_slot } } // docs:end:new +} + +impl PrivateSet { + // docs:start:insert_from_public + pub fn insert_from_public(self, note: &mut Note) where Note: NoteInterface { + create_note_hash_from_public(self.context, self.storage_slot, note); + } + // docs:end:insert_from_public +} + +impl PrivateSet { // docs:start:insert pub fn insert(self, note: &mut Note, broadcast: bool) where Note: NoteInterface { create_note( - self.context.private.unwrap(), + self.context, self.storage_slot, note, broadcast @@ -35,12 +46,6 @@ impl PrivateSet { } // docs:end:insert - // docs:start:insert_from_public - pub fn insert_from_public(self, note: &mut Note) where Note: NoteInterface { - create_note_hash_from_public(self.context.public.unwrap(), self.storage_slot, note); - } - // docs:end:insert_from_public - // DEPRECATED fn assert_contains_and_remove(_self: Self, _note: &mut Note, _nonce: Field) { assert( @@ -57,12 +62,11 @@ impl PrivateSet { // docs:start:remove pub fn remove(self, note: Note) where Note: NoteInterface { - let context = self.context.private.unwrap(); let note_hash = compute_note_hash_for_read_request(note); - let has_been_read = context.note_hash_read_requests.any(|r: ReadRequest| r.value == note_hash); + let has_been_read = self.context.note_hash_read_requests.any(|r: ReadRequest| r.value == note_hash); assert(has_been_read, "Can only remove a note that has been read from the set."); - destroy_note(context, note); + destroy_note(self.context, note); } // docs:end:remove @@ -72,11 +76,13 @@ impl PrivateSet { options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let storage_slot = self.storage_slot; - let opt_notes = get_notes(self.context.private.unwrap(), storage_slot, options); + let opt_notes = get_notes(self.context, storage_slot, options); opt_notes } // docs:end:get_notes +} +impl PrivateSet { // docs:start:view_notes unconstrained pub fn view_notes( self, diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr index f3fc0828bd6..f782be2ca3a 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr @@ -1,17 +1,20 @@ -use crate::{context::Context, oracle::{storage::{storage_read, storage_write}}, state_vars::storage::Storage}; +use crate::{ + context::{AvmContext, PublicContext}, oracle::{storage::{storage_read, storage_write}}, + state_vars::storage::Storage +}; use dep::protocol_types::{constants::INITIALIZATION_SLOT_SEPARATOR, traits::{Deserialize, Serialize}}; // Just like SharedImmutable but without the ability to read from private functions. // docs:start:public_immutable_struct -struct PublicImmutable { +struct PublicImmutable { context: Context, storage_slot: Field, } // docs:end:public_immutable_struct -impl Storage for PublicImmutable {} +impl Storage for PublicImmutable {} -impl PublicImmutable { +impl PublicImmutable { // docs:start:public_immutable_struct_new pub fn new( // Note: Passing the contexts to new(...) just to have an interface compatible with a Map. @@ -22,12 +25,53 @@ impl PublicImmutable { PublicImmutable { context, storage_slot } } // docs:end:public_immutable_struct_new +} + +impl PublicImmutable { + // docs:start:public_immutable_struct_write + pub fn initialize(self, value: T) where T: Serialize { + // TODO(#4738): Uncomment the following assert + // assert( + // self.context.public.unwrap_unchecked().is_deployment(), "PublicImmutable can only be initialized during contract deployment" + // ); + + // We check that the struct is not yet initialized by checking if the initialization slot is 0 + let initialization_slot = INITIALIZATION_SLOT_SEPARATOR + self.storage_slot; + let fields_read: [Field; 1] = storage_read(initialization_slot); + assert(fields_read[0] == 0, "PublicImmutable already initialized"); + + // We populate the initialization slot with a non-zero value to indicate that the struct is initialized + storage_write(initialization_slot, [0xdead]); + + let fields_write = T::serialize(value); + storage_write(self.storage_slot, fields_write); + } + // docs:end:public_immutable_struct_write + + // Note that we don't access the context, but we do call oracles that are only available in public + // docs:start:public_immutable_struct_read + pub fn read(self) -> T where T: Deserialize { + let fields = storage_read(self.storage_slot); + T::deserialize(fields) + } + // docs:end:public_immutable_struct_read +} + +impl PublicImmutable { + pub fn read(self) -> T where T: Deserialize { + // Note that this is the exact same implementation as for public execution, though it might change in the future + // since unconstrained execution might not rely on the same oracles as used for public execution (which + // transpile to AVM opcodes). + let fields = storage_read(self.storage_slot); + T::deserialize(fields) + } +} +// TODO (https://github.com/AztecProtocol/aztec-packages/issues/5818): remove this impl and leave the PublicContext impl +// once AvmContext becomes PublicContext. +impl PublicImmutable { // docs:start:public_immutable_struct_write pub fn initialize(self, value: T) where T: Serialize { - assert( - self.context.private.is_none(), "PublicImmutable can only be initialized from public functions" - ); // TODO(#4738): Uncomment the following assert // assert( // self.context.public.unwrap_unchecked().is_deployment(), "PublicImmutable can only be initialized during contract deployment" @@ -46,9 +90,9 @@ impl PublicImmutable { } // docs:end:public_immutable_struct_write + // Note that we don't access the context, but we do call oracles that are only available in public // docs:start:public_immutable_struct_read pub fn read(self) -> T where T: Deserialize { - assert(self.context.private.is_none(), "PublicImmutable reads only supported in public functions"); let fields = storage_read(self.storage_slot); T::deserialize(fields) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr index 442a7d55656..128d8a4ce47 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr @@ -1,19 +1,19 @@ -use crate::context::Context; +use crate::context::{AvmContext, PublicContext}; use crate::oracle::storage::storage_read; use crate::oracle::storage::storage_write; use dep::protocol_types::traits::{Deserialize, Serialize}; use crate::state_vars::storage::Storage; // docs:start:public_mutable_struct -struct PublicMutable { +struct PublicMutable { context: Context, storage_slot: Field, } // docs:end:public_mutable_struct -impl Storage for PublicMutable {} +impl Storage for PublicMutable {} -impl PublicMutable { +impl PublicMutable { // docs:start:public_mutable_struct_new pub fn new( // Note: Passing the contexts to new(...) just to have an interface compatible with a Map. @@ -24,10 +24,39 @@ impl PublicMutable { PublicMutable { context, storage_slot } } // docs:end:public_mutable_struct_new +} + +impl PublicMutable { + // docs:start:public_mutable_struct_read + pub fn read(self) -> T where T: Deserialize { + let fields = storage_read(self.storage_slot); + T::deserialize(fields) + } + // docs:end:public_mutable_struct_read + + // docs:start:public_mutable_struct_write + pub fn write(self, value: T) where T: Serialize { + let fields = T::serialize(value); + storage_write(self.storage_slot, fields); + } + // docs:end:public_mutable_struct_write +} + +impl PublicMutable { + pub fn read(self) -> T where T: Deserialize { + // Note that this is the exact same implementation as for public execution, though it might change in the future + // since unconstrained execution might not rely on the same oracles as used for public execution (which + // transpile to AVM opcodes). + let fields = storage_read(self.storage_slot); + T::deserialize(fields) + } +} +// TODO (https://github.com/AztecProtocol/aztec-packages/issues/5818): remove this impl and leave the PublicContext impl +// once AvmContext becomes PublicContext. +impl PublicMutable { // docs:start:public_mutable_struct_read pub fn read(self) -> T where T: Deserialize { - assert(self.context.private.is_none(), "PublicMutable reads only supported in public functions"); let fields = storage_read(self.storage_slot); T::deserialize(fields) } @@ -35,7 +64,6 @@ impl PublicMutable { // docs:start:public_mutable_struct_write pub fn write(self, value: T) where T: Serialize { - assert(self.context.private.is_none(), "PublicMutable writes only supported in public functions"); let fields = T::serialize(value); storage_write(self.storage_slot, fields); } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr index a44a605c3fd..097f2d75867 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr @@ -1,18 +1,18 @@ use crate::{ - context::Context, history::public_storage::public_storage_historical_read, + context::{PrivateContext, PublicContext}, history::public_storage::public_storage_historical_read, oracle::{storage::{storage_read, storage_write}}, state_vars::storage::Storage }; use dep::protocol_types::{constants::INITIALIZATION_SLOT_SEPARATOR, traits::{Deserialize, Serialize}}; // Just like PublicImmutable but with the ability to read from private functions. -struct SharedImmutable{ +struct SharedImmutable{ context: Context, storage_slot: Field, } -impl Storage for SharedImmutable {} +impl Storage for SharedImmutable {} -impl SharedImmutable { +impl SharedImmutable { pub fn new( // Note: Passing the contexts to new(...) just to have an interface compatible with a Map. context: Context, @@ -21,12 +21,11 @@ impl SharedImmutable { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); Self { context, storage_slot } } +} +impl SharedImmutable { // Intended to be only called once. pub fn initialize(self, value: T) where T: Serialize { - assert( - self.context.private.is_none(), "SharedImmutable can only be initialized from public functions" - ); // TODO(#4738): Uncomment the following assert // assert( // self.context.public.unwrap_unchecked().is_deployment(), "SharedImmutable can only be initialized during contract deployment" @@ -45,23 +44,28 @@ impl SharedImmutable { } pub fn read_public(self) -> T where T: Deserialize { - assert(self.context.private.is_none(), "Public read only supported in public functions"); let fields = storage_read(self.storage_slot); T::deserialize(fields) } +} - pub fn read_private(self) -> T where T: Deserialize { - assert(self.context.public.is_none(), "Private read only supported in private functions"); - let private_context = self.context.private.unwrap(); +impl SharedImmutable { + pub fn read_public(self) -> T where T: Deserialize { + let fields = storage_read(self.storage_slot); + T::deserialize(fields) + } +} +impl SharedImmutable { + pub fn read_private(self) -> T where T: Deserialize { let mut fields = [0; T_SERIALIZED_LEN]; for i in 0..fields.len() { fields[i] = public_storage_historical_read( - (*private_context), + (*self.context), self.storage_slot + i as Field, - (*private_context).this_address() + (*self.context).this_address() ); } T::deserialize(fields) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable.nr index a36bda7e6cb..0b8c91ef75c 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable.nr @@ -1,6 +1,6 @@ use dep::protocol_types::{hash::pedersen_hash, traits::FromField}; -use crate::context::{PrivateContext, PublicContext, Context}; +use crate::context::{PrivateContext, PublicContext}; use crate::history::public_storage::public_storage_historical_read; use crate::public_storage; use crate::state_vars::{ @@ -8,7 +8,7 @@ use crate::state_vars::{ shared_mutable::{scheduled_value_change::ScheduledValueChange, scheduled_delay_change::ScheduledDelayChange} }; -struct SharedMutable { +struct SharedMutable { context: Context, storage_slot: Field, } @@ -20,7 +20,7 @@ struct SharedMutable { // // TODO https://github.com/AztecProtocol/aztec-packages/issues/5736: change the storage allocation scheme so that we // can actually use it here -impl Storage for SharedMutable {} +impl Storage for SharedMutable {} // SharedMutable stores a value of type T that is: // - publicly known (i.e. unencrypted) @@ -33,18 +33,31 @@ impl Storage for SharedMutable {} // future, so that they can guarantee the value will not have possibly changed by then (because of the delay). // The delay for changing a value is initially equal to INITIAL_DELAY, but can be changed by calling // `schedule_delay_change`. -impl SharedMutable { +impl SharedMutable { pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); Self { context, storage_slot } } + // Since we can't rely on the native storage allocation scheme, we hash the storage slot to get a unique location in + // which we can safely store as much data as we need. + // See https://github.com/AztecProtocol/aztec-packages/issues/5492 and + // https://github.com/AztecProtocol/aztec-packages/issues/5736 + fn get_value_change_storage_slot(self) -> Field { + pedersen_hash([self.storage_slot, 0], 0) + } + + fn get_delay_change_storage_slot(self) -> Field { + pedersen_hash([self.storage_slot, 1], 0) + } +} + +impl SharedMutable { pub fn schedule_value_change(self, new_value: T) { - let context = self.context.public.unwrap(); let mut value_change = self.read_value_change(); let delay_change = self.read_delay_change(); - let block_number = context.block_number() as u32; + let block_number = self.context.block_number() as u32; let current_delay = delay_change.get_current(block_number); // TODO: make this configurable @@ -56,10 +69,9 @@ impl SharedMutable { } pub fn schedule_delay_change(self, new_delay: u32) { - let context = self.context.public.unwrap(); let mut delay_change = self.read_delay_change(); - let block_number = context.block_number() as u32; + let block_number = self.context.block_number() as u32; delay_change.schedule_change(new_delay, block_number); @@ -67,12 +79,12 @@ impl SharedMutable { } pub fn get_current_value_in_public(self) -> T { - let block_number = self.context.public.unwrap().block_number() as u32; + let block_number = self.context.block_number() as u32; self.read_value_change().get_current_at(block_number) } pub fn get_current_delay_in_public(self) -> u32 { - let block_number = self.context.public.unwrap().block_number() as u32; + let block_number = self.context.block_number() as u32; self.read_delay_change().get_current(block_number) } @@ -84,15 +96,31 @@ impl SharedMutable { self.read_delay_change().get_scheduled() } - pub fn get_current_value_in_private(self) -> T where T: FromField { - let mut context = self.context.private.unwrap(); + fn read_value_change(self) -> ScheduledValueChange { + public_storage::read(self.get_value_change_storage_slot()) + } + + fn read_delay_change(self) -> ScheduledDelayChange { + public_storage::read(self.get_delay_change_storage_slot()) + } + + fn write_value_change(self, value_change: ScheduledValueChange) { + public_storage::write(self.get_value_change_storage_slot(), value_change); + } + + fn write_delay_change(self, delay_change: ScheduledDelayChange) { + public_storage::write(self.get_delay_change_storage_slot(), delay_change); + } +} +impl SharedMutable { + pub fn get_current_value_in_private(self) -> T where T: FromField { // When reading the current value in private we construct a historical state proof for the public value. // However, since this value might change, we must constrain the maximum transaction block number as this proof // will only be valid for however many blocks we can ensure the value will not change, which will depend on the // current delay and any scheduled delay changes. - let (value_change, delay_change, historical_block_number) = self.historical_read_from_public_storage(*context); + let (value_change, delay_change, historical_block_number) = self.historical_read_from_public_storage(*self.context); // We use the effective minimum delay as opposed to the current delay at the historical block as this one also // takes into consideration any scheduled delay changes. @@ -106,7 +134,7 @@ impl SharedMutable { // We prevent this transaction from being included in any block after the block horizon, ensuring that the // historical public value matches the current one, since it can only change after the horizon. - context.set_tx_max_block_number(block_horizon); + self.context.set_tx_max_block_number(block_horizon); value_change.get_current_at(historical_block_number) } @@ -136,41 +164,13 @@ impl SharedMutable { (value_change, delay_change, historical_block_number) } - - fn read_value_change(self) -> ScheduledValueChange { - public_storage::read(self.get_value_change_storage_slot()) - } - - fn read_delay_change(self) -> ScheduledDelayChange { - public_storage::read(self.get_delay_change_storage_slot()) - } - - fn write_value_change(self, value_change: ScheduledValueChange) { - public_storage::write(self.get_value_change_storage_slot(), value_change); - } - - fn write_delay_change(self, delay_change: ScheduledDelayChange) { - public_storage::write(self.get_delay_change_storage_slot(), delay_change); - } - - // Since we can't rely on the native storage allocation scheme, we hash the storage slot to get a unique location in - // which we can safely store as much data as we need. - // See https://github.com/AztecProtocol/aztec-packages/issues/5492 and - // https://github.com/AztecProtocol/aztec-packages/issues/5736 - fn get_value_change_storage_slot(self) -> Field { - pedersen_hash([self.storage_slot, 0], 0) - } - - fn get_delay_change_storage_slot(self) -> Field { - pedersen_hash([self.storage_slot, 1], 0) - } } mod test { use dep::std::{merkle::compute_merkle_root, test::OracleMock}; use crate::{ - context::{PublicContext, PrivateContext, Context}, + context::{PublicContext, PrivateContext}, state_vars::shared_mutable::{ shared_mutable::SharedMutable, scheduled_value_change::ScheduledValueChange, scheduled_delay_change::ScheduledDelayChange @@ -193,30 +193,24 @@ mod test { global TEST_INITIAL_DELAY = 3; - fn setup(private: bool) -> (SharedMutable, Field) { + fn setup() -> (SharedMutable, Field) { let block_number = 40; - let context = create_context(block_number, private); + let context = create_context(block_number); let storage_slot = 57; - let state_var: SharedMutable = SharedMutable::new(context, storage_slot); + let state_var = SharedMutable::new(context, storage_slot); (state_var, block_number) } - fn create_context(block_number: Field, private: bool) -> Context { - if private { - let mut private_context = PrivateContext::empty(); - private_context.historical_header.global_variables.block_number = block_number; - Context::private(&mut private_context) - } else { - let mut public_context = PublicContext::empty(); - public_context.inputs.public_global_variables.block_number = block_number; - Context::public(&mut public_context) - } + fn create_context(block_number: Field) -> &mut PublicContext { + let mut public_context = PublicContext::empty(); + public_context.inputs.public_global_variables.block_number = block_number; + &mut public_context } fn mock_value_change_read( - state_var: SharedMutable, + state_var: SharedMutable, pre: Field, post: Field, block_of_change: Field @@ -228,7 +222,7 @@ mod test { } fn mock_delay_change_read( - state_var: SharedMutable, + state_var: SharedMutable, pre: Field, post: Field, block_of_change: Field @@ -244,7 +238,7 @@ mod test { let _ = OracleMock::mock("storageRead").with_params((delay_change_slot, 1)).returns(fields).times(1); } - fn mock_delay_change_read_uninitialized(state_var: SharedMutable) { + fn mock_delay_change_read_uninitialized(state_var: SharedMutable) { let delay_change_slot = state_var.get_delay_change_storage_slot(); let _ = OracleMock::mock("storageRead").with_params((delay_change_slot, 1)).returns([0]).times(1); } @@ -252,7 +246,7 @@ mod test { // Useful since change and delay values are always the global pre/post ones, so we typically only care about their // block of change. fn mock_value_and_delay_read( - state_var: SharedMutable, + state_var: SharedMutable, value_block_of_change: Field, delay_block_of_change: Field ) { @@ -269,7 +263,7 @@ mod test { } fn assert_value_change_write( - state_var: SharedMutable, + state_var: SharedMutable, mock: OracleMock, pre: Field, post: Field, @@ -280,7 +274,7 @@ mod test { } fn assert_delay_change_write( - state_var: SharedMutable, + state_var: SharedMutable, mock: OracleMock, pre: Field, post: Field, @@ -298,7 +292,7 @@ mod test { #[test] fn test_get_current_value_in_public() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Change in the future, current value is pre mock_value_change_read(state_var, pre_value, post_value, block_number + 1); @@ -315,7 +309,7 @@ mod test { #[test] fn test_get_scheduled_value_in_public() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Change in the future, scheduled is post (always is) mock_value_change_read(state_var, pre_value, post_value, block_number + 1); @@ -332,7 +326,7 @@ mod test { #[test] fn test_get_current_delay_in_public() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Uninitialized mock_delay_change_read_uninitialized(state_var); @@ -353,7 +347,7 @@ mod test { #[test] fn test_get_scheduled_delay_in_public_before_change() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Uninitialized mock_delay_change_read_uninitialized(state_var); @@ -374,7 +368,7 @@ mod test { #[test] fn test_schedule_value_change_no_delay() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Last value change was in the past mock_value_change_read(state_var, pre_value, post_value, 0); @@ -392,7 +386,7 @@ mod test { #[test] fn test_schedule_value_change_before_change_no_scheduled_delay() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Value change in the future, delay change in the past mock_value_and_delay_read(state_var, block_number + 1, block_number - 1); @@ -412,7 +406,7 @@ mod test { #[test] fn test_schedule_value_change_before_change_scheduled_delay() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Value change in the future, delay change in the future mock_value_and_delay_read(state_var, block_number + 1, block_number + 1); @@ -433,7 +427,7 @@ mod test { #[test] fn test_schedule_value_change_after_change_no_scheduled_delay() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Value change in the past, delay change in the past mock_value_and_delay_read(state_var, block_number - 1, block_number - 1); @@ -453,7 +447,7 @@ mod test { #[test] fn test_schedule_value_change_after_change_scheduled_delay() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Value change in the past, delay change in the future mock_value_and_delay_read(state_var, block_number - 1, block_number + 1); @@ -474,7 +468,7 @@ mod test { #[test] fn test_schedule_delay_increase_before_change() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Delay change in future, current delay is pre mock_delay_change_read(state_var, pre_delay, post_delay, block_number + 1); @@ -489,7 +483,7 @@ mod test { #[test] fn test_schedule_delay_reduction_before_change() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Delay change in future, current delay is pre mock_delay_change_read(state_var, pre_delay, post_delay, block_number + 1); @@ -510,7 +504,7 @@ mod test { #[test] fn test_schedule_delay_increase_after_change() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Delay change in the past, current delay is post mock_delay_change_read(state_var, pre_delay, post_delay, block_number - 1); @@ -525,7 +519,7 @@ mod test { #[test] fn test_schedule_delay_reduction_after_change() { - let (state_var, block_number) = setup(false); + let (state_var, block_number) = setup(); // Delay change in the past, current delay is post mock_delay_change_read(state_var, pre_delay, post_delay, block_number - 1); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr index 7da8f1524fc..7e923806e73 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr @@ -1,6 +1,6 @@ use dep::protocol_types::{hash::pedersen_hash, traits::FromField, address::AztecAddress}; -use crate::context::{PrivateContext, Context}; +use crate::context::PrivateContext; use crate::history::public_storage::public_storage_historical_read; use crate::public_storage; use crate::state_vars::{ diff --git a/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr b/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr index f6a4c9ebce2..ac4fd81a003 100644 --- a/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr +++ b/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr @@ -1,27 +1,28 @@ use dep::aztec::{ - protocol_types::address::AztecAddress, context::Context, + context::PrivateContext, + protocol_types::address::AztecAddress, note::note_getter_options::NoteGetterOptions, state_vars::PrivateSet }; use dep::value_note::{filter::filter_notes_min_sum, value_note::ValueNote}; -struct EasyPrivateUint { +struct EasyPrivateUint { context: Context, - set: PrivateSet, + set: PrivateSet, storage_slot: Field, } // Holds a note that can act similarly to an int. -impl EasyPrivateUint { +impl EasyPrivateUint { pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); - let set = PrivateSet { context, storage_slot }; + let set = PrivateSet::new(context, storage_slot); EasyPrivateUint { context, set, storage_slot } } +} +impl EasyPrivateUint<&mut PrivateContext> { // Very similar to `value_note::utils::increment`. pub fn add(self, addend: u64, owner: AztecAddress) { - assert(self.context.public.is_none(), "EasyPrivateUint::add can be called from private only."); - // Creates new note for the owner. let mut addend_note = ValueNote::new(addend as Field, owner); @@ -33,8 +34,6 @@ impl EasyPrivateUint { // Very similar to `value_note::utils::decrement`. pub fn sub(self, subtrahend: u64, owner: AztecAddress) { - assert(self.context.public.is_none(), "EasyPrivateUint::sub can be called from private only."); - // docs:start:get_notes let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend as Field); let maybe_notes = self.set.get_notes(options); diff --git a/noir-projects/aztec-nr/value-note/src/balance_utils.nr b/noir-projects/aztec-nr/value-note/src/balance_utils.nr index 83029fe93e8..5cbe5a4d9d6 100644 --- a/noir-projects/aztec-nr/value-note/src/balance_utils.nr +++ b/noir-projects/aztec-nr/value-note/src/balance_utils.nr @@ -2,11 +2,11 @@ use dep::aztec::note::{note_getter::view_notes, note_viewer_options::NoteViewerO use dep::aztec::state_vars::PrivateSet; use crate::value_note::ValueNote; -unconstrained pub fn get_balance(set: PrivateSet) -> Field { +unconstrained pub fn get_balance(set: PrivateSet) -> Field { get_balance_with_offset(set, 0) } -unconstrained pub fn get_balance_with_offset(set: PrivateSet, offset: u32) -> Field { +unconstrained pub fn get_balance_with_offset(set: PrivateSet, offset: u32) -> Field { let mut balance = 0; // docs:start:view_notes let mut options = NoteViewerOptions::new(); diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index 8d88fc6ef0a..8f5a35c5028 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -10,7 +10,7 @@ pub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteG // Creates a new note for the recipient. // Inserts it to the recipient's set of notes. -pub fn increment(balance: PrivateSet, amount: Field, recipient: AztecAddress) { +pub fn increment(balance: PrivateSet, amount: Field, recipient: AztecAddress) { let mut note = ValueNote::new(amount, recipient); // Insert the new note to the owner's set of notes and emit the log if value is non-zero. balance.insert(&mut note, amount != 0); @@ -20,7 +20,7 @@ pub fn increment(balance: PrivateSet, amount: Field, recipient: Aztec // Remove those notes. // If the value of the removed notes exceeds the requested `amount`, create a new note containing the excess value, so that exactly `amount` is removed. // Fail if the sum of the selected notes is less than the amount. -pub fn decrement(balance: PrivateSet, amount: Field, owner: AztecAddress) { +pub fn decrement(balance: PrivateSet, amount: Field, owner: AztecAddress) { let sum = decrement_by_at_most(balance, amount, owner); assert(sum == amount, "Balance too low"); } @@ -34,7 +34,7 @@ pub fn decrement(balance: PrivateSet, amount: Field, owner: AztecAddr // // It returns the decremented amount, which should be less than or equal to max_amount. pub fn decrement_by_at_most( - balance: PrivateSet, + balance: PrivateSet, max_amount: Field, owner: AztecAddress ) -> Field { @@ -61,7 +61,7 @@ pub fn decrement_by_at_most( // Removes the note from the owner's set of notes. // Returns the value of the destroyed note. -pub fn destroy_note(balance: PrivateSet, owner: AztecAddress, note: ValueNote) -> Field { +pub fn destroy_note(balance: PrivateSet, owner: AztecAddress, note: ValueNote) -> Field { // Ensure the note is actually owned by the owner (to prevent user from generating a valid proof while // spending someone else's notes). assert(note.owner.eq(owner)); diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 74cc3d1861b..62a8ced8fab 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -16,17 +16,17 @@ contract AppSubscription { }; #[aztec(storage)] - struct Storage { + struct Storage { // The following is only needed in private but we use ShareImmutable here instead of PrivateImmutable because // the value can be publicly known and SharedImmutable provides us with a better devex here because we don't // have to bother with sharing the note between pixies of users. - target_address: SharedImmutable, - subscription_token_address: SharedImmutable, - subscription_recipient_address: SharedImmutable, - subscription_price: SharedImmutable, - subscriptions: Map>, - gas_token_address: SharedImmutable, - gas_token_limit_per_tx: SharedImmutable, + target_address: SharedImmutable, + subscription_token_address: SharedImmutable, + subscription_recipient_address: SharedImmutable, + subscription_price: SharedImmutable, + subscriptions: Map, Context>, + gas_token_address: SharedImmutable, + gas_token_limit_per_tx: SharedImmutable, } global SUBSCRIPTION_DURATION_IN_BLOCKS = 5; @@ -110,16 +110,16 @@ contract AppSubscription { AppSubscription::at(context.this_address()).assert_block_number(expiry_block_number).static_enqueue(&mut context); let mut subscription_note = SubscriptionNote::new(subscriber_address, expiry_block_number, tx_count); - if (!is_initialized(subscriber_address)) { + + // is_initialized is an unconstrained function, so we must first convert the state variable to an unconstrained + // one to avoid having a mutable reference (to the private context) cross the constrained <> unconstrained + // boundary, which is not allowed. + let is_initialized = storage.subscriptions.at(subscriber_address).to_unconstrained().is_initialized(); + + if (!is_initialized) { storage.subscriptions.at(subscriber_address).initialize(&mut subscription_note, true); } else { storage.subscriptions.at(subscriber_address).replace(&mut subscription_note, true) } } - - // Compiler bug workaround. You can't call an unconstrained function in another module, unless its from an - // unconstained function in your module. - unconstrained fn is_initialized(subscriber_address: AztecAddress) -> pub bool { - storage.subscriptions.at(subscriber_address).is_initialized() - } } diff --git a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr index deb5e34315e..1abd0ca1ccc 100644 --- a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr @@ -8,11 +8,11 @@ contract Auth { global CHANGE_AUTHORIZED_DELAY_BLOCKS = 5; #[aztec(storage)] - struct Storage { + struct Storage { // Admin can change the value of the authorized address via set_authorized() - admin: PublicImmutable, + admin: PublicImmutable, // docs:start:shared_mutable_storage - authorized: SharedMutable, + authorized: SharedMutable, // docs:end:shared_mutable_storage } diff --git a/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr index a71cf2a1de4..96217d55661 100644 --- a/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr @@ -4,8 +4,8 @@ contract AvmInitializerTest { use dep::aztec::protocol_types::address::AztecAddress; #[aztec(storage)] - struct Storage { - immutable: PublicImmutable, + struct Storage { + immutable: PublicImmutable, } /************************************************************************ diff --git a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr index a21791aaee4..75cf3266772 100644 --- a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr @@ -9,8 +9,8 @@ contract AvmNestedCallsTest { use dep::aztec::protocol_types::abis::function_selector::FunctionSelector; #[aztec(storage)] - struct Storage { - single: PublicMutable, + struct Storage { + single: PublicMutable, } /************************************************************************ diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index cbff33dd760..b0fce9988a5 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -33,10 +33,10 @@ contract AvmTest { use dep::compressed_string::CompressedString; #[aztec(storage)] - struct Storage { - single: PublicMutable, - list: PublicMutable, - map: Map>, + struct Storage { + single: PublicMutable, + list: PublicMutable, + map: Map, Context>, } /************************************************************************ diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr index a8b9f34d36b..9edd181e293 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -7,12 +7,12 @@ contract Benchmarking { use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, Map, PublicMutable, PrivateSet}; use dep::value_note::{utils::{increment, decrement}, value_note::ValueNote}; - use dep::aztec::{context::{Context, gas::GasOpts}}; + use dep::aztec::context::gas::GasOpts; #[aztec(storage)] - struct Storage { - notes: Map>, - balances: Map>, + struct Storage { + notes: Map, Context>, + balances: Map, Context>, } // Creates a new value note for the target owner. Use this method to seed an initial set of notes. diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index c43ba634b10..34fdc21949f 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -1,8 +1,7 @@ use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext, NoteHeader, NoteGetterOptions, NoteViewerOptions}; use dep::aztec::{ - protocol_types::{traits::{ToField, Serialize, FromField}, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, - context::{PublicContext, Context}, note::note_getter::view_notes, state_vars::PrivateSet, + protocol_types::{traits::{ToField, Serialize, FromField}, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, note::note_getter::view_notes, state_vars::PrivateSet, note::constants::MAX_NOTES_PER_PAGE }; use dep::std; @@ -63,8 +62,8 @@ impl CardNote { } } -struct Deck { - set: PrivateSet, +struct Deck { + set: PrivateSet, } pub fn filter_cards( @@ -93,15 +92,15 @@ pub fn filter_cards( selected } -impl Deck { +impl Deck { pub fn new(context: Context, storage_slot: Field) -> Self { let set = PrivateSet { context, storage_slot }; Deck { set } } +} +impl Deck<&mut PrivateContext> { pub fn add_cards(&mut self, cards: [Card; N], owner: AztecAddress) -> [CardNote] { - let _context = self.set.context.private.unwrap(); - let mut inserted_cards = &[]; for card in cards { let mut card_note = CardNote::from_card(card, owner); @@ -147,7 +146,9 @@ impl Deck { self.set.remove(card_note.note); } } +} +impl Deck<()> { unconstrained pub fn view_cards(self, offset: u32) -> [Option; MAX_NOTES_PER_PAGE] { let mut options = NoteViewerOptions::new(); let opt_notes = self.set.view_notes(options.set_offset(offset)); diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr index fb37c121fcb..4ccf50c335e 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr @@ -3,7 +3,7 @@ mod game; contract CardGame { use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; - use dep::aztec::{context::Context, hash::pedersen_hash, state_vars::{Map, PublicMutable}}; + use dep::aztec::{hash::pedersen_hash, state_vars::{Map, PublicMutable}}; use dep::value_note::{balance_utils, value_note::{ValueNote, VALUE_NOTE_LEN}}; @@ -13,10 +13,10 @@ contract CardGame { use crate::game::{NUMBER_OF_PLAYERS, NUMBER_OF_CARDS_DECK, PLAYABLE_CARDS, PlayerEntry, Game, GAME_SERIALIZED_LEN}; #[aztec(storage)] - struct Storage { - collections: Map, - game_decks: Map>, - games: Map>, + struct Storage { + collections: Map, Context>, + game_decks: Map, Context>, Context>, + games: Map, Context>, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 75cfe1a1673..220249c7eb8 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -3,16 +3,16 @@ contract Child { use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize}; use dep::aztec::{ - context::{PublicContext, Context, gas::GasOpts}, + context::{PublicContext, gas::GasOpts}, protocol_types::{abis::{call_context::CallContext}}, - note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader} + note::{note_getter_options::NoteGetterOptions, note_viewer_options::NoteViewerOptions, note_header::NoteHeader} }; use dep::value_note::value_note::ValueNote; #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_private_value: PrivateSet, + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, } // Returns a sum of the input and the chain id and version of the contract in private circuit public input's return_values. diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index 090ea87a0a0..5cb41fee562 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -8,11 +8,11 @@ contract Claim { use dep::token::Token; #[aztec(storage)] - struct Storage { + struct Storage { // Address of a contract based on whose notes we distribute the rewards - target_contract: SharedImmutable, + target_contract: SharedImmutable, // Token to be distributed as a reward when claiming - reward_token: SharedImmutable, + reward_token: SharedImmutable, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index d863ecaaaeb..58a9260cbae 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -1,15 +1,14 @@ contract Counter { // docs:start:imports use dep::aztec::prelude::{AztecAddress, Map}; - use dep::aztec::context::Context; use dep::value_note::{balance_utils, value_note::{ValueNote, VALUE_NOTE_LEN}}; use dep::easy_private_state::EasyPrivateUint; // docs:end:imports // docs:start:storage_struct #[aztec(storage)] - struct Storage { - counters: Map, + struct Storage { + counters: Map, Context>, } // docs:end:storage_struct diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index 38fb7984a38..f22a7e10b7a 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -25,15 +25,15 @@ contract Crowdfunding { // docs:start:storage #[aztec(storage)] - struct Storage { + struct Storage { // Token used for donations (e.g. DAI) - donation_token: SharedImmutable, + donation_token: SharedImmutable, // Crowdfunding campaign operator - operator: SharedImmutable, + operator: SharedImmutable, // End of the crowdfunding campaign after which no more donations are accepted - deadline: PublicImmutable, + deadline: PublicImmutable, // Notes emitted to donors when they donate (can be used as proof to obtain rewards, eg in Claim contracts) - donation_receipts: PrivateSet, + donation_receipts: PrivateSet, } // docs:end:storage diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr index e6f093e569d..6d0434f27da 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr @@ -7,9 +7,9 @@ contract DelegatedOn { use dep::value_note::value_note::ValueNote; #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_private_value: PrivateSet, + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index b7f7592350a..632194db9e5 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -5,9 +5,9 @@ contract Delegator { use dep::delegated_on::DelegatedOn; #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_private_value: PrivateSet, + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index e36efb875bc..9b05bb0c7a4 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -18,42 +18,42 @@ contract DocsExample { PrivateContext, Map, PublicMutable, PublicImmutable, PrivateMutable, PrivateImmutable, PrivateSet, SharedImmutable, Deserialize }; - use dep::aztec::{note::note_getter_options::Comparator, context::{PublicContext, Context}}; + use dep::aztec::{note::note_getter_options::Comparator, context::PublicContext}; // how to import methods from other files/folders within your workspace use crate::options::create_account_card_getter_options; use crate::types::{card_note::{CardNote, CARD_NOTE_LEN}, leader::Leader}; #[aztec(storage)] - struct Storage { + struct Storage { // Shows how to create a custom struct in PublicMutable // docs:start:storage-leader-declaration - leader: PublicMutable, + leader: PublicMutable, // docs:end:storage-leader-declaration // docs:start:storage-private-mutable-declaration - legendary_card: PrivateMutable, + legendary_card: PrivateMutable, // docs:end:storage-private-mutable-declaration // just used for docs example to show how to create a private mutable map. - profiles: Map>, + profiles: Map, Context>, // docs:start:storage-set-declaration - set: PrivateSet, + set: PrivateSet, // docs:end:storage-set-declaration // docs:start:storage-private-immutable-declaration - private_immutable: PrivateImmutable, + private_immutable: PrivateImmutable, // docs:end:storage-private-immutable-declaration // docs:start:storage-shared-immutable-declaration - shared_immutable: SharedImmutable, + shared_immutable: SharedImmutable, // docs:end:storage-shared-immutable-declaration // docs:start:storage-minters-declaration - minters: Map>, + minters: Map, Context>, // docs:end:storage-minters-declaration // docs:start:storage-public-immutable-declaration - public_immutable: PublicImmutable, + public_immutable: PublicImmutable, // docs:end:storage-public-immutable-declaration } // Note: The following is no longer necessary to implement manually as our macros do this for us. It is left here // for documentation purposes only. - impl Storage { + impl Storage { fn init(context: Context) -> Self { Storage { // docs:start:storage-leader-init @@ -266,7 +266,8 @@ contract DocsExample { // docs:end:private_mutable_is_initialized // docs:start:get_note-private-immutable - unconstrained fn get_imm_card() -> pub CardNote { + #[aztec(private)] + fn get_imm_card() -> CardNote { storage.private_immutable.get_note() } // docs:end:get_note-private-immutable @@ -322,7 +323,7 @@ contract DocsExample { // docs:end:context-example-context // docs:start:storage-example-context - let mut storage = Storage::init(Context::private(&mut context)); + let mut storage = Storage::init(&mut context); // docs:end:storage-example-context // ************************************************************ diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index aa2fea463d4..3c26b6f6311 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -2,7 +2,7 @@ use dep::aztec::prelude::{AztecAddress, NoteInterface, NoteHeader, PrivateContex use dep::aztec::{ keys::getters::get_ivpk_m, note::{utils::compute_note_hash_for_consumption}, oracle::nullifier_key::get_app_nullifier_secret_key, hash::poseidon2_hash, - protocol_types::{traits::Empty, constants::GENERATOR_INDEX__NOTE_NULLIFIER} + protocol_types::{traits::{Empty, Serialize}, constants::GENERATOR_INDEX__NOTE_NULLIFIER} }; // Shows how to create a custom note @@ -57,3 +57,9 @@ impl NoteInterface for CardNote { ); } } + +impl Serialize<3> for CardNote { + fn serialize(self) -> [Field; 3] { + [ self.points.to_field(), self.randomness, self.owner.to_field() ] + } +} diff --git a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr index 1b5af4b8280..879a229ad3c 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr @@ -5,8 +5,8 @@ contract EasyPrivateToken { use dep::easy_private_state::EasyPrivateUint; #[aztec(storage)] - struct Storage { - balances: Map, + struct Storage { + balances: Map, Context>, } /** diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 6924ca2b328..834fd09e220 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -4,14 +4,13 @@ contract EasyPrivateVoting { AztecAddress, FunctionSelector, NoteHeader, NoteInterface, NoteGetterOptions, PrivateContext, Map, PublicMutable }; - use dep::aztec::context::Context; // docs:end:imports // docs:start:storage_struct #[aztec(storage)] - struct Storage { - admin: PublicMutable, // admin can end vote - tally: Map>, // we will store candidate as key and number of votes as value - vote_ended: PublicMutable, // vote_ended is boolean + struct Storage { + admin: PublicMutable, // admin can end vote + tally: Map, Context>, // we will store candidate as key and number of votes as value + vote_ended: PublicMutable, // vote_ended is boolean } // docs:end:storage_struct diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index d992251604d..8f6cb2043a8 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -8,7 +8,6 @@ contract EcdsaAccount { use dep::aztec::protocol_types::abis::call_context::CallContext; use dep::std; - use dep::aztec::context::Context; use dep::authwit::{ entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness @@ -17,8 +16,8 @@ contract EcdsaAccount { use crate::ecdsa_public_key_note::EcdsaPublicKeyNote; #[aztec(storage)] - struct Storage { - public_key: PrivateImmutable, + struct Storage { + public_key: PrivateImmutable, } global ACCOUNT_ACTIONS_STORAGE_SLOT = 2; @@ -35,20 +34,20 @@ contract EcdsaAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts #[aztec(private)] fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { - let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.entrypoint(app_payload, fee_payload); } #[aztec(private)] #[aztec(noinitcheck)] fn spend_private_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.spend_private_authwit(inner_hash) } #[aztec(public)] fn spend_public_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.spend_public_authwit(inner_hash) } @@ -61,14 +60,14 @@ contract EcdsaAccount { #[aztec(public)] #[aztec(internal)] fn approve_public_authwit(outer_hash: Field) { - let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.approve_public_authwit(outer_hash) } #[contract_library_method] fn is_valid_impl(context: &mut PrivateContext, outer_hash: Field) -> bool { // Load public key from storage - let storage = Storage::init(Context::private(context)); + let storage = Storage::init(context); let public_key = storage.public_key.get_note(); // Load auth witness diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index bc17776d83d..247c4606f2c 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -2,15 +2,13 @@ contract Escrow { use dep::aztec::prelude::{AztecAddress, EthAddress, FunctionSelector, NoteHeader, PrivateContext, PrivateImmutable}; - use dep::aztec::context::{PublicContext, Context}; - use dep::address_note::address_note::AddressNote; use dep::token::Token; #[aztec(storage)] - struct Storage { - owner: PrivateImmutable, + struct Storage { + owner: PrivateImmutable, } // Creates a new instance diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 878dd0c84a3..ba9b300c13f 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -6,9 +6,9 @@ contract FPC { use dep::aztec::context::gas::GasOpts; #[aztec(storage)] - struct Storage { - other_asset: SharedImmutable, - gas_token_address: SharedImmutable, + struct Storage { + other_asset: SharedImmutable, + gas_token_address: SharedImmutable, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr index 7ba446c54ed..c562c2d5972 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr @@ -7,9 +7,9 @@ contract GasToken { use crate::lib::{calculate_fee, get_bridge_gas_msg_hash}; #[aztec(storage)] - struct Storage { - balances: Map>, - portal_address: SharedImmutable, + struct Storage { + balances: Map, Context>, + portal_address: SharedImmutable, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 3e1112ff07b..798a9fcbd9d 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -6,7 +6,7 @@ contract InclusionProofs { }; use dep::aztec::protocol_types::{grumpkin_point::GrumpkinPoint, contract_class_id::ContractClassId}; - use dep::aztec::{context::Context, note::note_getter_options::NoteStatus}; + use dep::aztec::{note::note_getter_options::NoteStatus}; // docs:start:imports use dep::aztec::history::{ contract_inclusion::{ @@ -27,10 +27,10 @@ contract InclusionProofs { use dep::value_note::value_note::ValueNote; // docs:end:value_note_imports #[aztec(storage)] - struct Storage { - private_values: Map>, - public_value: PublicMutable, - public_unused_value: PublicMutable, + struct Storage { + private_values: Map, Context>, + public_value: PublicMutable, + public_unused_value: PublicMutable, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr index ec88658c95d..907f6de0ef5 100644 --- a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr @@ -9,21 +9,21 @@ contract KeyRegistry { global KEY_ROTATION_DELAY = 5; #[aztec(storage)] - struct Storage { + struct Storage { // The following stores a hash of individual master public keys // If you change slots of vars below, you must update the slots in `SharedMutablePrivateGetter` in aztec-nr/keys. // We store x and y coordinates in individual shared mutables as shared mutable currently supports only 1 field - npk_m_x_registry: Map>, - npk_m_y_registry: Map>, + npk_m_x_registry: Map, Context>, + npk_m_y_registry: Map, Context>, - ivpk_m_x_registry: Map>, - ivpk_m_y_registry: Map>, + ivpk_m_x_registry: Map, Context>, + ivpk_m_y_registry: Map, Context>, - ovpk_m_x_registry: Map>, - ovpk_m_y_registry: Map>, + ovpk_m_x_registry: Map, Context>, + ovpk_m_y_registry: Map, Context>, - tpk_m_x_registry: Map>, - tpk_m_y_registry: Map>, + tpk_m_x_registry: Map, Context>, + tpk_m_y_registry: Map, Context>, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index c640a523829..3cd5649cce5 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -11,7 +11,7 @@ mod helpers; // - Liquidations contract Lending { use dep::aztec::prelude::{FunctionSelector, AztecAddress, PrivateContext, Map, PublicMutable}; - use dep::aztec::context::{PublicContext, Context, gas::GasOpts}; + use dep::aztec::context::{PublicContext, gas::GasOpts}; use crate::asset::Asset; use crate::interest_math::compute_multiplier; @@ -21,12 +21,12 @@ contract Lending { // Storage structure, containing all storage, and specifying what slots they use. #[aztec(storage)] - struct Storage { - collateral_asset: PublicMutable, - stable_coin: PublicMutable, - assets: Map>, - collateral: Map>, - static_debt: Map>, // abusing keys very heavily + struct Storage { + collateral_asset: PublicMutable, + stable_coin: PublicMutable, + assets: Map, Context>, + collateral: Map, Context>, + static_debt: Map, Context>, // abusing keys very heavily } struct Position { diff --git a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr index 9cce1d75274..6b7a18d5de5 100644 --- a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr @@ -6,11 +6,10 @@ contract PendingNoteHashes { // Libs use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, PrivateContext, Map, PrivateSet}; use dep::value_note::{balance_utils, filter::filter_notes_min_sum, value_note::{VALUE_NOTE_LEN, ValueNote}}; - use dep::aztec::context::{PublicContext, Context}; #[aztec(storage)] - struct Storage { - balances: Map>, + struct Storage { + balances: Map, Context>, } // TODO(dbanks12): consolidate code into internal helper functions diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index c4afaacf753..33dda84a17f 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -2,13 +2,12 @@ mod asset; contract PriceFeed { use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext, Map, PublicMutable}; - use dep::aztec::{context::{PublicContext, Context}}; use crate::asset::Asset; // Storage structure, containing all storage, and specifying what slots they use. #[aztec(storage)] - struct Storage { - assets: Map>, + struct Storage { + assets: Map, Context>, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 39cc3384b3b..647dbc529f5 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -7,7 +7,6 @@ contract SchnorrAccount { use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, PrivateContext, PrivateImmutable}; use dep::aztec::state_vars::{Map, PublicMutable}; - use dep::aztec::context::Context; use dep::authwit::{ entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness @@ -18,11 +17,11 @@ contract SchnorrAccount { use crate::public_key_note::{PublicKeyNote, PUBLIC_KEY_NOTE_LEN}; #[aztec(storage)] - struct Storage { + struct Storage { // docs:start:storage - signing_public_key: PrivateImmutable, + signing_public_key: PrivateImmutable, // docs:end:storage - approved_actions: Map>, + approved_actions: Map, Context>, } // Constructs the contract @@ -40,7 +39,7 @@ contract SchnorrAccount { #[aztec(private)] #[aztec(noinitcheck)] fn entrypoint(app_payload: AppPayload, fee_payload: FeePayload) { - let actions = AccountActions::private( + let actions = AccountActions::init( &mut context, storage.approved_actions.storage_slot, is_valid_impl @@ -51,7 +50,7 @@ contract SchnorrAccount { #[aztec(private)] #[aztec(noinitcheck)] fn spend_private_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::private( + let actions = AccountActions::init( &mut context, storage.approved_actions.storage_slot, is_valid_impl @@ -62,7 +61,7 @@ contract SchnorrAccount { #[aztec(public)] #[aztec(noinitcheck)] fn spend_public_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::public( + let actions = AccountActions::init( &mut context, storage.approved_actions.storage_slot, is_valid_impl @@ -80,7 +79,7 @@ contract SchnorrAccount { #[aztec(internal)] #[aztec(noinitcheck)] fn approve_public_authwit(outer_hash: Field) { - let actions = AccountActions::public( + let actions = AccountActions::init( &mut context, storage.approved_actions.storage_slot, is_valid_impl @@ -92,7 +91,7 @@ contract SchnorrAccount { fn is_valid_impl(context: &mut PrivateContext, outer_hash: Field) -> bool { // docs:start:entrypoint // Load public key from storage - let storage = Storage::init(Context::private(context)); + let storage = Storage::init(context); // docs:start:get_note let public_key = storage.signing_public_key.get_note(); // docs:end:get_note diff --git a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index a660670a2a5..48d63470a5f 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -17,19 +17,19 @@ contract SchnorrHardcodedAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts #[aztec(private)] fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { - let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.entrypoint(app_payload, fee_payload); } #[aztec(private)] fn spend_private_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.spend_private_authwit(inner_hash) } #[aztec(public)] fn spend_public_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.spend_public_authwit(inner_hash) } @@ -42,7 +42,7 @@ contract SchnorrHardcodedAccount { #[aztec(public)] #[aztec(internal)] fn approve_public_authwit(outer_hash: Field) { - let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.approve_public_authwit(outer_hash) } diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr index 9803ed4f15e..fdaa1163d87 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr @@ -13,19 +13,19 @@ contract SchnorrSingleKeyAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts #[aztec(private)] fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { - let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.entrypoint(app_payload, fee_payload); } #[aztec(private)] fn spend_private_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.spend_private_authwit(inner_hash) } #[aztec(public)] fn spend_public_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.spend_public_authwit(inner_hash) } @@ -38,7 +38,7 @@ contract SchnorrSingleKeyAccount { #[aztec(public)] #[aztec(internal)] fn approve_public_authwit(outer_hash: Field) { - let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.approve_public_authwit(outer_hash) } diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index db8efde4a25..af1e70ae29d 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -3,15 +3,14 @@ contract StatefulTest { use dep::aztec::prelude::{PrivateContext, NoteHeader, Map, PublicMutable, PrivateSet, AztecAddress, FunctionSelector}; use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote}}; use dep::aztec::{ - deploy::deploy_contract as aztec_deploy_contract, - context::{PublicContext, Context, gas::GasOpts}, + deploy::deploy_contract as aztec_deploy_contract, context::{PublicContext, gas::GasOpts}, oracle::get_contract_instance::get_contract_instance, initializer::assert_is_initialized_private }; #[aztec(storage)] - struct Storage { - notes: Map>, - public_values: Map>, + struct Storage { + notes: Map, Context>, + public_values: Map, Context>, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 2a248a7eaf2..b9672c299bf 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -24,7 +24,7 @@ contract Test { use dep::aztec::{ keys::getters::{get_npk_m, get_ivpk_m}, - context::{Context, inputs::private_context_inputs::PrivateContextInputs}, + context::inputs::private_context_inputs::PrivateContextInputs, hash::{pedersen_hash, compute_secret_hash, ArgsHasher}, note::{ lifecycle::{create_note, destroy_note}, note_getter::{get_notes, view_notes}, @@ -44,9 +44,9 @@ contract Test { } #[aztec(storage)] - struct Storage { - example_constant: PrivateImmutable, - example_set: PrivateSet, + struct Storage { + example_constant: PrivateImmutable, + example_set: PrivateSet, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index f2e54e26133..0186b4528e5 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -23,12 +23,12 @@ contract TokenBlacklist { global CHANGE_ROLES_DELAY_BLOCKS = 2; #[aztec(storage)] - struct Storage { - balances: BalancesMap, - total_supply: PublicMutable, - pending_shields: PrivateSet, - public_balances: Map>, - roles: Map>, + struct Storage { + balances: BalancesMap, + total_supply: PublicMutable, + pending_shields: PrivateSet, + public_balances: Map, Context>, + roles: Map, Context>, } // docs:start:constructor diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index db69c2a8c1b..4548c046e83 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -1,15 +1,15 @@ use dep::aztec::prelude::{AztecAddress, NoteHeader, NoteInterface, NoteGetterOptions, NoteViewerOptions, PrivateSet, Map}; use dep::aztec::{ - context::Context, protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, + context::PrivateContext, protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, note::{note_getter::view_notes, note_getter_options::SortOrder} }; use crate::types::token_note::{TokenNote, OwnedNote}; -struct BalancesMap { - map: Map> +struct BalancesMap { + map: Map, Context> } -impl BalancesMap { +impl BalancesMap { pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); Self { @@ -20,7 +20,9 @@ impl BalancesMap { ) } } +} +impl BalancesMap { unconstrained pub fn balance_of( self: Self, owner: AztecAddress @@ -50,7 +52,9 @@ impl BalancesMap { balance } +} +impl BalancesMap { pub fn add( self: Self, owner: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index e503e3f691a..bb7085a2ebe 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -16,9 +16,9 @@ contract TokenBridge { // docs:start:token_bridge_storage_and_constructor // Storage structure, containing all storage, and specifying what slots they use. #[aztec(storage)] - struct Storage { - token: PublicMutable, - portal_address: SharedImmutable, + struct Storage { + token: PublicMutable, + portal_address: SharedImmutable, } // Constructs the contract. diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index e488c5f4f43..266118c8488 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -28,25 +28,25 @@ contract Token { // docs:start:storage_struct #[aztec(storage)] - struct Storage { + struct Storage { // docs:start:storage_admin - admin: PublicMutable, + admin: PublicMutable, // docs:end:storage_admin // docs:start:storage_minters - minters: Map>, + minters: Map, Context>, // docs:end:storage_minters // docs:start:storage_balances - balances: BalancesMap, + balances: BalancesMap, // docs:end:storage_balances - total_supply: PublicMutable, + total_supply: PublicMutable, // docs:start:storage_pending_shields - pending_shields: PrivateSet, + pending_shields: PrivateSet, // docs:end:storage_pending_shields - public_balances: Map>, - symbol: SharedImmutable, - name: SharedImmutable, + public_balances: Map, Context>, + symbol: SharedImmutable, + name: SharedImmutable, // docs:start:storage_decimals - decimals: SharedImmutable, + decimals: SharedImmutable, // docs:end:storage_decimals } // docs:end:storage_struct @@ -86,10 +86,6 @@ contract Token { storage.name.read_private() } - unconstrained fn un_get_name() -> pub [u8; 31] { - storage.name.read_public().to_bytes() - } - #[aztec(public)] fn public_get_symbol() -> pub FieldCompressedString { storage.symbol.read_public() @@ -100,10 +96,6 @@ contract Token { storage.symbol.read_private() } - unconstrained fn un_get_symbol() -> pub [u8; 31] { - storage.symbol.read_public().to_bytes() - } - #[aztec(public)] fn public_get_decimals() -> pub u8 { // docs:start:read_decimals_public @@ -118,10 +110,6 @@ contract Token { // docs:end:read_decimals_private } - unconstrained fn un_get_decimals() -> pub u8 { - storage.decimals.read_public() - } - // docs:start:set_minter #[aztec(public)] fn set_minter(minter: AztecAddress, approve: bool) { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr index 3862e9d0f38..ec6cd43da33 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr @@ -2,18 +2,17 @@ use dep::aztec::prelude::{ AztecAddress, NoteGetterOptions, NoteViewerOptions, NoteHeader, NoteInterface, PrivateContext, PrivateSet, Map }; -use dep::aztec::{ - context::{PublicContext, Context}, hash::pedersen_hash, +use dep::aztec::{hash::pedersen_hash, protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, note::{note_getter::view_notes, note_getter_options::SortOrder} }; use crate::types::token_note::{TokenNote, OwnedNote}; -struct BalancesMap { - map: Map> +struct BalancesMap { + map: Map, Context> } -impl BalancesMap { +impl BalancesMap { pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); Self { @@ -24,7 +23,9 @@ impl BalancesMap { ) } } +} +impl BalancesMap { unconstrained pub fn balance_of( self: Self, owner: AztecAddress @@ -54,7 +55,9 @@ impl BalancesMap { balance } +} +impl BalancesMap { pub fn add( self: Self, owner: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr index afacb220568..379a4b45ad6 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -18,13 +18,13 @@ contract Uniswap { use crate::util::{compute_swap_private_content_hash, compute_swap_public_content_hash}; #[aztec(storage)] - struct Storage { + struct Storage { // like with account contracts, stores the approval message on a slot and tracks if they are active - approved_action: Map>, + approved_action: Map, Context>, // tracks the nonce used to create the approval message for burning funds // gets incremented each time after use to prevent replay attacks - nonce_for_burn_approval: PublicMutable, - portal_address: SharedImmutable, + nonce_for_burn_approval: PublicMutable, + portal_address: SharedImmutable, } // docs:end:uniswap_setup diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 32e4ef51d4c..1b5cea0b99d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -104,12 +104,12 @@ global BLOB_SIZE_IN_BYTES: Field = 31 * 4096; global NESTED_CALL_L2_GAS_BUFFER = 20000; // CONTRACT CLASS CONSTANTS -global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u64 = 32000; +global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u64 = 32; // Bytecode size for private functions is per function, not for the entire contract. // Note that private functions bytecode includes a mix of acir and brillig. -global MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS: u64 = 3000; +global MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS: u64 = 30; // Same for unconstrained functions: the size is per function. -global MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS: u64 = 3000; +global MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS: u64 = 30; // How many fields are on the serialized ClassPrivateFunctionBroadcasted event in addition to MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS. global REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS: u64 = 19; // How many fields are on the serialized ClassUnconstrainedFunctionBroadcasted event in addition to MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS. diff --git a/noir/noir-repo/aztec_macros/src/transforms/functions.rs b/noir/noir-repo/aztec_macros/src/transforms/functions.rs index 90563c6085c..03efa769f9a 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/functions.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/functions.rs @@ -59,7 +59,7 @@ pub fn transform_function( // Add access to the storage struct if let Some(storage_struct_name) = storage_struct_name { - let storage_def = abstract_storage(storage_struct_name, &ty.to_lowercase(), false); + let storage_def = abstract_storage(storage_struct_name, false); func.def.body.statements.insert(0, storage_def); } @@ -216,7 +216,7 @@ pub fn transform_unconstrained(func: &mut NoirFunction, storage_struct_name: Str func.def .body .statements - .insert(0, abstract_storage(storage_struct_name, "Unconstrained", true)); + .insert(0, abstract_storage(storage_struct_name, true)); } /// Helper function that returns what the private context would look like in the ast @@ -564,7 +564,7 @@ fn abstract_return_values(func: &NoirFunction) -> Result>, /// ```noir /// #[aztec(private)] /// fn lol() { -/// let storage = Storage::init(Context::private(context)); +/// let storage = Storage::init(context); /// } /// ``` /// @@ -572,33 +572,28 @@ fn abstract_return_values(func: &NoirFunction) -> Result>, /// ```noir /// #[aztec(public)] /// fn lol() { -/// let storage = Storage::init(Context::public(context)); +/// let storage = Storage::init(context); /// } /// ``` /// /// For unconstrained functions: /// ```noir /// unconstrained fn lol() { -/// let storage = Storage::init(Context::none()); +/// let storage = Storage::init(()); /// } -fn abstract_storage(storage_struct_name: String, typ: &str, unconstrained: bool) -> Statement { - let init_context_call = if unconstrained { - call( - variable_path(chained_dep!("aztec", "context", "Context", "none")), // Path - vec![], // args - ) +fn abstract_storage(storage_struct_name: String, unconstrained: bool) -> Statement { + let context_expr = if unconstrained { + // Note that the literal unit type (i.e. '()') is not the same as a tuple with zero elements + expression(ExpressionKind::Literal(Literal::Unit)) } else { - call( - variable_path(chained_dep!("aztec", "context", "Context", typ)), // Path - vec![mutable_reference("context")], // args - ) + mutable_reference("context") }; assignment( "storage", // Assigned to call( variable_path(chained_path!(storage_struct_name.as_str(), "init")), // Path - vec![init_context_call], // args + vec![context_expr], // args ), ) } diff --git a/noir/noir-repo/aztec_macros/src/transforms/storage.rs b/noir/noir-repo/aztec_macros/src/transforms/storage.rs index 1e3cc011715..a08beececd0 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/storage.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/storage.rs @@ -48,7 +48,7 @@ pub fn check_for_storage_definition( Ok(result.iter().map(|&r#struct| r#struct.name.0.contents.clone()).next()) } -// Check to see if the user has defined a storage struct +// Check to see if the user has defined an impl for the storage struct pub fn check_for_storage_implementation( module: &SortedModule, storage_struct_name: &String, @@ -79,22 +79,25 @@ pub fn generate_storage_field_constructor( variable("context"), slot, lambda( + // This lambda will be equivalent to the following + // | context, slot | { T::new(context, slot) } + // Since the `new` function has type bindings for its arguments, we don't specify the types + // of either context nor slot, and avoid that way having to deal with the generic context + // type. vec![ ( pattern("context"), - make_type(UnresolvedTypeData::Named( - chained_dep!("aztec", "context", "Context"), - vec![], - true, - )), + make_type(UnresolvedTypeData::Unspecified), ), ( Pattern::Identifier(ident("slot")), - make_type(UnresolvedTypeData::FieldElement), + make_type(UnresolvedTypeData::Unspecified), ), ], generate_storage_field_constructor( - &(type_ident.clone(), generics.iter().last().unwrap().clone()), + // Map is expected to have three generic parameters: key, value and context (i.e. + // Map. Here `get(1)` fetches the value type. + &(type_ident.clone(), generics.get(1).unwrap().clone()), variable("slot"), )?, ), @@ -113,15 +116,15 @@ pub fn generate_storage_field_constructor( // Generates the Storage implementation block from the Storage struct definition if it does not exist /// From: /// -/// struct Storage { -/// a_map: Map>, -/// a_nested_map: Map>>, -/// a_field: SomeStoragePrimitive, +/// struct Storage { +/// a_map: Map, Context>, +/// a_nested_map: Map, Context>, Context>, +/// a_field: SomeStoragePrimitive, /// } /// /// To: /// -/// impl Storage { +/// impl Storage { /// fn init(context: Context) -> Self { /// Storage { /// a_map: Map::new(context, 0, |context, slot| { @@ -167,16 +170,16 @@ pub fn generate_storage_implementation( ExpressionKind::constructor((chained_path!(storage_struct_name), field_constructors)), ))); + // This is the type over which the impl is generic. + let generic_context_ident = ident("Context"); + let generic_context_type = make_type(UnresolvedTypeData::Named(ident_path("Context"), vec![], true)); + let init = NoirFunction::normal(FunctionDefinition::normal( &ident("init"), &vec![], &[( ident("context"), - make_type(UnresolvedTypeData::Named( - chained_dep!("aztec", "context", "Context"), - vec![], - true, - )), + generic_context_type.clone(), )], &BlockExpression { statements: vec![storage_constructor_statement] }, &[], @@ -185,11 +188,12 @@ pub fn generate_storage_implementation( let storage_impl = TypeImpl { object_type: UnresolvedType { - typ: UnresolvedTypeData::Named(chained_path!(storage_struct_name), vec![], true), + typ: UnresolvedTypeData::Named(chained_path!(storage_struct_name), vec![generic_context_type.clone()], true), span: Some(Span::default()), }, type_span: Span::default(), - generics: vec![], + generics: vec![generic_context_ident], + methods: vec![(init, Span::default())], }; module.impls.push(storage_impl); @@ -341,7 +345,7 @@ pub fn assign_storage_slots( let mut storage_slot: u64 = 1; for (index, (_, expr_id)) in storage_constructor_expression.fields.iter().enumerate() { - let fields = storage_struct.borrow().get_fields(&[]); + let fields = storage_struct.borrow().get_fields(&storage_constructor_expression.struct_generics); let (field_name, field_type) = fields.get(index).unwrap(); let new_call_expression = match context.def_interner.expression(expr_id) { HirExpression::Call(hir_call_expression) => Ok(hir_call_expression), From 5dc14061377cb4e14eb5bdf95a5dbb7671687591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 15 May 2024 21:19:35 +0000 Subject: [PATCH 02/15] Update migration notes --- docs/docs/misc/migration_notes.md | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index 7f990738590..60be81f449e 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -8,6 +8,62 @@ Aztec is in full-speed development. Literally every version breaks compatibility ## 0.39.0 +### [Aztec.nr] State variable rework + +Aztec.nr state variables have been reworked so that calling private functions in public and vice versa is detected as an error during compilation instead of at runtime. This affects users in a number of ways: + +#### New compile time errors + +It used to be that calling a state variable method only available in public from a private function resulted in obscure runtime errors in the form of a failed `_is_some` assertion. + +Incorrect usage of the state variable methods now results in compile time errors. For example, given the following function: + +```rust +#[aztec(public)] +fn get_decimals() -> pub u8 { + storage.decimals.read_private() +} +``` + +The compiler will now error out with +``` +Expected type SharedImmutable<_, &mut PrivateContext>, found type SharedImmutable +``` + +The key component is the second generic parameter: the compiler expects a `PrivateContext` (becuse `read_private` is only available during private execution), but a `PublicContext` is being used instead (because of the `#[aztec(public)]` attribute). + +#### Generic parameters in `Storage` + +The `Storage` struct (the one marked with `#[aztec(storage)]`) should now be generic over a `Context` type, which matches the new generic parameter of all Aztec.nr libraries. This parameter is always the last generic parameter. + +This means that there's now slightly more boilerplate when declaring this struct: + +```diff +#[aztec(storage)] +- struct Storage { ++ struct Storage { +- nonce_for_burn_approval: PublicMutable, ++ nonce_for_burn_approval: PublicMutable, +- portal_address: SharedImmutable, ++ portal_address: SharedImmutable, +- approved_action: Map>, ++ approved_action: Map, Context>, +} +``` + +Note that `Map` also has a generic `Context` parameter, so for each `Map` an extra `Context` must be added: + +```diff +- game_decks: Map>, ++ game_decks: Map, Context>, Context>, +``` + +This is an unfortunate side-effect, and we're looking into ways to improve this. + +#### Removal of `Context` + +The `Context` type no longer exists. End users typically didn't use it, but if imported it needs to be deleted. + ### [Aztec.nr] Mutable delays in `SharedMutable` The type signature for `SharedMutable` changed from `SharedMutable` to `SharedMutable`. The behavior is the same as before, except the delay can now be changed after deployment by calling `schedule_delay_change`. From c98a474d5a3f5669d9b0e4443f9cabb668f86280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 15 May 2024 22:04:46 +0000 Subject: [PATCH 03/15] Fix noir formatting --- .../contracts/card_game_contract/src/cards.nr | 4 ++-- .../noir-contracts/contracts/child_contract/src/main.nr | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index 34fdc21949f..3ecc180477f 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -1,8 +1,8 @@ use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext, NoteHeader, NoteGetterOptions, NoteViewerOptions}; use dep::aztec::{ - protocol_types::{traits::{ToField, Serialize, FromField}, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, note::note_getter::view_notes, state_vars::PrivateSet, - note::constants::MAX_NOTES_PER_PAGE + protocol_types::{traits::{ToField, Serialize, FromField}, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, + note::note_getter::view_notes, state_vars::PrivateSet, note::constants::MAX_NOTES_PER_PAGE }; use dep::std; use dep::std::{option::Option}; diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 220249c7eb8..e275c1a9648 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -3,9 +3,11 @@ contract Child { use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize}; use dep::aztec::{ - context::{PublicContext, gas::GasOpts}, - protocol_types::{abis::{call_context::CallContext}}, - note::{note_getter_options::NoteGetterOptions, note_viewer_options::NoteViewerOptions, note_header::NoteHeader} + context::{PublicContext, gas::GasOpts}, protocol_types::{abis::{call_context::CallContext}}, + note::{ + note_getter_options::NoteGetterOptions, note_viewer_options::NoteViewerOptions, + note_header::NoteHeader + } }; use dep::value_note::value_note::ValueNote; From 41ac75a90c54273636a2f58c5a72f39e5d1c7bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 15 May 2024 22:06:22 +0000 Subject: [PATCH 04/15] Fix rust formatting --- .../aztec_macros/src/transforms/functions.rs | 5 +--- .../aztec_macros/src/transforms/storage.rs | 23 ++++++++++--------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/noir/noir-repo/aztec_macros/src/transforms/functions.rs b/noir/noir-repo/aztec_macros/src/transforms/functions.rs index 8b6b3c6f4a6..410c5ff667d 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/functions.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/functions.rs @@ -213,10 +213,7 @@ pub fn export_fn_abi( /// /// This will allow developers to access their contract' storage struct in unconstrained functions pub fn transform_unconstrained(func: &mut NoirFunction, storage_struct_name: String) { - func.def - .body - .statements - .insert(0, abstract_storage(storage_struct_name, true)); + func.def.body.statements.insert(0, abstract_storage(storage_struct_name, true)); } /// Helper function that returns what the private context would look like in the ast diff --git a/noir/noir-repo/aztec_macros/src/transforms/storage.rs b/noir/noir-repo/aztec_macros/src/transforms/storage.rs index a08beececd0..bd518a17ee3 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/storage.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/storage.rs @@ -85,10 +85,7 @@ pub fn generate_storage_field_constructor( // of either context nor slot, and avoid that way having to deal with the generic context // type. vec![ - ( - pattern("context"), - make_type(UnresolvedTypeData::Unspecified), - ), + (pattern("context"), make_type(UnresolvedTypeData::Unspecified)), ( Pattern::Identifier(ident("slot")), make_type(UnresolvedTypeData::Unspecified), @@ -172,15 +169,13 @@ pub fn generate_storage_implementation( // This is the type over which the impl is generic. let generic_context_ident = ident("Context"); - let generic_context_type = make_type(UnresolvedTypeData::Named(ident_path("Context"), vec![], true)); + let generic_context_type = + make_type(UnresolvedTypeData::Named(ident_path("Context"), vec![], true)); let init = NoirFunction::normal(FunctionDefinition::normal( &ident("init"), &vec![], - &[( - ident("context"), - generic_context_type.clone(), - )], + &[(ident("context"), generic_context_type.clone())], &BlockExpression { statements: vec![storage_constructor_statement] }, &[], &return_type(chained_path!("Self")), @@ -188,7 +183,11 @@ pub fn generate_storage_implementation( let storage_impl = TypeImpl { object_type: UnresolvedType { - typ: UnresolvedTypeData::Named(chained_path!(storage_struct_name), vec![generic_context_type.clone()], true), + typ: UnresolvedTypeData::Named( + chained_path!(storage_struct_name), + vec![generic_context_type.clone()], + true, + ), span: Some(Span::default()), }, type_span: Span::default(), @@ -345,7 +344,9 @@ pub fn assign_storage_slots( let mut storage_slot: u64 = 1; for (index, (_, expr_id)) in storage_constructor_expression.fields.iter().enumerate() { - let fields = storage_struct.borrow().get_fields(&storage_constructor_expression.struct_generics); + let fields = storage_struct + .borrow() + .get_fields(&storage_constructor_expression.struct_generics); let (field_name, field_type) = fields.get(index).unwrap(); let new_call_expression = match context.def_interner.expression(expr_id) { HirExpression::Call(hir_call_expression) => Ok(hir_call_expression), From 274f84e97cc644b849831050b0b483f55b91e0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 16 May 2024 20:18:18 +0000 Subject: [PATCH 05/15] Update docs --- docs/docs/aztec/aztec/glossary/call_types.md | 6 +++-- .../common_patterns/index.md | 4 +-- .../writing_contracts/storage/index.md | 2 +- .../sandbox_reference/cheat_codes.md | 12 ++++----- .../smart_contract_reference/storage/index.md | 26 +++++++++++++------ 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/docs/docs/aztec/aztec/glossary/call_types.md b/docs/docs/aztec/aztec/glossary/call_types.md index ba700ae846d..ba8e4d6a67e 100644 --- a/docs/docs/aztec/aztec/glossary/call_types.md +++ b/docs/docs/aztec/aztec/glossary/call_types.md @@ -140,9 +140,11 @@ This is the same function that was called by privately enqueuing a call to it! P ### Top-level Unconstrained -Contract functions with the `unconstrained` Noir keyword are a special type of function still under development, and their semantics will likely change in the near future. They are used to perform state queries from an off-chain client, and are never included in any transaction. No guarantees are made on the correctness of the result since they rely exclusively on unconstrained oracle calls. +Contract functions with the `unconstrained` Noir keyword are a special type of function still under development, and their semantics will likely change in the near future. They are used to perform state queries from an off-chain client (from both private and public state!), and are never included in any transaction. No guarantees are made on the correctness of the result since the entire execution is unconstrained and heavily reliant on oracle calls. -A reasonable mental model for them is that of a `view` Solidity function that is never called in any transaction, and is only ever invoked via `eth_call`. Note that in these the caller assumes that the node is acting honestly by exectuing the true contract bytecode with correct blockchain state, the same way the Aztec version assumes the oracles are returning legitimate data. +Any programming language could be used to construct these queries, since all they do is perform arbitrary computation on data that is either publicly available from any node, or locally available from PXE. Top-level unconstrained functions exist because they let developers the rest of the contract code directly by being part of the same Noir contract, as opposed to having to rely on e.g. manual computation of storage slots, struct layout and padding, etc. + +A reasonable mental model for them is that of a `view` Solidity function that can never called in any transaction, and is only ever invoked via `eth_call`. Note that in these the caller assumes that the node is acting honestly by exectuing the true contract bytecode with correct blockchain state, the same way the Aztec version assumes the oracles are returning legitimate data. ### aztec.js diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/index.md b/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/index.md index a09038acc4c..d757d641883 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/index.md +++ b/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/index.md @@ -45,8 +45,8 @@ You can't read public storage in private domain. But nevertheless reading public 1. You pass the data as a parameter to your private method and later assert in public that the data is correct. E.g.: ```rust -struct Storage { - token: PublicMutable, +struct Storage { + token: PublicMutable, } contract Bridge { diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/index.md b/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/index.md index f6cc58cac40..9fe4a3693da 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/index.md +++ b/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/index.md @@ -10,7 +10,7 @@ To learn more about how storage works in Aztec, read [the concepts](/guides/guid ```rust #[aztec(storage)] -struct Storage { +struct Storage { // public state variables // private state variables } diff --git a/docs/docs/reference/reference/sandbox_reference/cheat_codes.md b/docs/docs/reference/reference/sandbox_reference/cheat_codes.md index 2817c900f27..61a2ff83fdb 100644 --- a/docs/docs/reference/reference/sandbox_reference/cheat_codes.md +++ b/docs/docs/reference/reference/sandbox_reference/cheat_codes.md @@ -463,8 +463,8 @@ The baseSlot is specified in the Aztec.nr contract. ```rust #[aztec(storage)] -struct Storage { - balances: Map>, +struct Storage { + balances: Map, Context>, } contract Token { @@ -494,8 +494,8 @@ Note: One Field element occupies a storage slot. Hence, structs with multiple fi ```rust #[aztec(storage)] -struct Storage { - balances: Map>, +struct Storage { + balances: Map, Context>, } contract Token { @@ -526,9 +526,9 @@ Note: One Field element occupies a storage slot. Hence, structs with multiple fi #### Example ```rust #[aztec(storage)] -struct Storage { +struct Storage { ... - pending_shields: Set, + pending_shields: PrivateSet, } contract Token { diff --git a/docs/docs/reference/reference/smart_contract_reference/storage/index.md b/docs/docs/reference/reference/smart_contract_reference/storage/index.md index 267b71f8b08..76d455da82c 100644 --- a/docs/docs/reference/reference/smart_contract_reference/storage/index.md +++ b/docs/docs/reference/reference/smart_contract_reference/storage/index.md @@ -9,7 +9,7 @@ To learn more about storage slots, read [this explainer](/guides/guides/smart_co You control this storage in Aztec using a struct annotated with `#[aztec(storage)]`. This struct serves as the housing unit for all your smart contract's state variables - the data it needs to keep track of and maintain. -These state variables come in two forms: public and private. Public variables are visible to anyone, and private variables remain hidden within the contract. +These state variables come in two forms: [public](./public_state.md) and [private](./private_state.md). Public variables are visible to anyone, and private variables remain hidden within the contract. A state variable with both public and private components is said to be [shared](./shared_state.md). Aztec.nr has a few abstractions to help define the type of data your contract holds. These include PrivateMutable, PrivateImmutable, PublicMutable, PrivateSet, and SharedImmutable. @@ -22,22 +22,32 @@ On this and the following pages in this section, you’ll learn: - Practical implications of Storage in real smart contracts In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. -## Public and private state variables +## The `Context` parameter -Public state variables can be read by anyone, while private state variables can only be read by their owner (or people whom the owner has shared the decrypted data or note viewing key with). +Aztec contracts have three different modes of execution: [private](../../../../aztec/aztec/glossary/call_types.md#private-execution), [public](../../../../aztec/aztec/glossary/call_types.md#public-execution) and [top-level unconstrained](../../../../aztec/aztec/glossary/call_types.md#top-level-unconstrained). How storage is accessed depends on the execution mode: for example, `PublicImmutable` can be read in all execution modes but only initialized in public, while `PrivateMutable` is entirely unavailable in public. -Public state follows the Ethereum style account model, where each contract has its own key-value datastore. Private state follows a UTXO model, where note contents (/aztec/aztec/concepts/state_model/index.md) and [private/public execution](/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md)) for more background. +Aztec.nr prevents developers from calling functions unavailable in the current execution mode via the `context` variable that is injected into all contract functions. Its type indicates the current execution mode: + - `&mut PrivateContext` for private execution + - `&mut PublicContext` for public execution + - `()` for unconstrained -## Storage struct +All state variables are generic over this `Context` type, and expose different methods in each execution mode. In the example above, `PublicImmutable`'s `initialize` function is only available with a public execution context, and so the following code results in a compilation error: ```rust #[aztec(storage)] -struct Storage { - // public state variables - // private state variables +struct Storage { + variable: PublicImmutable, +} + +#[aztec(private)] +fn some_private_function() { + storage.variable.initialize(0); + // ^ ERROR: Expected type PublicImmutable<_, &mut PublicContext>, found type PublicImmutable } ``` +This does mean however that the storage struct must be generic over a `Context` type parameter, which must in turn be passed to all state variables (`PublicImmutable`, `Map`, etc.). + ## Map A `map` is a state variable that "maps" a key to a value. It can be used with private or public storage variables. From 2d20947155a63253eabaf808676725391e66da24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 17 May 2024 13:21:19 +0000 Subject: [PATCH 06/15] Fix constants --- .../noir-protocol-circuits/crates/types/src/constants.nr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index f56791703d8..1799f1e176a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -104,12 +104,12 @@ global BLOB_SIZE_IN_BYTES: Field = 31 * 4096; global NESTED_CALL_L2_GAS_BUFFER = 20000; // CONTRACT CLASS CONSTANTS -global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u64 = 32; +global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u64 = 32000; // Bytecode size for private functions is per function, not for the entire contract. // Note that private functions bytecode includes a mix of acir and brillig. -global MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS: u64 = 30; +global MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS: u64 = 3000; // Same for unconstrained functions: the size is per function. -global MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS: u64 = 30; +global MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS: u64 = 3000; // How many fields are on the serialized ClassPrivateFunctionBroadcasted event in addition to MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS. global REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS: u64 = 19; // How many fields are on the serialized ClassUnconstrainedFunctionBroadcasted event in addition to MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS. From b447fded8280f8af46b31925873028f23495d31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 17 May 2024 17:38:22 +0000 Subject: [PATCH 07/15] Remove extra imports --- noir/noir-repo/aztec_macros/src/transforms/storage.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir/noir-repo/aztec_macros/src/transforms/storage.rs b/noir/noir-repo/aztec_macros/src/transforms/storage.rs index bd518a17ee3..447fb4d86c0 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/storage.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/storage.rs @@ -1,7 +1,7 @@ use noirc_errors::Span; use noirc_frontend::ast::{ BlockExpression, Expression, ExpressionKind, FunctionDefinition, Ident, Literal, NoirFunction, - NoirStruct, PathKind, Pattern, StatementKind, TypeImpl, UnresolvedType, UnresolvedTypeData, + NoirStruct, Pattern, StatementKind, TypeImpl, UnresolvedType, UnresolvedTypeData, }; use noirc_frontend::{ graph::CrateId, @@ -16,7 +16,7 @@ use noirc_frontend::{ }; use crate::{ - chained_dep, chained_path, + chained_path, utils::{ ast_utils::{ call, expression, ident, ident_path, is_custom_attribute, lambda, make_statement, From d9de995dfc11d3c6036ecdb51b05e17ad67eaf23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 17 May 2024 18:45:07 +0000 Subject: [PATCH 08/15] Fix merge --- .../aztec-nr/easy-private-state/src/easy_private_uint.nr | 1 + noir-projects/aztec-nr/value-note/src/utils.nr | 2 +- .../noir-contracts/contracts/card_game_contract/src/cards.nr | 4 ++-- .../contracts/docs_example_contract/src/main.nr | 4 +--- .../contracts/docs_example_contract/src/types/card_note.nr | 4 ++-- .../token_blacklist_contract/src/types/balances_map.nr | 5 ++--- .../contracts/token_contract/src/types/balances_map.nr | 3 +-- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr b/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr index d1a983116cd..e335ad0cfbc 100644 --- a/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr +++ b/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr @@ -1,4 +1,5 @@ use dep::aztec::{ + context::PrivateContext, protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}, note::note_getter_options::NoteGetterOptions, state_vars::PrivateSet, keys::getters::{get_npk_m_hash, get_ivpk_m} diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index 8b243cb52cf..ec31b8690ae 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -47,7 +47,7 @@ pub fn decrement_by_at_most( let options = create_note_getter_options_for_decreasing_balance(max_amount); let opt_notes = balance.get_notes(options); - let owner_npk_m_hash = get_npk_m_hash(balance.context.private.unwrap(), owner); + let owner_npk_m_hash = get_npk_m_hash(balance.context, owner); let mut decremented = 0; for i in 0..opt_notes.len() { diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index 9263b368a11..a14d62cdf4b 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -5,8 +5,8 @@ use dep::aztec::{ traits::{ToField, Serialize, FromField}, grumpkin_point::GrumpkinPoint, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL }, - keys::getters::{get_npk_m_hash, get_ivpk_m}, - note::note_getter::view_notes, state_vars::PrivateSet, note::constants::MAX_NOTES_PER_PAGE + keys::getters::{get_npk_m_hash, get_ivpk_m}, note::note_getter::view_notes, state_vars::PrivateSet, + note::constants::MAX_NOTES_PER_PAGE }; use dep::std; use dep::std::{option::Option}; diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index ad4b4efc816..d28accdfcba 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -18,9 +18,7 @@ contract DocsExample { PrivateContext, Map, PublicMutable, PublicImmutable, PrivateMutable, PrivateImmutable, PrivateSet, SharedImmutable, Deserialize }; - use dep::aztec::{ - note::note_getter_options::Comparator, keys::getters::{get_npk_m_hash, get_ivpk_m} - }; + use dep::aztec::{note::note_getter_options::Comparator, keys::getters::{get_npk_m_hash, get_ivpk_m}}; use dep::aztec::protocol_types::grumpkin_point::GrumpkinPoint; // how to import methods from other files/folders within your workspace use crate::options::create_account_card_getter_options; diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index f1c0f220664..58a467a6613 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -3,8 +3,8 @@ use dep::aztec::{ keys::getters::get_ivpk_m, note::{utils::compute_note_hash_for_consumption}, oracle::nullifier_keys::get_nsk_app, protocol_types::{ - traits::Empty, grumpkin_point::GrumpkinPoint, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash + traits::{Empty, Serialize}, grumpkin_point::GrumpkinPoint, + constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash } }; diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index 0eb946fcdb6..dd9c3acf344 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -3,8 +3,7 @@ use dep::aztec::prelude::{ PrivateSet, Map }; use dep::aztec::{ - context::PrivateContext, hash::pedersen_hash, - protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, + hash::pedersen_hash, protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, note::{note_getter::view_notes, note_getter_options::SortOrder}, keys::getters::{get_npk_m_hash, get_ivpk_m} }; @@ -65,7 +64,7 @@ impl BalancesMap { owner: AztecAddress, addend: U128 ) where T: NoteInterface + OwnedNote { - let context = self.map.context.private.unwrap(); + let context = self.map.context; let owner_ivpk_m = get_ivpk_m(context, owner); // We fetch the nullifier public key hash from the registry / from our PXE diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr index 670c0deeb8d..5f45d7279dc 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr @@ -3,8 +3,7 @@ use dep::aztec::prelude::{ PrivateSet, Map }; use dep::aztec::{ - context::PrivateContext, hash::pedersen_hash, - protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, + hash::pedersen_hash, protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, note::{note_getter::view_notes, note_getter_options::SortOrder}, keys::getters::{get_npk_m_hash, get_ivpk_m} }; From b8583b81dafe75989b724fa9318c1ee95c098f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 17 May 2024 15:46:35 -0300 Subject: [PATCH 09/15] Apply suggestions from code review Co-authored-by: esau <152162806+sklppy88@users.noreply.github.com> --- docs/docs/aztec/aztec/glossary/call_types.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/aztec/aztec/glossary/call_types.md b/docs/docs/aztec/aztec/glossary/call_types.md index ba8e4d6a67e..073b6ea95ca 100644 --- a/docs/docs/aztec/aztec/glossary/call_types.md +++ b/docs/docs/aztec/aztec/glossary/call_types.md @@ -142,9 +142,9 @@ This is the same function that was called by privately enqueuing a call to it! P Contract functions with the `unconstrained` Noir keyword are a special type of function still under development, and their semantics will likely change in the near future. They are used to perform state queries from an off-chain client (from both private and public state!), and are never included in any transaction. No guarantees are made on the correctness of the result since the entire execution is unconstrained and heavily reliant on oracle calls. -Any programming language could be used to construct these queries, since all they do is perform arbitrary computation on data that is either publicly available from any node, or locally available from PXE. Top-level unconstrained functions exist because they let developers the rest of the contract code directly by being part of the same Noir contract, as opposed to having to rely on e.g. manual computation of storage slots, struct layout and padding, etc. +Any programming language could be used to construct these queries, since all they do is perform arbitrary computation on data that is either publicly available from any node, or locally available from the PXE. Top-level unconstrained functions exist because they let developers the rest of the contract code directly by being part of the same Noir contract, as opposed to having to rely on e.g. manual computation of storage slots, struct layout and padding, etc. -A reasonable mental model for them is that of a `view` Solidity function that can never called in any transaction, and is only ever invoked via `eth_call`. Note that in these the caller assumes that the node is acting honestly by exectuing the true contract bytecode with correct blockchain state, the same way the Aztec version assumes the oracles are returning legitimate data. +A reasonable mental model for them is that of a Solidity `view` function that can never be called in any transaction, and is only ever invoked via `eth_call`. Note that in these the caller assumes that the node is acting honestly by executing the true contract bytecode with correct blockchain state, the same way the Aztec version assumes the oracles are returning legitimate data. ### aztec.js From fbd8edbcc5f303556de40b4925a2ed3140799382 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 20 May 2024 09:39:44 +0000 Subject: [PATCH 10/15] prototype --- .../contracts/counter_contract/src/main.nr | 4 +- .../src/types/card_note.nr | 2 +- .../contracts/fpc_contract/src/main.nr | 6 +-- noir/noir-repo/aztec_macros/src/lib.rs | 3 +- .../aztec_macros/src/transforms/storage.rs | 51 +++++++++++++++++++ .../aztec_macros/src/utils/errors.rs | 6 +++ 6 files changed, 65 insertions(+), 7 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 58a9260cbae..73c4cd0d3b4 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -7,8 +7,8 @@ contract Counter { // docs:start:storage_struct #[aztec(storage)] - struct Storage { - counters: Map, Context>, + struct Storage { + counters: Map, } // docs:end:storage_struct diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 58a467a6613..cbede22c41f 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -63,6 +63,6 @@ impl NoteInterface for CardNote { impl Serialize<3> for CardNote { fn serialize(self) -> [Field; 3] { - [ self.points.to_field(), self.randomness, self.owner.to_field() ] + [ self.points.to_field(), self.randomness, self.npk_m_hash.to_field() ] } } diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 68aad561926..d6c808c17f1 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -6,9 +6,9 @@ contract FPC { use dep::aztec::context::gas::GasOpts; #[aztec(storage)] - struct Storage { - other_asset: SharedImmutable, - gas_token_address: SharedImmutable, + struct Storage { + other_asset: SharedImmutable, + gas_token_address: SharedImmutable, } #[aztec(public)] diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 5f0326bea5a..850d8d1dae7 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -13,7 +13,7 @@ use transforms::{ note_interface::{generate_note_interface_impl, inject_note_exports}, storage::{ assign_storage_slots, check_for_storage_definition, check_for_storage_implementation, - generate_storage_implementation, generate_storage_layout, + generate_storage_implementation, generate_storage_layout, inject_context_in_storage, }, }; @@ -99,6 +99,7 @@ fn transform_module( let storage_defined = maybe_storage_struct_name.is_some(); if let Some(ref storage_struct_name) = maybe_storage_struct_name { + inject_context_in_storage(module)?; if !check_for_storage_implementation(module, storage_struct_name) { generate_storage_implementation(module, storage_struct_name)?; } diff --git a/noir/noir-repo/aztec_macros/src/transforms/storage.rs b/noir/noir-repo/aztec_macros/src/transforms/storage.rs index 447fb4d86c0..0a210934827 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/storage.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/storage.rs @@ -48,6 +48,57 @@ pub fn check_for_storage_definition( Ok(result.iter().map(|&r#struct| r#struct.name.0.contents.clone()).next()) } +// Injects the Context generic in each of the Storage struct fields to avoid boilerplate, +// taking maps into account (including nested maps) +fn inject_context_in_storage_field(field: &mut UnresolvedType) -> Result<(), AztecMacroError> { + match &mut field.typ { + UnresolvedTypeData::Named(path, generics, _) => { + generics.push(make_type(UnresolvedTypeData::Named( + ident_path("Context"), + vec![], + false, + ))); + match path.segments.last().unwrap().0.contents.as_str() { + "Map" => inject_context_in_storage_field(&mut generics[1]), + _ => Ok(()), + } + } + _ => Err(AztecMacroError::CouldNotInjectContextGenericInStorage { + secondary_message: Some(format!("Unsupported type: {:?}", field.typ)), + }), + } +} + +// Injects the Context generic in the storage struct to avoid boilerplate +// Transforms this: +// struct Storage { +// a_var: SomeStoragePrimitive, +// a_map: Map>, +// } +// +// Into this: +// +// struct Storage { +// a_var: SomeStoragePrimitive, +// a_map: Map, Context>, +// } +pub fn inject_context_in_storage(module: &mut SortedModule) -> Result<(), AztecMacroError> { + let storage_struct = module + .types + .iter_mut() + .find(|r#struct| { + r#struct.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(storage)")) + }) + .unwrap(); + storage_struct.generics.push(ident("Context")); + storage_struct + .fields + .iter_mut() + .map(|(_, field)| inject_context_in_storage_field(field)) + .collect::, _>>()?; + Ok(()) +} + // Check to see if the user has defined an impl for the storage struct pub fn check_for_storage_implementation( module: &SortedModule, diff --git a/noir/noir-repo/aztec_macros/src/utils/errors.rs b/noir/noir-repo/aztec_macros/src/utils/errors.rs index 8d1a19bfea9..51aea3d052f 100644 --- a/noir/noir-repo/aztec_macros/src/utils/errors.rs +++ b/noir/noir-repo/aztec_macros/src/utils/errors.rs @@ -16,6 +16,7 @@ pub enum AztecMacroError { CouldNotImplementNoteInterface { span: Option, secondary_message: Option }, MultipleStorageDefinitions { span: Option }, CouldNotExportStorageLayout { span: Option, secondary_message: Option }, + CouldNotInjectContextGenericInStorage { secondary_message: Option }, CouldNotExportFunctionAbi { span: Option, secondary_message: Option }, CouldNotGenerateContractInterface { secondary_message: Option }, EventError { span: Span, message: String }, @@ -76,6 +77,11 @@ impl From for MacroError { secondary_message, span, }, + AztecMacroError::CouldNotInjectContextGenericInStorage { secondary_message } => MacroError { + primary_message: "Could not inject context generic in storage".to_string(), + secondary_message, + span: None + }, AztecMacroError::CouldNotExportFunctionAbi { secondary_message, span } => MacroError { primary_message: "Could not generate and export function abi".to_string(), secondary_message, From e189d8f3e45e2facc9d74cd80ae5d15a08051a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 20 May 2024 17:59:34 +0000 Subject: [PATCH 11/15] Clarify why top level unconstrained --- docs/docs/aztec/aztec/glossary/call_types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/aztec/aztec/glossary/call_types.md b/docs/docs/aztec/aztec/glossary/call_types.md index 073b6ea95ca..c2918f2e944 100644 --- a/docs/docs/aztec/aztec/glossary/call_types.md +++ b/docs/docs/aztec/aztec/glossary/call_types.md @@ -142,7 +142,7 @@ This is the same function that was called by privately enqueuing a call to it! P Contract functions with the `unconstrained` Noir keyword are a special type of function still under development, and their semantics will likely change in the near future. They are used to perform state queries from an off-chain client (from both private and public state!), and are never included in any transaction. No guarantees are made on the correctness of the result since the entire execution is unconstrained and heavily reliant on oracle calls. -Any programming language could be used to construct these queries, since all they do is perform arbitrary computation on data that is either publicly available from any node, or locally available from the PXE. Top-level unconstrained functions exist because they let developers the rest of the contract code directly by being part of the same Noir contract, as opposed to having to rely on e.g. manual computation of storage slots, struct layout and padding, etc. +Any programming language could be used to construct these queries, since all they do is perform arbitrary computation on data that is either publicly available from any node, or locally available from the PXE. Top-level unconstrained functions exist because they let developers utilize the rest of the contract code directly by being part of the same Noir contract, and e.g. use the same libraries, structs, etc. instead of having to rely on manual computation of storage slots, struct layout and padding, and so on. A reasonable mental model for them is that of a Solidity `view` function that can never be called in any transaction, and is only ever invoked via `eth_call`. Note that in these the caller assumes that the node is acting honestly by executing the true contract bytecode with correct blockchain state, the same way the Aztec version assumes the oracles are returning legitimate data. From fe8610d8f6183e1a8a6e34e6465e4f468a29c3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 21 May 2024 13:12:02 +0000 Subject: [PATCH 12/15] Update docs --- .../common_patterns/index.md | 5 +- .../writing_contracts/storage/index.md | 2 +- docs/docs/migration_notes.md | 107 +++++++++--------- .../sandbox_reference/cheat_codes.md | 12 +- .../smart_contract_reference/storage/index.md | 6 +- .../app_subscription_contract/src/main.nr | 16 +-- .../contracts/auth_contract/src/main.nr | 6 +- .../avm_initializer_test_contract/src/main.nr | 4 +- .../src/main.nr | 4 +- .../contracts/avm_test_contract/src/main.nr | 8 +- .../benchmarking_contract/src/main.nr | 6 +- .../contracts/card_game_contract/src/main.nr | 8 +- .../contracts/child_contract/src/main.nr | 6 +- .../contracts/claim_contract/src/main.nr | 6 +- .../crowdfunding_contract/src/main.nr | 10 +- .../delegated_on_contract/src/main.nr | 6 +- .../contracts/delegator_contract/src/main.nr | 6 +- .../docs_example_contract/src/main.nr | 18 +-- .../easy_private_token_contract/src/main.nr | 4 +- .../easy_private_voting_contract/src/main.nr | 8 +- .../ecdsa_account_contract/src/main.nr | 4 +- .../contracts/escrow_contract/src/main.nr | 4 +- .../contracts/gas_token_contract/src/main.nr | 6 +- .../inclusion_proofs_contract/src/main.nr | 8 +- .../key_registry_contract/src/main.nr | 18 +-- .../contracts/lending_contract/src/main.nr | 12 +- .../pending_note_hashes_contract/src/main.nr | 4 +- .../contracts/price_feed_contract/src/main.nr | 4 +- .../schnorr_account_contract/src/main.nr | 6 +- .../stateful_test_contract/src/main.nr | 6 +- .../static_child_contract/src/main.nr | 3 +- .../contracts/test_contract/src/main.nr | 6 +- .../token_blacklist_contract/src/main.nr | 12 +- .../token_bridge_contract/src/main.nr | 6 +- .../contracts/token_contract/src/main.nr | 20 ++-- .../contracts/uniswap_contract/src/main.nr | 8 +- 36 files changed, 185 insertions(+), 190 deletions(-) diff --git a/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/index.md b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/index.md index af345218325..d0d139c38e2 100644 --- a/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/index.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/index.md @@ -45,8 +45,9 @@ You can't read public storage in private domain. But nevertheless reading public 1. You pass the data as a parameter to your private method and later assert in public that the data is correct. E.g.: ```rust -struct Storage { - token: PublicMutable, +#[aztec(storage)] +struct Storage { + token: PublicMutable, } contract Bridge { diff --git a/docs/docs/guides/smart_contracts/writing_contracts/storage/index.md b/docs/docs/guides/smart_contracts/writing_contracts/storage/index.md index e589c660e58..7198612356d 100644 --- a/docs/docs/guides/smart_contracts/writing_contracts/storage/index.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/storage/index.md @@ -10,7 +10,7 @@ To learn more about how storage works in Aztec, read [the concepts](/guides/smar ```rust #[aztec(storage)] -struct Storage { +struct Storage { // public state variables // private state variables } diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index 65f918a0f84..663c9640eeb 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -8,6 +8,57 @@ Aztec is in full-speed development. Literally every version breaks compatibility ## 0.X.X + + +### [Aztec.nr] State variable rework + +Aztec.nr state variables have been reworked so that calling private functions in public and vice versa is detected as an error during compilation instead of at runtime. This affects users in a number of ways: + +#### New compile time errors + +It used to be that calling a state variable method only available in public from a private function resulted in obscure runtime errors in the form of a failed `_is_some` assertion. + +Incorrect usage of the state variable methods now results in compile time errors. For example, given the following function: + +```rust +#[aztec(public)] +fn get_decimals() -> pub u8 { + storage.decimals.read_private() +} +``` + +The compiler will now error out with +``` +Expected type SharedImmutable<_, &mut PrivateContext>, found type SharedImmutable +``` + +The key component is the second generic parameter: the compiler expects a `PrivateContext` (becuse `read_private` is only available during private execution), but a `PublicContext` is being used instead (because of the `#[aztec(public)]` attribute). + +#### Generic parameters in `Storage` + +The `Storage` struct (the one marked with `#[aztec(storage)]`) should now be generic over a `Context` type, which matches the new generic parameter of all Aztec.nr libraries. This parameter is always the last generic parameter. + +This means that, without any additional features, we'd end up with some extra boilerplate when declaring this struct: + +```diff +#[aztec(storage)] +- struct Storage { ++ struct Storage { +- nonce_for_burn_approval: PublicMutable, ++ nonce_for_burn_approval: PublicMutable, +- portal_address: SharedImmutable, ++ portal_address: SharedImmutable, +- approved_action: Map>, ++ approved_action: Map, Context>, +} +``` + +Because of this, the `#[aztec(storage)]` macro has been updated to **automatically inject** this `Context` generic parameter. The storage declaration does not require any changes. + +#### Removal of `Context` + +The `Context` type no longer exists. End users typically didn't use it, but if imported it needs to be deleted. + ### [Aztec.nr] View functions and interface navigation It is now possible to explicitly state a function doesn't perform any state alterations (including storage, logs, nullifiers and/or messages from L2 to L1) with the `#[aztec(view)]` attribute, similarly to solidity's `view` function modifier. @@ -72,62 +123,6 @@ The function `debug_log_array_with_prefix` has been removed. Use `debug_log_form ## 0.39.0 -### [Aztec.nr] State variable rework - -Aztec.nr state variables have been reworked so that calling private functions in public and vice versa is detected as an error during compilation instead of at runtime. This affects users in a number of ways: - -#### New compile time errors - -It used to be that calling a state variable method only available in public from a private function resulted in obscure runtime errors in the form of a failed `_is_some` assertion. - -Incorrect usage of the state variable methods now results in compile time errors. For example, given the following function: - -```rust -#[aztec(public)] -fn get_decimals() -> pub u8 { - storage.decimals.read_private() -} -``` - -The compiler will now error out with -``` -Expected type SharedImmutable<_, &mut PrivateContext>, found type SharedImmutable -``` - -The key component is the second generic parameter: the compiler expects a `PrivateContext` (becuse `read_private` is only available during private execution), but a `PublicContext` is being used instead (because of the `#[aztec(public)]` attribute). - -#### Generic parameters in `Storage` - -The `Storage` struct (the one marked with `#[aztec(storage)]`) should now be generic over a `Context` type, which matches the new generic parameter of all Aztec.nr libraries. This parameter is always the last generic parameter. - -This means that there's now slightly more boilerplate when declaring this struct: - -```diff -#[aztec(storage)] -- struct Storage { -+ struct Storage { -- nonce_for_burn_approval: PublicMutable, -+ nonce_for_burn_approval: PublicMutable, -- portal_address: SharedImmutable, -+ portal_address: SharedImmutable, -- approved_action: Map>, -+ approved_action: Map, Context>, -} -``` - -Note that `Map` also has a generic `Context` parameter, so for each `Map` an extra `Context` must be added: - -```diff -- game_decks: Map>, -+ game_decks: Map, Context>, Context>, -``` - -This is an unfortunate side-effect, and we're looking into ways to improve this. - -#### Removal of `Context` - -The `Context` type no longer exists. End users typically didn't use it, but if imported it needs to be deleted. - ### [Aztec.nr] Mutable delays in `SharedMutable` The type signature for `SharedMutable` changed from `SharedMutable` to `SharedMutable`. The behavior is the same as before, except the delay can now be changed after deployment by calling `schedule_delay_change`. diff --git a/docs/docs/reference/sandbox_reference/cheat_codes.md b/docs/docs/reference/sandbox_reference/cheat_codes.md index 4c78e3c7200..00c408bda8d 100644 --- a/docs/docs/reference/sandbox_reference/cheat_codes.md +++ b/docs/docs/reference/sandbox_reference/cheat_codes.md @@ -463,8 +463,8 @@ The baseSlot is specified in the Aztec.nr contract. ```rust #[aztec(storage)] -struct Storage { - balances: Map, Context>, +struct Storage { + balances: Map>, } contract Token { @@ -494,8 +494,8 @@ Note: One Field element occupies a storage slot. Hence, structs with multiple fi ```rust #[aztec(storage)] -struct Storage { - balances: Map, Context>, +struct Storage { + balances: Map>, } contract Token { @@ -526,9 +526,9 @@ Note: One Field element occupies a storage slot. Hence, structs with multiple fi #### Example ```rust #[aztec(storage)] -struct Storage { +struct Storage { ... - pending_shields: PrivateSet, + pending_shields: PrivateSet, } contract Token { diff --git a/docs/docs/reference/smart_contract_reference/storage/index.md b/docs/docs/reference/smart_contract_reference/storage/index.md index 269547c7790..84cfe9d919b 100644 --- a/docs/docs/reference/smart_contract_reference/storage/index.md +++ b/docs/docs/reference/smart_contract_reference/storage/index.md @@ -35,8 +35,8 @@ All state variables are generic over this `Context` type, and expose different m ```rust #[aztec(storage)] -struct Storage { - variable: PublicImmutable, +struct Storage { + variable: PublicImmutable, } #[aztec(private)] @@ -46,7 +46,7 @@ fn some_private_function() { } ``` -This does mean however that the storage struct must be generic over a `Context` type parameter, which must in turn be passed to all state variables (`PublicImmutable`, `Map`, etc.). +The `Context` generic type parameter is not visible in the code above as it is automatically injected by the `#[aztec(storage)]` macro, in order to reduce boilerplate. Similarly, all state variables in that struct (e.g. `PublicImmutable`) similarly have that same type parameter automatically passed to them. ## Map diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 16910d14b1b..bdb0d902c17 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -17,17 +17,17 @@ contract AppSubscription { }; #[aztec(storage)] - struct Storage { + struct Storage { // The following is only needed in private but we use ShareImmutable here instead of PrivateImmutable because // the value can be publicly known and SharedImmutable provides us with a better devex here because we don't // have to bother with sharing the note between pixies of users. - target_address: SharedImmutable, - subscription_token_address: SharedImmutable, - subscription_recipient_address: SharedImmutable, - subscription_price: SharedImmutable, - subscriptions: Map, Context>, - gas_token_address: SharedImmutable, - gas_token_limit_per_tx: SharedImmutable, + target_address: SharedImmutable, + subscription_token_address: SharedImmutable, + subscription_recipient_address: SharedImmutable, + subscription_price: SharedImmutable, + subscriptions: Map>, + gas_token_address: SharedImmutable, + gas_token_limit_per_tx: SharedImmutable, } global SUBSCRIPTION_DURATION_IN_BLOCKS = 5; diff --git a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr index 1abd0ca1ccc..deb5e34315e 100644 --- a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr @@ -8,11 +8,11 @@ contract Auth { global CHANGE_AUTHORIZED_DELAY_BLOCKS = 5; #[aztec(storage)] - struct Storage { + struct Storage { // Admin can change the value of the authorized address via set_authorized() - admin: PublicImmutable, + admin: PublicImmutable, // docs:start:shared_mutable_storage - authorized: SharedMutable, + authorized: SharedMutable, // docs:end:shared_mutable_storage } diff --git a/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr index 96217d55661..a71cf2a1de4 100644 --- a/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr @@ -4,8 +4,8 @@ contract AvmInitializerTest { use dep::aztec::protocol_types::address::AztecAddress; #[aztec(storage)] - struct Storage { - immutable: PublicImmutable, + struct Storage { + immutable: PublicImmutable, } /************************************************************************ diff --git a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr index 8f0a471c9f0..a62fc79b5ec 100644 --- a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr @@ -9,8 +9,8 @@ contract AvmNestedCallsTest { use dep::aztec::protocol_types::abis::function_selector::FunctionSelector; #[aztec(storage)] - struct Storage { - single: PublicMutable, + struct Storage { + single: PublicMutable, } /************************************************************************ diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 133285a5a4b..36873f06d8b 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -33,10 +33,10 @@ contract AvmTest { use dep::compressed_string::CompressedString; #[aztec(storage)] - struct Storage { - single: PublicMutable, - list: PublicMutable, - map: Map, Context>, + struct Storage { + single: PublicMutable, + list: PublicMutable, + map: Map>, } /************************************************************************ diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr index 9edd181e293..8d79d608ff0 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -10,9 +10,9 @@ contract Benchmarking { use dep::aztec::context::gas::GasOpts; #[aztec(storage)] - struct Storage { - notes: Map, Context>, - balances: Map, Context>, + struct Storage { + notes: Map>, + balances: Map>, } // Creates a new value note for the target owner. Use this method to seed an initial set of notes. diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr index 4ccf50c335e..53ab64848df 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr @@ -13,10 +13,10 @@ contract CardGame { use crate::game::{NUMBER_OF_PLAYERS, NUMBER_OF_CARDS_DECK, PLAYABLE_CARDS, PlayerEntry, Game, GAME_SERIALIZED_LEN}; #[aztec(storage)] - struct Storage { - collections: Map, Context>, - game_decks: Map, Context>, Context>, - games: Map, Context>, + struct Storage { + collections: Map, + game_decks: Map>, + games: Map>, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 01870d6eb7f..fbcf4fb9956 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -11,9 +11,9 @@ contract Child { use dep::value_note::value_note::ValueNote; #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_private_value: PrivateSet, + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, } // Returns a sum of the input and the chain id and version of the contract in private circuit public input's return_values. diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index ca9433a5fe1..72f80b872a4 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -8,11 +8,11 @@ contract Claim { use dep::token::Token; #[aztec(storage)] - struct Storage { + struct Storage { // Address of a contract based on whose notes we distribute the rewards - target_contract: SharedImmutable, + target_contract: SharedImmutable, // Token to be distributed as a reward when claiming - reward_token: SharedImmutable, + reward_token: SharedImmutable, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index 2bbe086fca0..88bc4a0c54b 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -29,15 +29,15 @@ contract Crowdfunding { // docs:start:storage #[aztec(storage)] - struct Storage { + struct Storage { // Token used for donations (e.g. DAI) - donation_token: SharedImmutable, + donation_token: SharedImmutable, // Crowdfunding campaign operator - operator: SharedImmutable, + operator: SharedImmutable, // End of the crowdfunding campaign after which no more donations are accepted - deadline: PublicImmutable, + deadline: PublicImmutable, // Notes emitted to donors when they donate (can be used as proof to obtain rewards, eg in Claim contracts) - donation_receipts: PrivateSet, + donation_receipts: PrivateSet, } // docs:end:storage diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr index 6969786a9df..f38d4bff58c 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr @@ -8,9 +8,9 @@ contract DelegatedOn { use dep::value_note::value_note::ValueNote; #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_private_value: PrivateSet, + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index ab712871da8..023974cd81f 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -6,9 +6,9 @@ contract Delegator { use dep::delegated_on::DelegatedOn; #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_private_value: PrivateSet, + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index cd3f36858cf..267c6affff9 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -25,30 +25,30 @@ contract DocsExample { use crate::types::{card_note::{CardNote, CARD_NOTE_LEN}, leader::Leader}; #[aztec(storage)] - struct Storage { + struct Storage { // Shows how to create a custom struct in PublicMutable // docs:start:storage-leader-declaration - leader: PublicMutable, + leader: PublicMutable, // docs:end:storage-leader-declaration // docs:start:storage-private-mutable-declaration - legendary_card: PrivateMutable, + legendary_card: PrivateMutable, // docs:end:storage-private-mutable-declaration // just used for docs example to show how to create a private mutable map. - profiles: Map, Context>, + profiles: Map>, // docs:start:storage-set-declaration - set: PrivateSet, + set: PrivateSet, // docs:end:storage-set-declaration // docs:start:storage-private-immutable-declaration - private_immutable: PrivateImmutable, + private_immutable: PrivateImmutable, // docs:end:storage-private-immutable-declaration // docs:start:storage-shared-immutable-declaration - shared_immutable: SharedImmutable, + shared_immutable: SharedImmutable, // docs:end:storage-shared-immutable-declaration // docs:start:storage-minters-declaration - minters: Map, Context>, + minters: Map>, // docs:end:storage-minters-declaration // docs:start:storage-public-immutable-declaration - public_immutable: PublicImmutable, + public_immutable: PublicImmutable, // docs:end:storage-public-immutable-declaration } diff --git a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr index 879a229ad3c..1b5af4b8280 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr @@ -5,8 +5,8 @@ contract EasyPrivateToken { use dep::easy_private_state::EasyPrivateUint; #[aztec(storage)] - struct Storage { - balances: Map, Context>, + struct Storage { + balances: Map, } /** diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 4de227cd77d..bb19fa9505e 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -8,10 +8,10 @@ contract EasyPrivateVoting { // docs:end:imports // docs:start:storage_struct #[aztec(storage)] - struct Storage { - admin: PublicMutable, // admin can end vote - tally: Map, Context>, // we will store candidate as key and number of votes as value - vote_ended: PublicMutable, // vote_ended is boolean + struct Storage { + admin: PublicMutable, // admin can end vote + tally: Map>, // we will store candidate as key and number of votes as value + vote_ended: PublicMutable, // vote_ended is boolean } // docs:end:storage_struct diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index 4fef4aeac60..08400e06169 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -17,8 +17,8 @@ contract EcdsaAccount { use crate::ecdsa_public_key_note::EcdsaPublicKeyNote; #[aztec(storage)] - struct Storage { - public_key: PrivateImmutable, + struct Storage { + public_key: PrivateImmutable, } global ACCOUNT_ACTIONS_STORAGE_SLOT = 2; diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index 0c766b5f450..550b32e09c1 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -9,8 +9,8 @@ contract Escrow { use dep::token::Token; #[aztec(storage)] - struct Storage { - owner: PrivateImmutable, + struct Storage { + owner: PrivateImmutable, } // Creates a new instance diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr index 15dff3f57b5..0e3c422707c 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr @@ -7,9 +7,9 @@ contract GasToken { use crate::lib::{calculate_fee, get_bridge_gas_msg_hash}; #[aztec(storage)] - struct Storage { - balances: Map, Context>, - portal_address: SharedImmutable, + struct Storage { + balances: Map>, + portal_address: SharedImmutable, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 608f03af7b8..d3fbbcf4b16 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -27,10 +27,10 @@ contract InclusionProofs { use dep::value_note::value_note::ValueNote; // docs:end:value_note_imports #[aztec(storage)] - struct Storage { - private_values: Map, Context>, - public_value: PublicMutable, - public_unused_value: PublicMutable, + struct Storage { + private_values: Map>, + public_value: PublicMutable, + public_unused_value: PublicMutable, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr index 907f6de0ef5..ec88658c95d 100644 --- a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr @@ -9,21 +9,21 @@ contract KeyRegistry { global KEY_ROTATION_DELAY = 5; #[aztec(storage)] - struct Storage { + struct Storage { // The following stores a hash of individual master public keys // If you change slots of vars below, you must update the slots in `SharedMutablePrivateGetter` in aztec-nr/keys. // We store x and y coordinates in individual shared mutables as shared mutable currently supports only 1 field - npk_m_x_registry: Map, Context>, - npk_m_y_registry: Map, Context>, + npk_m_x_registry: Map>, + npk_m_y_registry: Map>, - ivpk_m_x_registry: Map, Context>, - ivpk_m_y_registry: Map, Context>, + ivpk_m_x_registry: Map>, + ivpk_m_y_registry: Map>, - ovpk_m_x_registry: Map, Context>, - ovpk_m_y_registry: Map, Context>, + ovpk_m_x_registry: Map>, + ovpk_m_y_registry: Map>, - tpk_m_x_registry: Map, Context>, - tpk_m_y_registry: Map, Context>, + tpk_m_x_registry: Map>, + tpk_m_y_registry: Map>, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index fb3ccde29d9..79314a807e8 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -21,12 +21,12 @@ contract Lending { // Storage structure, containing all storage, and specifying what slots they use. #[aztec(storage)] - struct Storage { - collateral_asset: PublicMutable, - stable_coin: PublicMutable, - assets: Map, Context>, - collateral: Map, Context>, - static_debt: Map, Context>, // abusing keys very heavily + struct Storage { + collateral_asset: PublicMutable, + stable_coin: PublicMutable, + assets: Map>, + collateral: Map>, + static_debt: Map>, // abusing keys very heavily } struct Position { diff --git a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr index d9344027a8e..a21c94fa79e 100644 --- a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr @@ -10,8 +10,8 @@ contract PendingNoteHashes { use dep::aztec::protocol_types::grumpkin_point::GrumpkinPoint; #[aztec(storage)] - struct Storage { - balances: Map, Context>, + struct Storage { + balances: Map>, } // TODO(dbanks12): consolidate code into internal helper functions diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index 0425b730b0f..5b0c32b4ac7 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -6,8 +6,8 @@ contract PriceFeed { // Storage structure, containing all storage, and specifying what slots they use. #[aztec(storage)] - struct Storage { - assets: Map, Context>, + struct Storage { + assets: Map>, } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 97c4887bc78..c2b687b5311 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -18,11 +18,11 @@ contract SchnorrAccount { use crate::public_key_note::{PublicKeyNote, PUBLIC_KEY_NOTE_LEN}; #[aztec(storage)] - struct Storage { + struct Storage { // docs:start:storage - signing_public_key: PrivateImmutable, + signing_public_key: PrivateImmutable, // docs:end:storage - approved_actions: Map, Context>, + approved_actions: Map>, } // Constructs the contract diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index f93e5d0c716..41756a48401 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -8,9 +8,9 @@ contract StatefulTest { }; #[aztec(storage)] - struct Storage { - notes: Map, Context>, - public_values: Map, Context>, + struct Storage { + notes: Map>, + public_values: Map>, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr index f6f7b7e79c7..9a8431fb252 100644 --- a/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr @@ -3,8 +3,7 @@ contract StaticChild { use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize}; use dep::aztec::{ - context::{PublicContext, Context, gas::GasOpts}, - protocol_types::{abis::{call_context::CallContext}}, + context::{PublicContext, gas::GasOpts}, protocol_types::{abis::{call_context::CallContext}}, note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, keys::getters::{get_npk_m_hash, get_ivpk_m} }; diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 4570b2bb051..e5a5d759950 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -45,9 +45,9 @@ contract Test { } #[aztec(storage)] - struct Storage { - example_constant: PrivateImmutable, - example_set: PrivateSet, + struct Storage { + example_constant: PrivateImmutable, + example_set: PrivateSet, } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 0186b4528e5..f2e54e26133 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -23,12 +23,12 @@ contract TokenBlacklist { global CHANGE_ROLES_DELAY_BLOCKS = 2; #[aztec(storage)] - struct Storage { - balances: BalancesMap, - total_supply: PublicMutable, - pending_shields: PrivateSet, - public_balances: Map, Context>, - roles: Map, Context>, + struct Storage { + balances: BalancesMap, + total_supply: PublicMutable, + pending_shields: PrivateSet, + public_balances: Map>, + roles: Map>, } // docs:start:constructor diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index bb7085a2ebe..e503e3f691a 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -16,9 +16,9 @@ contract TokenBridge { // docs:start:token_bridge_storage_and_constructor // Storage structure, containing all storage, and specifying what slots they use. #[aztec(storage)] - struct Storage { - token: PublicMutable, - portal_address: SharedImmutable, + struct Storage { + token: PublicMutable, + portal_address: SharedImmutable, } // Constructs the contract. diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 266118c8488..d84d4c218b3 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -28,25 +28,25 @@ contract Token { // docs:start:storage_struct #[aztec(storage)] - struct Storage { + struct Storage { // docs:start:storage_admin - admin: PublicMutable, + admin: PublicMutable, // docs:end:storage_admin // docs:start:storage_minters - minters: Map, Context>, + minters: Map>, // docs:end:storage_minters // docs:start:storage_balances - balances: BalancesMap, + balances: BalancesMap, // docs:end:storage_balances - total_supply: PublicMutable, + total_supply: PublicMutable, // docs:start:storage_pending_shields - pending_shields: PrivateSet, + pending_shields: PrivateSet, // docs:end:storage_pending_shields - public_balances: Map, Context>, - symbol: SharedImmutable, - name: SharedImmutable, + public_balances: Map>, + symbol: SharedImmutable, + name: SharedImmutable, // docs:start:storage_decimals - decimals: SharedImmutable, + decimals: SharedImmutable, // docs:end:storage_decimals } // docs:end:storage_struct diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr index eaf1cce0317..0ccd4b5a74b 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -18,13 +18,13 @@ contract Uniswap { use crate::util::{compute_swap_private_content_hash, compute_swap_public_content_hash}; #[aztec(storage)] - struct Storage { + struct Storage { // like with account contracts, stores the approval message on a slot and tracks if they are active - approved_action: Map, Context>, + approved_action: Map>, // tracks the nonce used to create the approval message for burning funds // gets incremented each time after use to prevent replay attacks - nonce_for_burn_approval: PublicMutable, - portal_address: SharedImmutable, + nonce_for_burn_approval: PublicMutable, + portal_address: SharedImmutable, } // docs:end:uniswap_setup From 9235f36af5672f1ab4bc80db98f8a90b2d65c7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 21 May 2024 13:15:43 +0000 Subject: [PATCH 13/15] Apply nargo fmt --- noir-projects/aztec-nr/authwit/src/account.nr | 2 +- noir-projects/aztec-nr/authwit/src/auth.nr | 5 +---- .../aztec/src/state_vars/private_set.nr | 8 +------- .../src/easy_private_uint.nr | 3 +-- noir-projects/aztec-nr/value-note/src/utils.nr | 18 +++++++++++++++--- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/noir-projects/aztec-nr/authwit/src/account.nr b/noir-projects/aztec-nr/authwit/src/account.nr index 766a467c55e..33b519c7424 100644 --- a/noir-projects/aztec-nr/authwit/src/account.nr +++ b/noir-projects/aztec-nr/authwit/src/account.nr @@ -90,4 +90,4 @@ impl AccountActions<&mut PublicContext> { self.approved_action.at(message_hash).write(true); } // docs:end:approve_public_authwit -} \ No newline at end of file +} diff --git a/noir-projects/aztec-nr/authwit/src/auth.nr b/noir-projects/aztec-nr/authwit/src/auth.nr index 49aa118622a..fa30e94a3fc 100644 --- a/noir-projects/aztec-nr/authwit/src/auth.nr +++ b/noir-projects/aztec-nr/authwit/src/auth.nr @@ -4,10 +4,7 @@ use dep::aztec::protocol_types::{ }; use dep::aztec::{ prelude::Deserialize, - context::{ - PrivateContext, PublicContext, gas::GasOpts, - interface::{ContextInterface, PublicContextInterface} -}, + context::{PrivateContext, PublicContext, gas::GasOpts, interface::{ContextInterface, PublicContextInterface}}, hash::hash_args_array }; diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index 5c4b1fb5c1f..a976420cfd5 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -45,13 +45,7 @@ impl PrivateSet { broadcast: bool, ivpk_m: GrumpkinPoint ) where Note: NoteInterface { - create_note( - self.context, - self.storage_slot, - note, - broadcast, - ivpk_m - ); + create_note(self.context, self.storage_slot, note, broadcast, ivpk_m); } // docs:end:insert diff --git a/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr b/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr index e335ad0cfbc..eeed3726be0 100644 --- a/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr +++ b/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr @@ -1,6 +1,5 @@ use dep::aztec::{ - context::PrivateContext, - protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}, + context::PrivateContext, protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}, note::note_getter_options::NoteGetterOptions, state_vars::PrivateSet, keys::getters::{get_npk_m_hash, get_ivpk_m} }; diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index ec31b8690ae..659ecb38b8f 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -12,7 +12,11 @@ pub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteG // Creates a new note for the recipient. // Inserts it to the recipient's set of notes. -pub fn increment(balance: PrivateSet, amount: Field, recipient: AztecAddress) { +pub fn increment( + balance: PrivateSet, + amount: Field, + recipient: AztecAddress +) { let context = balance.context; let recipient_npk_m_hash = get_npk_m_hash(context, recipient); let recipient_ivpk_m = get_ivpk_m(context, recipient); @@ -26,7 +30,11 @@ pub fn increment(balance: PrivateSet, amount: Fi // Remove those notes. // If the value of the removed notes exceeds the requested `amount`, create a new note containing the excess value, so that exactly `amount` is removed. // Fail if the sum of the selected notes is less than the amount. -pub fn decrement(balance: PrivateSet, amount: Field, owner: AztecAddress) { +pub fn decrement( + balance: PrivateSet, + amount: Field, + owner: AztecAddress +) { let sum = decrement_by_at_most(balance, amount, owner); assert(sum == amount, "Balance too low"); } @@ -80,7 +88,11 @@ pub fn decrement_by_at_most( // Removes the note from the owner's set of notes. // Returns the value of the destroyed note. -pub fn destroy_note(balance: PrivateSet, owner: AztecAddress, note: ValueNote) -> Field { +pub fn destroy_note( + balance: PrivateSet, + owner: AztecAddress, + note: ValueNote +) -> Field { // Ensure the note is actually owned by the owner (to prevent user from generating a valid proof while // spending someone else's notes). let owner_npk_m_hash = get_npk_m_hash(balance.context, owner); From a8ccf6ad47f14d67ce212b3ccc446f33a8a8d067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 21 May 2024 14:39:06 +0000 Subject: [PATCH 14/15] Restore accidentally deleted function --- .../contracts/token_contract/src/main.nr | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index d84d4c218b3..09f69cca44e 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -76,6 +76,10 @@ contract Token { } // docs:end:set_admin + unconstrained fn un_get_name() -> pub [u8; 31] { + storage.name.read_public().to_bytes() + } + #[aztec(public)] fn public_get_name() -> pub FieldCompressedString { storage.name.read_public() @@ -86,6 +90,10 @@ contract Token { storage.name.read_private() } + unconstrained fn un_get_symbol() -> pub [u8; 31] { + storage.symbol.read_public().to_bytes() + } + #[aztec(public)] fn public_get_symbol() -> pub FieldCompressedString { storage.symbol.read_public() @@ -96,6 +104,10 @@ contract Token { storage.symbol.read_private() } + unconstrained fn un_get_decimals() -> pub u8 { + storage.decimals.read_public() + } + #[aztec(public)] fn public_get_decimals() -> pub u8 { // docs:start:read_decimals_public From 6b4e6da4cdda6eeec25cc393f4ec5232da0cdf43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 21 May 2024 16:22:48 +0000 Subject: [PATCH 15/15] Fix links --- docs/docs/reference/smart_contract_reference/storage/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/reference/smart_contract_reference/storage/index.md b/docs/docs/reference/smart_contract_reference/storage/index.md index 84cfe9d919b..3a9a3fee788 100644 --- a/docs/docs/reference/smart_contract_reference/storage/index.md +++ b/docs/docs/reference/smart_contract_reference/storage/index.md @@ -24,7 +24,7 @@ On this and the following pages in this section, you’ll learn: ## The `Context` parameter -Aztec contracts have three different modes of execution: [private](../../../../aztec/aztec/glossary/call_types.md#private-execution), [public](../../../../aztec/aztec/glossary/call_types.md#public-execution) and [top-level unconstrained](../../../../aztec/aztec/glossary/call_types.md#top-level-unconstrained). How storage is accessed depends on the execution mode: for example, `PublicImmutable` can be read in all execution modes but only initialized in public, while `PrivateMutable` is entirely unavailable in public. +Aztec contracts have three different modes of execution: [private](../../../aztec/glossary/call_types.md#private-execution), [public](../../../aztec/glossary/call_types.md#public-execution) and [top-level unconstrained](../../../aztec/glossary/call_types.md#top-level-unconstrained). How storage is accessed depends on the execution mode: for example, `PublicImmutable` can be read in all execution modes but only initialized in public, while `PrivateMutable` is entirely unavailable in public. Aztec.nr prevents developers from calling functions unavailable in the current execution mode via the `context` variable that is injected into all contract functions. Its type indicates the current execution mode: - `&mut PrivateContext` for private execution