use alloc::collections::BTreeMap;
use miden_crypto::merkle::InnerNodeInfo;
use miden_crypto::merkle::smt::SmtProof;
use crate::Word;
use crate::account::StorageMapKey;
use crate::errors::StorageMapError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StorageMapWitness {
proof: SmtProof,
entries: BTreeMap<StorageMapKey, Word>,
}
impl StorageMapWitness {
pub fn new(
proof: SmtProof,
keys: impl IntoIterator<Item = StorageMapKey>,
) -> Result<Self, StorageMapError> {
let mut entries = BTreeMap::new();
for key in keys.into_iter() {
let hashed_map_key = key.hash().as_word();
let value = proof.get(&hashed_map_key).ok_or(StorageMapError::MissingKey { key })?;
entries.insert(key, value);
}
Ok(Self { proof, entries })
}
pub fn new_unchecked(
proof: SmtProof,
key_values: impl IntoIterator<Item = (StorageMapKey, Word)>,
) -> Self {
Self {
proof,
entries: key_values.into_iter().collect(),
}
}
pub fn proof(&self) -> &SmtProof {
&self.proof
}
pub fn get(&self, key: StorageMapKey) -> Option<Word> {
let hash_word = key.hash().as_word();
self.proof.get(&hash_word)
}
pub fn entries(&self) -> impl Iterator<Item = (&StorageMapKey, &Word)> {
self.entries.iter()
}
pub fn authenticated_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
self.proof
.path()
.authenticated_nodes(self.proof.leaf().index().position(), self.proof.leaf().hash())
.expect("leaf index is u64 and should be less than 2^SMT_DEPTH")
}
}
impl From<StorageMapWitness> for SmtProof {
fn from(witness: StorageMapWitness) -> Self {
witness.proof
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
use super::*;
use crate::account::StorageMap;
#[test]
fn creating_witness_fails_on_missing_key() {
let key1 = StorageMapKey::from_array([1, 2, 3, 4]);
let value1 = Word::from([10, 20, 30, 40u32]);
let entries = [(key1, value1)];
let storage_map = StorageMap::with_entries(entries).unwrap();
let proof = storage_map.open(&key1).into();
let missing_key = StorageMapKey::from_array([5, 6, 7, 8u32]);
let result = StorageMapWitness::new(proof, [missing_key]);
assert_matches!(result, Err(StorageMapError::MissingKey { key }) => {
assert_eq!(key, missing_key);
});
}
}