Skip to content

Commit

Permalink
feat!: remove SharedImmutable (#10183)
Browse files Browse the repository at this point in the history
Working on #10164
made me realize that this state variable is now useless: it is the exact
same as `PublicImmutable` except it also has getters for private
execution contexts. I deleted it entirely in favor of `PublicImmutable`,
which should be less surprising for a library user. After all, reading
publicly known immutable values during private execution is fine.

I updated the docs and tests accordingly, mostly keeping the shared
immut versions as those were more complete.
  • Loading branch information
nventuro authored Nov 25, 2024
1 parent 6e7fae7 commit a9f3b5f
Show file tree
Hide file tree
Showing 21 changed files with 127 additions and 237 deletions.
9 changes: 9 additions & 0 deletions docs/docs/migration_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ Aztec is in full-speed development. Literally every version breaks compatibility

## TBD

### [aztec.nr] Removed SharedImmutable

The `SharedImmutable` state variable has been removed, since it was essentially the exact same as `PublicImmutable`, which now contains functions for reading from private:

```diff
- foo: SharedImmutable<T, Context>.
+ foo: PublicImmutable<T, Context>.
```

### [aztec.nr] SharedImmutable renamings

`SharedImmutable::read_private` and `SharedImmutable::read_public` were renamed to simply `read`, since only one of these versions is ever available depending on the current context.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ You control this storage in Aztec using a struct annotated with `#[storage]`. Th

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.
Aztec.nr has a few abstractions to help define the type of data your contract holds. These include PrivateMutable, PrivateImmutable, PublicMutable, PublicImmutable, PrivateSet, and SharedMutable.

On this and the following pages in this section, you’ll learn:

- How to manage a smart contract's storage structure
- The distinctions and applications of public and private state variables
- How to use PrivateMutable, PrivateImmutable, PrivateSet, PublicMutable, SharedImmutable and Map
- How to use PrivateMutable, PrivateImmutable, PrivateSet, PublicMutable, SharedMutable and Map
- An overview of 'notes' and the UTXO model
- 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Public State

On this page we will look at how to manage public state in Aztec contracts. We will look at how to declare public state, how to read and write to it, and how to use it in your contracts.

For a higher level overview of the state model in Aztec, see the [state model](../../../../aztec/concepts/state_model/index.md) concepts page.
For a higher level overview of the state model in Aztec, see the [state model](../../../../aztec/concepts/state_model/index.md) concepts page.

## `PublicMutable`

Expand Down Expand Up @@ -71,9 +71,11 @@ We have a `write` method on the `PublicMutable` struct that takes the value to w

## `PublicImmutable`

`PublicImmutable` is a type that can be written once during a contract deployment and read later on from public only. For a version of `PublicImmutable` that can also be read in private, head to [`SharedImmutable`](./shared_state.md#sharedimmutable).
`PublicImmutable` is a type that is initialized from public once, typically during a contract deployment, but which can later be read from public, private and unconstrained execution contexts. This state variable is useful for stuff that you would usually have in `immutable` values in Solidity, e.g. this can be the name of a token or its number of decimals.

Just like the `PublicMutable` it is generic over the variable type `T`. The type `MUST` implement Serialize and Deserialize traits.
Just like the `PublicMutable` it is generic over the variable type `T`. The type `MUST` implement the `Serialize` and `Deserialize` traits.

#include_code storage-public-immutable-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust

You can find the details of `PublicImmutable` in the implementation [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr).

Expand All @@ -83,13 +85,20 @@ Is done exactly like the `PublicMutable` struct, but with the `PublicImmutable`

#include_code storage-public-immutable-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust

#include_code storage-public-immutable /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust

### `initialize`

This function sets the immutable value. It can only be called once.

#include_code initialize_decimals /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust

:::warning
A `PublicImmutable`'s storage **must** only be set once via `initialize`. Attempting to override this by manually accessing the underlying storage slots breaks all properties of the data structure, rendering it useless.
:::

#include_code initialize_public_immutable /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust

### `read`

Reading the value is just like `PublicMutable`.
Returns the stored immutable value. This function is available in public, private and unconstrained contexts.

#include_code read_public_immutable /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust
Original file line number Diff line number Diff line change
Expand Up @@ -97,31 +97,3 @@ Returns the last scheduled value change, along with the block number at which th
#include_code shared_mutable_get_scheduled_public /noir-projects/noir-contracts/contracts/auth_contract/src/main.nr rust

It is not possible to call this function in private: doing so would not be very useful at it cannot be asserted that a scheduled value change will not be immediately replaced if `shcedule_value_change` where to be called.

## `SharedImmutable`

`SharedImmutable` (formerly known as `StablePublicState`) is a simplification of the `SharedMutable` case, where the value can only be set once during initialization. Because there's no further mutation, there's no need for delays. These state variables are useful for stuff that you would usually have in `immutable` values in Solidity, e.g. this can be the name of a token or its number of decimals.

Like most state variables, `SharedImmutable` is generic over the variable type `T`. This type `MUST` implement the `Serialize` and `Deserialize` traits.

#include_code storage-shared-immutable-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust

You can find the details of `SharedImmutable` in the implementation [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr).

### `initialize`

This function sets the immutable value. It must only be called once during contract construction.

#include_code initialize_decimals /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust

:::warning
A `SharedImmutable`'s storage **must** only be set once via `initialize`. Attempting to override this by manually accessing the underlying storage slots breaks all properties of the data structure, rendering it useless.
:::

### `read`

Returns the stored immutable value. This function is available in public, private and unconstrained contexts.

#include_code read_shared_immutable_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust

#include_code read_shared_immutable_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ We are using various utils within the Aztec `prelude` library:
- `PrivateContext` - exposes things such as the contract address, msg_sender, etc
- `Map` - A data storage type for storing candidates with the number of votes they have
- `PublicMutable` - A type of storage, which holds a mutable public value. We'll store votes as PublicMutables
- `SharedImmutable` - an immutable storage value that is accessible in private and public execution.
- `PublicImmutable` - an immutable storage value that is accessible in private and public execution.

## Set up storage

Expand Down
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/prelude.nr
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub use crate::{
state_vars::{
map::Map, private_immutable::PrivateImmutable, private_mutable::PrivateMutable,
private_set::PrivateSet, public_immutable::PublicImmutable, public_mutable::PublicMutable,
shared_immutable::SharedImmutable, shared_mutable::SharedMutable, storage::Storable,
shared_mutable::SharedMutable, storage::Storable,
},
};
pub use dep::protocol_types::{
Expand Down
2 changes: 0 additions & 2 deletions noir-projects/aztec-nr/aztec/src/state_vars/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ pub mod private_mutable;
pub mod public_immutable;
pub mod public_mutable;
pub mod private_set;
pub mod shared_immutable;
pub mod shared_mutable;
pub mod storage;

Expand All @@ -14,6 +13,5 @@ pub use crate::state_vars::private_mutable::PrivateMutable;
pub use crate::state_vars::private_set::PrivateSet;
pub use crate::state_vars::public_immutable::PublicImmutable;
pub use crate::state_vars::public_mutable::PublicMutable;
pub use crate::state_vars::shared_immutable::SharedImmutable;
pub use crate::state_vars::shared_mutable::SharedMutable;
pub use crate::state_vars::storage::Storage;
28 changes: 25 additions & 3 deletions noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use crate::{context::{PublicContext, UnconstrainedContext}, state_vars::storage::Storage};
use crate::{
context::{PrivateContext, PublicContext, UnconstrainedContext},
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.
/// Stores an immutable value in public state which can be read from public, private and unconstrained execution
/// contexts.
// docs:start:public_immutable_struct
pub struct PublicImmutable<T, Context> {
context: Context,
Expand Down Expand Up @@ -57,9 +61,27 @@ where

impl<T, let T_SERIALIZED_LEN: u32> PublicImmutable<T, UnconstrainedContext>
where
T: Deserialize<T_SERIALIZED_LEN>,
T: Serialize<T_SERIALIZED_LEN> + Deserialize<T_SERIALIZED_LEN>,
{
pub unconstrained fn read(self) -> T {
self.context.storage_read(self.storage_slot)
}
}

impl<T, let T_SERIALIZED_LEN: u32> PublicImmutable<T, &mut PrivateContext>
where
T: Serialize<T_SERIALIZED_LEN> + Deserialize<T_SERIALIZED_LEN>,
{
pub fn read(self) -> T {
let header = self.context.get_header();
let mut fields = [0; T_SERIALIZED_LEN];

for i in 0..fields.len() {
fields[i] = header.public_storage_historical_read(
self.storage_slot + i as Field,
(*self.context).this_address(),
);
}
T::deserialize(fields)
}
}
78 changes: 0 additions & 78 deletions noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ contract AppSubscription {
encrypted_logs::encrypted_note_emission::encode_and_encrypt_note,
keys::getters::get_public_keys,
macros::{functions::{initializer, private, public}, storage::storage},
prelude::{AztecAddress, Map, PrivateMutable, SharedImmutable},
prelude::{AztecAddress, Map, PrivateMutable, PublicImmutable},
protocol_types::constants::MAX_FIELD_VALUE,
utils::comparison::Comparator,
};
Expand All @@ -21,15 +21,12 @@ contract AppSubscription {

#[storage]
struct Storage<Context> {
// 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<AztecAddress, Context>,
subscription_token_address: SharedImmutable<AztecAddress, Context>,
subscription_recipient_address: SharedImmutable<AztecAddress, Context>,
subscription_price: SharedImmutable<Field, Context>,
target_address: PublicImmutable<AztecAddress, Context>,
subscription_token_address: PublicImmutable<AztecAddress, Context>,
subscription_recipient_address: PublicImmutable<AztecAddress, Context>,
subscription_price: PublicImmutable<Field, Context>,
subscriptions: Map<AztecAddress, PrivateMutable<SubscriptionNote, Context>, Context>,
fee_juice_limit_per_tx: SharedImmutable<Field, Context>,
fee_juice_limit_per_tx: PublicImmutable<Field, Context>,
}

global SUBSCRIPTION_DURATION_IN_BLOCKS = 5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ contract Claim {
macros::{functions::{initializer, private, public}, storage::storage},
note::utils::compute_note_hash_for_nullify,
protocol_types::address::AztecAddress,
state_vars::SharedImmutable,
state_vars::PublicImmutable,
};
use dep::value_note::value_note::ValueNote;
use token::Token;

#[storage]
struct Storage<Context> {
// Address of a contract based on whose notes we distribute the rewards
target_contract: SharedImmutable<AztecAddress, Context>,
target_contract: PublicImmutable<AztecAddress, Context>,
// Token to be distributed as a reward when claiming
reward_token: SharedImmutable<AztecAddress, Context>,
reward_token: PublicImmutable<AztecAddress, Context>,
}

#[public]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract Crowdfunding {
functions::{initializer, internal, private, public},
storage::storage,
},
prelude::{AztecAddress, PrivateSet, SharedImmutable},
prelude::{AztecAddress, PrivateSet, PublicImmutable},
protocol_types::traits::Serialize,
unencrypted_logs::unencrypted_event_emission::encode_event,
utils::comparison::Comparator,
Expand All @@ -38,11 +38,11 @@ contract Crowdfunding {
#[storage]
struct Storage<Context> {
// Token used for donations (e.g. DAI)
donation_token: SharedImmutable<AztecAddress, Context>,
donation_token: PublicImmutable<AztecAddress, Context>,
// Crowdfunding campaign operator
operator: SharedImmutable<AztecAddress, Context>,
operator: PublicImmutable<AztecAddress, Context>,
// End of the crowdfunding campaign after which no more donations are accepted
deadline: SharedImmutable<u64, Context>,
deadline: PublicImmutable<u64, Context>,
// Notes emitted to donors when they donate (can be used as proof to obtain rewards, eg in Claim contracts)
donation_receipts: PrivateSet<ValueNote, Context>,
}
Expand Down
Loading

0 comments on commit a9f3b5f

Please sign in to comment.