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 page.
PublicMutable
The PublicMutable
(formerly known as PublicState
) struct is generic over the variable type T
. The type must implement Serialize and Deserialize traits, as specified here:
trait Serialize<N> {
fn serialize(self) -> [Field; N];
}
Source code: noir-projects/noir-protocol-circuits/crates/types/src/traits.nr#L86-L90
trait Deserialize<N> {
fn deserialize(fields: [Field; N]) -> Self;
}
Source code: noir-projects/noir-protocol-circuits/crates/types/src/traits.nr#L108-L112
The struct contains a storage_slot
which, similar to Ethereum, is used to figure out where in storage the variable is located. Notice that while we don't have the exact same state model as EVM chains it will look similar from the contract developers point of view.
You can find the details of PublicMutable
in the implementation here.
For a version of PublicMutable
that can also be read in private, head to SharedMutable
.
An example using a larger struct can be found in the lending example's use of an Asset
.
new
When declaring the storage for T
as a persistent public storage variable, we use the PublicMutable::new()
constructor. As seen below, this takes the storage_slot
and the serialization_methods
as arguments along with the Context
, which in this case is used to share interface with other structures. You can view the implementation here.
Single value example
Say that we wish to add admin
public state variable into our storage struct. In the struct we can define it as:
leader: PublicMutable<Leader>,
Source code: noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr#L30-L32
Mapping example
Say we want to have a group of minters
that are able to mint assets in our contract, and we want them in public storage, because access control in private is quite cumbersome. In the Storage
struct we can add it as follows:
minters: Map<AztecAddress, PublicMutable<bool>>,
Source code: noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr#L47-L49
read
On the PublicMutable
structs we have a read
method to read the value at the location in storage.
Reading from our admin
example
For our admin
example from earlier, this could be used as follows to check that the stored value matches the msg_sender()
.
assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin");
Source code: noir-projects/noir-contracts/contracts/token_contract/src/main.nr#L156-L158
Reading from our minters
example
As we saw in the Map earlier, a very similar operation can be done to perform a lookup in a map.
assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter");
Source code: noir-projects/noir-contracts/contracts/token_contract/src/main.nr#L168-L170
write
We have a write
method on the PublicMutable
struct that takes the value to write as an input and saves this in storage. It uses the serialization method to serialize the value which inserts (possibly multiple) values into storage.
Writing to our admin
example
storage.admin.write(new_admin);
Source code: noir-projects/noir-contracts/contracts/token_contract/src/main.nr#L75-L77
Writing to our minters
example
storage.minters.at(minter).write(approve);
Source code: noir-projects/noir-contracts/contracts/token_contract/src/main.nr#L159-L161
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
.
Just like the PublicMutable
it is generic over the variable type T
. The type MUST
implement Serialize and Deserialize traits.
You can find the details of PublicImmutable
in the implementation here.
new
Is done exactly like the PublicMutable
struct, but with the PublicImmutable
struct.
public_immutable: PublicImmutable<Leader>,
Source code: noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr#L50-L52
Source code: noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr#L90-L91
initialize
let mut new_leader = Leader { account: context.msg_sender(), points };
storage.public_immutable.initialize(new_leader);
Source code: noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr#L157-L160
read
Reading the value is just like PublicMutable
.
storage.public_immutable.read()
Source code: noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr#L164-L166