Skip to content
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

docs: storage and state variables #1725

Merged
merged 9 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions docs/docs/dev_docs/contracts/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@

## secret functions

LeilaWang marked this conversation as resolved.
Show resolved Hide resolved
> a.k.a. "private" functions

#include_code functions-SecretFunction /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

## `open` functions

LeilaWang marked this conversation as resolved.
Show resolved Hide resolved
## `unconstrained` functions
> a.k.a. "public" functions

#include_code functions-OpenFunction /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

## `unconstrained` functions

#include_code functions-UncontrainedFunction /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

# Calling functions

Expand Down Expand Up @@ -47,4 +55,4 @@ E.g. `get()`

## Delegatecall

Talk a about the dangers of delegatecall too!
Talk a about the dangers of delegatecall too!
301 changes: 284 additions & 17 deletions docs/docs/dev_docs/contracts/state_variables.md

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions docs/docs/dev_docs/contracts/storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The 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
3 changes: 2 additions & 1 deletion docs/docs/dev_docs/contracts/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
On top of [Noir's stdlib](https://noir-lang.org/standard_library/array_methods), we provide [Aztec.nr](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-libs) for writing contracts on Aztec.

Aztec.nr contains abstractions which remove the need to understand the low-level Aztec protocol. Notably, it provides:

- Public and private [state variable types](./types.md)
- Some pre-designed notes.
- Functions for [emitting](./events.md) encrypted and unencrypted logs
Expand All @@ -15,4 +16,4 @@ Aztec.nr contains abstractions which remove the need to understand the low-level

To import Aztec.nr into your Aztec contract project, simply include it as a dependency.

#include_code importing-aztec /yarn-project/noir-contracts/src/contracts/private_token_contract/Nargo.toml toml
#include_code importing-aztec /yarn-project/noir-contracts/src/contracts/private_token_contract/Nargo.toml toml
2 changes: 1 addition & 1 deletion yarn-project/noir-contracts/.gitignore
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
Loading