Expand description
Performs lowering of storage variables and storage vectors into explicit Mapping operations.
This pass rewrites high-level storage constructs—such as storage declarations and Vector methods concrete
calls to the underlying Mapping API used in Aleo programs. Each storage variable is de-sugared into one or more
Mapping instances, and all read/write operations are rewritten as Mapping::get, Mapping::set, or
Mapping::get_or_use calls.
§Overview
-
Storage Variables: Each top-level
storagevariable (e.g.,storage counter: u32;) is represented by aMappingthat persists across transitions. The pass introduces ternary expressions that check whether the underlying mapping contains a value before reading it. -
Storage Vectors: A
storagevector (e.g.,storage vec: [u32];) is lowered into two mappings:<vec_name>__stores the vector elements keyed by au32index.<vec_name>__len__stores the current vector length under keyfalse.
Vector operations such as
.push(),.pop(),.len(),.get(),.set(),.swap_remove(), and.clear()are translated into combinations ofMappingcalls and helper expressions that manipulate the length mapping and element mappings directly.
§Example: Storage Vector
storage vec: [u32];
async transition test_vector_ops() -> Future {
return async {
vec.push(10u32);
let x = vec.get(0u32).unwrap();
let y = vec.pop();
};
}is lowered to:
mapping vec__: u32 => u32; // vector values
mapping vec__len__: bool => u32; // length
// vec.push(10u32);
let $len_var = Mapping::get_or_use(vec__len__, false, 0u32);
Mapping::set(vec__, $len_var, 10u32);
Mapping::set(vec__len__, false, $len_var + 1u32);
// let x = vec.get(3u32);
let $len_var = Mapping::get_or_use(vec__len__, false, 0u32);
let x = 3u32 < $len_var ? Mapping::get_or_use(vec__, 3u32, 0u32) : None;
// let y = vec.pop();
let $len_var = Mapping::get_or_use(vec__len__, false, 0u32);
if ($len_var > 0u32) { Mapping::set(vec__len__, false, $len_var - 1u32); }
let y = $len_var > 0u32 ? Mapping::get_or_use(vec__, $len_var - 1u32, 0u32) : None;§Example: Singleton Storage
storage counter: u32;
async transition increment() -> Future {
return async {
let old = counter.unwrap_or(0u32);
counter = old + 1u32;
};
}is lowered to:
mapping counter__: bool => u32;
// let old = counter.unwrap_or(0u32)
let old = counter__.contains(false) ? counter__.get_or_use(false, 0u32) : 0u32
// counter = old + 1u32
Mapping::set(counter__, false, old + 1u32)