Evolve provides type-safe, deterministic storage collections for module state.
Each storage field needs a unique u8 prefix within its module. The #[derive(AccountState)] macro validates uniqueness at compile time.
#[derive(evolve_core::AccountState)]
pub struct MyModule {
#[storage(0)]
pub counter: Item<u64>,
#[storage(1)]
pub balances: Map<AccountId, u128>,
#[storage(2)] // ERROR: compile fails if you use duplicate prefix
pub metadata: Item<String>,
}- Prevents accidental collisions - Compile-time validation catches duplicates
- Stable across refactors - Reordering fields doesn't change storage layout
- Migration safety - Adding new fields doesn't corrupt existing data
Some collections require multiple prefixes:
| Collection | Prefixes Required | Example |
|---|---|---|
Item<T> |
1 | Item::new(0) |
Map<K,V> |
1 | Map::new(0) |
Vector<T> |
2 | Vector::new(0, 1) |
Queue<T> |
2 | Queue::new(0, 1) |
UnorderedMap<K,V> |
4 | UnorderedMap::new(0, 1, 2, 3) |
For multi-prefix collections, use manual initialization:
pub struct ComplexModule {
validators: UnorderedMap<AccountId, Validator>,
changes: Vector<Change>,
}
impl ComplexModule {
pub const fn new() -> Self {
Self {
validators: UnorderedMap::new(0, 1, 2, 3),
changes: Vector::new(4, 5),
}
}
}Single value storage.
use evolve_collections::item::Item;
#[storage(0)]
pub counter: Item<u64>,
// Write
self.counter.set(&42, env)?;
// Read (returns error if not set)
let value = self.counter.get(env)?;
// Read (returns Option)
let maybe_value = self.counter.may_get(env)?;
// Update
self.counter.update(|current| {
Ok(current.unwrap_or(0) + 1)
}, env)?;Key-value storage with deterministic iteration.
use evolve_collections::map::Map;
#[storage(1)]
pub balances: Map<AccountId, u128>,
// Write
self.balances.set(&account_id, &balance, env)?;
// Read
let balance = self.balances.get(&account_id, env)?;
let maybe_balance = self.balances.may_get(&account_id, env)?;
// Check existence
let exists = self.balances.exists(&account_id, env)?;
// Update
self.balances.update(&account_id, |current| {
Ok(current.unwrap_or(0) + amount)
}, env)?;
// Remove
self.balances.remove(&account_id, env)?;Ordered, indexable sequence.
use evolve_collections::vector::Vector;
// Requires 2 prefixes (index + elements)
pub items: Vector<Item>,
impl Module {
pub const fn new() -> Self {
Self { items: Vector::new(0, 1) }
}
}
// Push
self.items.push(&item, env)?;
// Access by index
let item = self.items.get(0, env)?;
// Length
let len = self.items.len(env)?;
// Iterate
for item in self.items.iter(env)? {
let item = item?;
// process item
}FIFO queue for ordered processing.
use evolve_collections::queue::Queue;
// Requires 2 prefixes
pub pending: Queue<Task>,
// Enqueue
self.pending.push_back(&task, env)?;
// Dequeue
let task = self.pending.pop_front(env)?;
// Peek
let next = self.pending.front(env)?;
// Check empty
let is_empty = self.pending.is_empty(env)?;Hash-like map with O(1) access but deterministic iteration.
use evolve_collections::unordered_map::UnorderedMap;
// Requires 4 prefixes
pub validators: UnorderedMap<AccountId, Validator>,
impl Module {
pub const fn new() -> Self {
Self {
validators: UnorderedMap::new(0, 1, 2, 3),
}
}
}
// Insert
self.validators.insert(&key, &value, env)?;
// Remove (swap-remove, O(1))
self.validators.remove(&key, env)?;
// Iterate (order not guaranteed but deterministic)
for entry in self.validators.iter(env)? {
let (key, value) = entry?;
}For stateless helper types (like EventsEmitter), use #[skip_storage]:
#[derive(evolve_core::AccountState)]
pub struct MyModule {
#[storage(0)]
pub data: Item<Data>,
#[skip_storage]
pub events: EventsEmitter, // Initialized with Type::new()
}| Limit | Value |
|---|---|
| Max key size | 254 bytes |
| Max value size | 1 MB |
| Max overlay entries | 100,000 per transaction |
| Max events | 10,000 per execution |
- Use
may_get()for optional data - ReturnsOption<T>instead of erroring - Prefer
update()for read-modify-write - Atomic operation - Reserve prefix ranges - Leave gaps for future fields (0, 10, 20...)
- Document prefix assignments - Add comments for complex modules