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

feat(aztec_noir): abstract storage initialisation #2406

Merged
merged 12 commits into from
Sep 26, 2023
8 changes: 8 additions & 0 deletions docs/docs/dev_docs/contracts/syntax/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,14 @@ Each Aztec function has access to a [context](./context.mdx) object. This object
As previously mentioned we use the kernel to pass information between circuits. This means that the return values of functions must also be passed to the kernel (where they can be later passed on to another function).
We achieve this by pushing return values to the execution context, which we then pass to the kernel.

**Making the contract's storage available**
#include_code storage-example-context /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust
Copy link
Contributor

@rahul-kothari rahul-kothari Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need to show this given the macro? Wouldn't it be more confusing?

Or if we do, can we also show how storage init works for public? (this include code just shows for private)

Copy link
Member Author

@Maddiaa0 Maddiaa0 Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case we should also show the expansion for a public function as the context uses different values too. I think people can infer that a different context goes in there. I can leave a note alluding to it.

I can also update the example such that it actually uses storage if that helps

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since in expansion I think its fine to show it 🤷


When a [`Storage` struct](./storage.md) is declared within a contract, the `storage` keyword is made available. As shown in the macro expansion above, this calls the init function on the storage struct with the current function's context.

Any state variables declared in the `Storage` struct can now be accessed as normal struct members.


**Returning the function context to the kernel.**
#include_code context-example-finish /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust

Expand Down
9 changes: 1 addition & 8 deletions docs/docs/dev_docs/contracts/syntax/storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,7 @@ impl Storage {
}
```

To use storage in functions, e.g., functions where you would read or write storage, you need to initialize the struct first, and then you can read and write afterwards. Below are snippets for initializing in private and public functions.

#include_code private_init_storage /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust
#include_code public_init_storage /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust

:::info
https://github.com/AztecProtocol/aztec-packages/pull/2406 is removing the need to explicitly initialize the storage in each function before reading or writing. This will be updated in the docs once the PR is merged.
:::
If you have defined a `Storage` struct following this naming scheme, then it will be made available to you through the reserved `storage` keyword within your contract functions.

:::warning Using slot `0` is not supported!
No storage values should be initialized at slot `0`. This is a known issue that will be fixed in the future.
Expand Down
15 changes: 2 additions & 13 deletions docs/docs/dev_docs/tutorials/writing_token_contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,8 @@ Public functions are declared with the `#[aztec(public)]` macro above the functi

As described in the [execution contexts section above](#execution-contexts), public function logic and transaction information is transparent to the world. Public functions update public state, but can be used to prepare data to be used in a private context, as we will go over below (e.g. see the [shield](#shield) function).

Every public function initializes storage using the public context like so:

```rust
let storage = Storage::init(Context::public(&mut context));
```

After this, storage is referenced as `storage.variable`. We won't go over this step in any of the following function descriptions.
Storage is referenced as `storage.variable`.

#### `set_admin`

Expand Down Expand Up @@ -374,13 +369,7 @@ Private functions are declared with the `#[aztec(private)]` macro above the func

As described in the [execution contexts section above](#execution-contexts), private function logic and transaction information is hidden from the world and is executed on user devices. Private functions update private state, but can pass data to the public execution context (e.g. see the [`unshield`](#unshield) function).

Every private function initializes storage using the private context like so:

```rust
let storage = Storage::init(Context::private(&mut context));
```

After this, storage is referenced as `storage.variable`. We won't go over this step in any of the following function descriptions.
Storage is referenced as `storage.variable`.

#### `redeem_shield`

Expand Down
10 changes: 5 additions & 5 deletions yarn-project/aztec.js/src/abis/ecdsa_account_contract.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions yarn-project/aztec.js/src/abis/schnorr_account_contract.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions yarn-project/boxes/private-token/src/contracts/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ contract PrivateToken {
initial_supply: Field,
owner: Field
) {
let storage = Storage::init(Context::private(&mut context));

// Insert new note to a set of user notes and emit the newly created encrypted note preimage via oracle call.
let owner_balance = storage.balances.at(owner);
if (initial_supply != 0) {
Expand All @@ -53,7 +53,7 @@ contract PrivateToken {
amount: Field,
owner: Field
) {
let storage = Storage::init(Context::private(&mut context));


// Insert new note to a set of user notes and emit the newly created encrypted note preimage via oracle call.
let owner_balance = storage.balances.at(owner);
Expand All @@ -66,7 +66,7 @@ contract PrivateToken {
amount: Field,
recipient: Field,
) {
let storage = Storage::init(Context::private(&mut context));

let sender = context.msg_sender();

// Pick from the set of sender's notes to spend amount.
Expand All @@ -82,7 +82,7 @@ contract PrivateToken {
unconstrained fn getBalance(
owner: Field,
) -> Field {
let storage = Storage::init(Context::none());


// Get the set of notes owned by the user.
let owner_balance = storage.balances.at(owner);
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/noir-compiler/src/noir-version.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"tag": "0.11.1-aztec.0",
"commit": "2103b2ffb640fe457b24be09b6d63fe6ee1c6ac1"
"tag": "0.12.0-aztec.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can already see the pain out there from this hehe.

"commit": "3b43709ddd5feffdbbc1723ba7dbcf63531aae05"
}
Original file line number Diff line number Diff line change
@@ -1,72 +1,16 @@
mod cards;
mod game;

use dep::aztec::{
context::{PrivateContext, PublicContext, Context},
state_vars::{
map::Map,
public_state::PublicState,
},
};

use dep::std::option::Option;

use cards::{Deck};
use game::{Game, GameSerializationMethods, GAME_SERIALIZED_LEN};

struct Storage {
collections: Map<Deck>,
game_decks: Map<Map<Deck>>,
games: Map<PublicState<Game, GAME_SERIALIZED_LEN>>,
}
contract CardGame {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not clear to me why you are changing the entire ordering here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this to work it needs to see the Storage struct within the contract def, previously it was a scope up

use dep::aztec::{
context::Context,
state_vars::{
map::Map,
public_state::PublicState,
},
};

impl Storage {
fn init(
context: Context,
) -> Self {
Storage {
collections: Map::new(
context,
1,
|context, slot| {
Deck::new(
context,
slot,
)
},
),
game_decks: Map::new(
context,
2,
|context, slot| {
Map::new(
context,
slot,
|context, slot|{
Deck::new(
context,
slot,
)
}
)
},
),
games: Map::new(
context,
3,
|context, slot| {
PublicState::new(
context,
slot,
GameSerializationMethods,
)
},
)
}
}
}

contract CardGame {
use dep::std::option::Option;
use dep::value_note::{
balance_utils,
Expand All @@ -82,15 +26,13 @@ contract CardGame {
abi::{
Hasher, PrivateContextInputs,
},
context::{PrivateContext, Context},
note::{
note_header::NoteHeader,
utils as note_utils,
},
oracle::compute_selector::compute_selector
};

use crate::Storage;
use crate::cards::{
PACK_CARDS,
Deck,
Expand All @@ -103,8 +45,62 @@ contract CardGame {
NUMBER_OF_CARDS_DECK,
PLAYABLE_CARDS,
PlayerEntry,
Game
Game,
GameSerializationMethods,
GAME_SERIALIZED_LEN
};

struct Storage {
collections: Map<Deck>,
game_decks: Map<Map<Deck>>,
games: Map<PublicState<Game, GAME_SERIALIZED_LEN>>,
}

impl Storage {
fn init(
context: Context,
) -> pub Self {
Storage {
collections: Map::new(
context,
1,
|context, slot| {
Deck::new(
context,
slot,
)
},
),
game_decks: Map::new(
context,
2,
|context, slot| {
Map::new(
context,
slot,
|context, slot|{
Deck::new(
context,
slot,
)
}
)
},
),
games: Map::new(
context,
3,
|context, slot| {
PublicState::new(
context,
slot,
GameSerializationMethods,
)
},
)
}
}
}

#[aztec(private)]
fn constructor() {}
Expand All @@ -113,7 +109,7 @@ contract CardGame {
fn buy_pack(
seed: Field, // The randomness used to generate the cards. Passed in for now.
) {
let storage = Storage::init(Context::private(&mut context));

let buyer = context.msg_sender();
let mut cards = get_pack_cards(seed, buyer);

Expand All @@ -127,7 +123,7 @@ contract CardGame {
cards_fields: [Field; 2],
) {
let cards = cards_fields.map(|card_field| Card::from_field(card_field));
let storage = Storage::init(Context::private(&mut context));

let player = context.msg_sender();

let mut collection = storage.collections.at(player);
Expand All @@ -145,7 +141,7 @@ contract CardGame {
player: Field,
deck_strength: u32,
) {
let storage = Storage::init(Context::public(&mut context));

let game_storage = storage.games.at(game as Field);

let mut game_data = game_storage.read();
Expand All @@ -156,7 +152,7 @@ contract CardGame {

#[aztec(public)]
fn start_game(game: u32) {
let storage = Storage::init(Context::public(&mut context));

let game_storage = storage.games.at(game as Field);

let mut game_data = game_storage.read();
Expand All @@ -169,7 +165,7 @@ contract CardGame {
game: u32,
card: Card,
) {
let storage = Storage::init(Context::private(&mut context));

let player = context.msg_sender();

let mut game_deck = storage.game_decks.at(game as Field).at(player);
Expand All @@ -181,7 +177,7 @@ contract CardGame {

#[aztec(public)]
internal fn on_card_played(game: u32, player: Field, card_as_field: Field) {
let storage = Storage::init(Context::public(&mut context));

let game_storage = storage.games.at(game as Field);

let mut game_data = game_storage.read();
Expand All @@ -199,7 +195,7 @@ contract CardGame {
game: u32,
cards_fields: [Field; PLAYABLE_CARDS],
) {
let storage = Storage::init(Context::private(&mut context));

let player = context.msg_sender();
let cards = cards_fields.map(|card_field| Card::from_field(card_field));

Expand All @@ -216,7 +212,7 @@ contract CardGame {

#[aztec(public)]
internal fn on_cards_claimed(game: u32, player: Field, cards_hash: Field) {
let storage = Storage::init(Context::public(&mut context));

let game_storage = storage.games.at(game as Field);
let mut game_data = game_storage.read();

Expand All @@ -235,21 +231,21 @@ contract CardGame {
}

unconstrained fn view_collection_cards(owner: Field, offset: u32) -> [Option<Card>; MAX_NOTES_PER_PAGE] {
let storage = Storage::init(Context::none());

let collection = storage.collections.at(owner);

collection.view_cards(offset)
}

unconstrained fn view_game_cards(game: u32, player: Field, offset: u32) -> [Option<Card>; MAX_NOTES_PER_PAGE] {
let storage = Storage::init(Context::none());

let game_deck = storage.game_decks.at(game as Field).at(player);

game_deck.view_cards(offset)
}

unconstrained fn view_game(game: u32) -> Game {
Storage::init(Context::none()).games.at(game as Field).read()
storage.games.at(game as Field).read()
}

// Computes note hash and nullifier.
Expand Down
Loading