-
Notifications
You must be signed in to change notification settings - Fork 596
docs: storage and state variables #1725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
584fb1b
12fb070
80c51e2
6e5c2d6
e1a4822
97f4ae7
77d69d8
83d337e
f78d591
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,10 +4,16 @@ | |
|
|
||
| State variables must be declared inside a struct. (This enables us to declare types composed of nested generics in Noir - see [types](./types.md)). | ||
|
|
||
| By way of example, we could define a private state variable `balances`, mapping user addresses to their token balances: | ||
| We could define any kinds of state variables in the Storage struct: | ||
|
|
||
| #include_code storage-declaration /yarn-project/noir-contracts/src/contracts/private_token_contract/src/storage.nr rust | ||
| #include_code storage-declaration /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/storage.nr rust | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll start reviewing this now (in between other meetings). It's looking lovely! My first comment: If the example contract is going to be used throughout the syntax explanations (which is a very nice idea), should we have a page or paragraph which introduces the purpose of this contract? What is the game? What is the objective of the game? What are the rules? What do players do? It feels like this explanation could be both a README within the contract's directory, but also as a dedicated page or paragraph of these docs? |
||
|
|
||
| #include_code storage-import /yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr rust | ||
| See [State Variables](./state_variables.md) for how to initialise them. | ||
|
|
||
| State variables come in two flavours: **public** state and **private** state. <INSERT LINK TO DOC EXPLAINING PRIVATE STATE & UTXOS>. | ||
| Using Storage in a contract is like using any other struct in Noir. First, import the struct into the contract's `main.nr` file: | ||
|
|
||
| #include_code storage-import /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust | ||
|
|
||
| For each function that needs access to the storage, initialise the storage inside the function, and call the state variables in it: | ||
|
|
||
| #include_code storage-init /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| artifacts/ | ||
| target/ | ||
| proofs/ | ||
| types/ | ||
| /src/types/ | ||
| Prover.toml | ||
| Verifier.toml |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| [package] | ||
| name = "docs_example_contract" | ||
| authors = [""] | ||
| compiler_version = "0.1" | ||
iAmMichaelConnor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| type = "contract" | ||
|
|
||
| [dependencies] | ||
| aztec = { path = "../../../../noir-libs/noir-aztec" } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| struct AccountContractInterface { | ||
| address: Field, | ||
| } | ||
|
|
||
| impl AccountContractInterface { | ||
| fn at(address: Field) -> Self { | ||
| AccountContractInterface { address } | ||
| } | ||
|
|
||
| fn send_rewards(_self: Self, _rewards: u8) { | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| use dep::std::option::Option; | ||
| use dep::aztec::constants_gen::{MAX_READ_REQUESTS_PER_CALL, MAX_NOTES_PER_PAGE}; | ||
| use dep::aztec::context::{ | ||
| PrivateContext, | ||
| }; | ||
| use dep::aztec::note::{ | ||
| note_getter_options::NoteGetterOptions, | ||
| note_viewer_options::NoteViewerOptions, | ||
| }; | ||
| use dep::aztec::state_vars::{ | ||
| immutable_singleton::ImmutableSingleton, | ||
| map::Map, | ||
| public_state::PublicState, | ||
| set::Set, | ||
| singleton::Singleton, | ||
| }; | ||
| use dep::aztec::types::type_serialisation::bool_serialisation::{ | ||
| BOOL_SERIALISED_LEN, | ||
| }; | ||
|
|
||
| use crate::types::{ | ||
| card_note::{CardNote, CARD_NOTE_LEN}, | ||
| profile_note::{ProfileNote, PROFILE_NOTE_LEN}, | ||
| queen::{Queen, QUEEN_SERIALISED_LEN}, | ||
| rules_note::{RulesNote, RULES_NOTE_LEN}, | ||
| }; | ||
|
|
||
| // docs:start:state_vars-PublicStateRead | ||
| fn is_locked(state_var: PublicState<bool, BOOL_SERIALISED_LEN>) -> bool { | ||
| state_var.read() | ||
| } | ||
| // docs:end:state_vars-PublicStateRead | ||
|
|
||
| // docs:start:state_vars-PublicStateWrite | ||
| fn lock(state_var: PublicState<bool, BOOL_SERIALISED_LEN>) { | ||
| state_var.write(true); | ||
| } | ||
| // docs:end:state_vars-PublicStateWrite | ||
|
|
||
| fn unlock(state_var: PublicState<bool, BOOL_SERIALISED_LEN>) { | ||
| state_var.write(false); | ||
| } | ||
|
|
||
| // docs:start:state_vars-PublicStateReadCustom | ||
| fn get_current_queen(state_var: PublicState<Queen, QUEEN_SERIALISED_LEN>) -> Queen { | ||
| state_var.read() | ||
| } | ||
| // docs:end:state_vars-PublicStateReadCustom | ||
|
|
||
| fn can_replace_queen( | ||
| state_var: PublicState<Queen, QUEEN_SERIALISED_LEN>, | ||
| new_queen: Queen, | ||
| ) -> bool { | ||
| let current_queen = get_current_queen(state_var); | ||
| new_queen.points > current_queen.points | ||
| } | ||
|
|
||
| // docs:start:state_vars-PublicStateWriteCustom | ||
| fn replace_queen( | ||
| state_var: PublicState<Queen, QUEEN_SERIALISED_LEN>, | ||
| new_queen: Queen, | ||
| ) { | ||
| state_var.write(new_queen); | ||
| } | ||
| // docs:end:state_vars-PublicStateWriteCustom | ||
|
|
||
| // docs:start:state_vars-PublicStateReadWriteCustom | ||
| fn add_points_to_queen( | ||
| state_var: PublicState<Queen, QUEEN_SERIALISED_LEN>, | ||
| new_points: u8, | ||
| ) { | ||
| let mut queen = state_var.read(); | ||
| queen.points += new_points; | ||
| state_var.write(queen); | ||
| } | ||
| // docs:end:state_vars-PublicStateReadWriteCustom | ||
|
|
||
| // docs:start:state_vars-SingletonInit | ||
| fn init_legendary_card( | ||
| context: &mut PrivateContext, | ||
| state_var: Singleton<CardNote, CARD_NOTE_LEN>, | ||
| card: &mut CardNote, | ||
| ) { | ||
| state_var.initialise(context, card); | ||
| } | ||
| // docs:end:state_vars-SingletonInit | ||
|
|
||
| // docs:start:state_vars-SingletonReplace | ||
| fn update_legendary_card( | ||
| context: &mut PrivateContext, | ||
| state_var: Singleton<CardNote, CARD_NOTE_LEN>, | ||
| card: &mut CardNote, | ||
| ) { | ||
| state_var.replace(context, card); | ||
| } | ||
| // docs:end:state_vars-SingletonReplace | ||
|
|
||
| // docs:start:state_vars-SingletonGet | ||
| fn get_legendary_card( | ||
| context: &mut PrivateContext, | ||
| state_var: Singleton<CardNote, CARD_NOTE_LEN>, | ||
| ) -> CardNote { | ||
| state_var.get_note(context) | ||
| } | ||
| // docs:end:state_vars-SingletonGet | ||
|
|
||
| // docs:start:state_vars-ImmutableSingletonInit | ||
| fn init_game_rules( | ||
| context: &mut PrivateContext, | ||
| state_var: ImmutableSingleton<RulesNote, RULES_NOTE_LEN>, | ||
| rules: &mut RulesNote, | ||
| ) { | ||
| state_var.initialise(context, rules); | ||
| } | ||
| // docs:end:state_vars-ImmutableSingletonInit | ||
|
|
||
| // docs:start:state_vars-ImmutableSingletonGet | ||
| fn is_valid_card( | ||
| context: &mut PrivateContext, | ||
| state_var: ImmutableSingleton<RulesNote, RULES_NOTE_LEN>, | ||
| card: CardNote, | ||
| ) -> bool { | ||
| let rules = state_var.get_note(context); | ||
| card.points >= rules.min_points & card.points <= rules.max_points | ||
| } | ||
| // docs:end:state_vars-ImmutableSingletonGet | ||
|
|
||
| // docs:start:state_vars-SetInsert | ||
| fn add_new_card( | ||
| context: &mut PrivateContext, | ||
| state_var: Set<CardNote, CARD_NOTE_LEN>, | ||
| card: &mut CardNote, | ||
| ) { | ||
| state_var.insert(context, card); | ||
| } | ||
| // docs:end:state_vars-SetInsert | ||
|
|
||
| // docs:start:state_vars-SetRemove | ||
| fn remove_card( | ||
| context: &mut PrivateContext, | ||
| state_var: Set<CardNote, CARD_NOTE_LEN>, | ||
| card: CardNote, | ||
| ) { | ||
| state_var.remove(context, card); | ||
| } | ||
| // docs:end:state_vars-SetRemove | ||
|
|
||
| // docs:start:state_vars-SetGet | ||
| fn get_cards<FILTER_PARAMS>( | ||
| context: &mut PrivateContext, | ||
| state_var: Set<CardNote, CARD_NOTE_LEN>, | ||
| options: NoteGetterOptions<CardNote, CARD_NOTE_LEN, FILTER_PARAMS>, | ||
| ) -> [Option<CardNote>; MAX_READ_REQUESTS_PER_CALL] { | ||
| state_var.get_notes(context, options) | ||
| } | ||
| // docs:end:state_vars-SetGet | ||
|
|
||
| // docs:start:state_vars-SetView | ||
| unconstrained fn view_cards( | ||
| state_var: Set<CardNote, CARD_NOTE_LEN>, | ||
| options: NoteViewerOptions<CardNote, CARD_NOTE_LEN>, | ||
| ) -> [Option<CardNote>; MAX_NOTES_PER_PAGE] { | ||
| state_var.view_notes(options) | ||
| } | ||
| // docs:end:state_vars-SetView | ||
|
|
||
| unconstrained fn get_total_points(state_var: Set<CardNote, CARD_NOTE_LEN>, account: Field, offset: u32) -> u8 { | ||
| let options = NoteViewerOptions::new().select(2, account).set_offset(offset); | ||
| let mut total_points = 0; | ||
| let notes = view_cards(state_var, options); | ||
| for i in 0..notes.len() { | ||
| if notes[i].is_some() { | ||
| total_points += notes[i].unwrap_unchecked().points; | ||
| } | ||
| } | ||
| if notes[notes.len() - 1].is_some() { | ||
| total_points += get_total_points(state_var, account, offset + notes.len() as u32); | ||
| } | ||
| total_points | ||
| } | ||
|
|
||
| // docs:start:state_vars-SetContains | ||
| fn assert_contains_card<RERUEN_LEN, FILTER_PARAMS>( | ||
| context: &mut PrivateContext, | ||
| state_var: Set<CardNote, CARD_NOTE_LEN>, | ||
| card: CardNote, | ||
| ) { | ||
| state_var.assert_contains_and_remove(context, card); | ||
| } | ||
| // docs:end:state_vars-SetContains | ||
|
|
||
| // docs:start:state_vars-MapAtSingletonInit | ||
| fn add_new_profile( | ||
| context: &mut PrivateContext, | ||
| state_var: Map<Singleton<ProfileNote, PROFILE_NOTE_LEN>>, | ||
| account: Field, | ||
| profile: &mut ProfileNote, | ||
| ) { | ||
| state_var.at(account).initialise(context, profile); | ||
| } | ||
| // docs:end:state_vars-MapAtSingletonInit | ||
|
|
||
| // docs:start:state_vars-MapAtSingletonGet | ||
| fn get_profile( | ||
| context: &mut PrivateContext, | ||
| state_var: Map<Singleton<ProfileNote, PROFILE_NOTE_LEN>>, | ||
| account: Field, | ||
| ) -> ProfileNote { | ||
| state_var.at(account).get_note(context) | ||
| } | ||
| // docs:end:state_vars-MapAtSingletonGet |
Uh oh!
There was an error while loading. Please reload this page.