Storage
Leo provides storage variables for persistent on-chain state that isn't tied to record ownership or mapping key-value lookups:
program counter.aleo {
@noupgrade
constructor() {}
storage count: u64;
storage history: [field];
fn bump(public next: u64) -> Final {
return final {
count = next;
history.push(BHP256::hash_to_field(next));
};
}
}
Storage declarations live inside the program { } block, and reads and writes only work inside final code, same as mappings.
A storage variable behaves like an option: it is unset until something assigns to it. Read it with count.unwrap_or(0u64) rather than count.unwrap() unless you are certain it has been initialized, since unwrapping an unset value fails the transaction.
Storage vectors (storage history: [field];) are dynamic on-chain lists supporting push, pop, len, get, and set. They do not support index syntax: history[0u32] fails, and history.get(0u32) returns an option you have to unwrap. Under the hood Leo lowers a storage vector into two mappings, one holding the elements and one holding the length.
Everything in storage is publicly readable. Use it for counters, configuration, and accumulators, and use records for anything that should stay private.