use alloc::collections::BTreeMap;
use miden_core::EMPTY_WORD;
use miden_crypto::merkle::EmptySubtreeRoots;
use super::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, Word};
use crate::account::StorageMapDelta;
use crate::crypto::merkle::{InnerNodeInfo, LeafIndex, SMT_DEPTH, Smt, SmtLeaf};
use crate::errors::StorageMapError;
use crate::{AccountError, Felt, Hasher};
mod partial;
pub use partial::PartialStorageMap;
mod witness;
pub use witness::StorageMapWitness;
pub const EMPTY_STORAGE_MAP_ROOT: Word = *EmptySubtreeRoots::entry(StorageMap::DEPTH, 0);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StorageMap {
smt: Smt,
entries: BTreeMap<Word, Word>,
}
impl StorageMap {
pub const DEPTH: u8 = SMT_DEPTH;
pub const EMPTY_VALUE: Word = Smt::EMPTY_VALUE;
pub fn new() -> Self {
StorageMap {
smt: Smt::new(),
entries: BTreeMap::new(),
}
}
pub fn with_entries<I: ExactSizeIterator<Item = (Word, Word)>>(
entries: impl IntoIterator<Item = (Word, Word), IntoIter = I>,
) -> Result<Self, StorageMapError> {
let mut map = BTreeMap::new();
for (key, value) in entries {
if let Some(prev_value) = map.insert(key, value) {
return Err(StorageMapError::DuplicateKey {
key,
value0: prev_value,
value1: value,
});
}
}
Ok(Self::from_btree_map(map))
}
fn from_btree_map(entries: BTreeMap<Word, Word>) -> Self {
let hashed_keys_iter = entries.iter().map(|(key, value)| (Self::hash_key(*key), *value));
let smt = Smt::with_entries(hashed_keys_iter)
.expect("btree maps should not contain duplicate keys");
StorageMap { smt, entries }
}
pub fn root(&self) -> Word {
self.smt.root()
}
pub fn num_leaves(&self) -> usize {
self.smt.num_leaves()
}
pub fn num_entries(&self) -> usize {
self.smt.num_entries()
}
pub fn get(&self, raw_key: &Word) -> Word {
self.entries.get(raw_key).copied().unwrap_or_default()
}
pub fn open(&self, raw_key: &Word) -> StorageMapWitness {
let hashed_map_key = Self::hash_key(*raw_key);
let smt_proof = self.smt.open(&hashed_map_key);
let value = self.entries.get(raw_key).copied().unwrap_or_default();
StorageMapWitness::new_unchecked(smt_proof, [(*raw_key, value)])
}
pub fn leaves(&self) -> impl Iterator<Item = (LeafIndex<SMT_DEPTH>, &SmtLeaf)> {
self.smt.leaves() }
pub fn entries(&self) -> impl Iterator<Item = (&Word, &Word)> {
self.entries.iter()
}
pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
self.smt.inner_nodes() }
pub fn insert(&mut self, raw_key: Word, value: Word) -> Result<Word, AccountError> {
if value == EMPTY_WORD {
self.entries.remove(&raw_key);
} else {
self.entries.insert(raw_key, value);
}
let hashed_key = Self::hash_key(raw_key);
self.smt
.insert(hashed_key, value)
.map_err(AccountError::MaxNumStorageMapLeavesExceeded)
}
pub fn apply_delta(&mut self, delta: &StorageMapDelta) -> Result<Word, AccountError> {
for (&key, &value) in delta.entries().iter() {
self.insert(key.into_inner(), value)?;
}
Ok(self.root())
}
pub fn into_entries(self) -> BTreeMap<Word, Word> {
self.entries
}
pub fn hash_key(raw_key: Word) -> Word {
Hasher::hash_elements(raw_key.as_elements())
}
pub fn hashed_map_key_to_leaf_index(hashed_map_key: Word) -> Felt {
hashed_map_key[3]
}
}
impl Default for StorageMap {
fn default() -> Self {
Self::new()
}
}
impl Serializable for StorageMap {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.entries.write_into(target);
}
fn get_size_hint(&self) -> usize {
self.smt.get_size_hint()
}
}
impl Deserializable for StorageMap {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let map = BTreeMap::read_from(source)?;
Ok(Self::from_btree_map(map))
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
use super::{Deserializable, EMPTY_STORAGE_MAP_ROOT, Serializable, StorageMap, Word};
use crate::errors::StorageMapError;
#[test]
fn account_storage_serialization() {
let storage_map_default = StorageMap::default();
let bytes = storage_map_default.to_bytes();
assert_eq!(storage_map_default, StorageMap::read_from_bytes(&bytes).unwrap());
let storage_map_leaves_2: [(Word, Word); 2] = [
(Word::from([101, 102, 103, 104u32]), Word::from([1, 2, 3, 4u32])),
(Word::from([105, 106, 107, 108u32]), Word::from([5, 6, 7, 8u32])),
];
let storage_map = StorageMap::with_entries(storage_map_leaves_2).unwrap();
assert_eq!(storage_map.num_entries(), 2);
assert_eq!(storage_map.num_leaves(), 2);
let bytes = storage_map.to_bytes();
let deserialized_map = StorageMap::read_from_bytes(&bytes).unwrap();
assert_eq!(storage_map.root(), deserialized_map.root());
assert_eq!(storage_map, deserialized_map);
}
#[test]
fn test_empty_storage_map_constants() {
assert_eq!(StorageMap::default().root(), EMPTY_STORAGE_MAP_ROOT);
}
#[test]
fn account_storage_map_fails_on_duplicate_entries() {
let storage_map_leaves_2: [(Word, Word); 2] = [
(Word::from([101, 102, 103, 104u32]), Word::from([1, 2, 3, 4u32])),
(Word::from([101, 102, 103, 104u32]), Word::from([5, 6, 7, 8u32])),
];
let error = StorageMap::with_entries(storage_map_leaves_2).unwrap_err();
assert_matches!(error, StorageMapError::DuplicateKey { .. });
}
}