use alloc::collections::BTreeMap;
use miden_crypto::merkle::{InnerNodeInfo, SmtProof};
use crate::Word;
use crate::account::StorageMap;
use crate::errors::StorageMapError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StorageMapWitness {
proof: SmtProof,
entries: BTreeMap<Word, Word>,
}
impl StorageMapWitness {
pub fn new(
proof: SmtProof,
raw_keys: impl IntoIterator<Item = Word>,
) -> Result<Self, StorageMapError> {
let mut entries = BTreeMap::new();
for raw_key in raw_keys.into_iter() {
let hashed_map_key = StorageMap::hash_key(raw_key);
let value =
proof.get(&hashed_map_key).ok_or(StorageMapError::MissingKey { raw_key })?;
entries.insert(raw_key, value);
}
Ok(Self { proof, entries })
}
pub fn new_unchecked(
proof: SmtProof,
raw_key_values: impl IntoIterator<Item = (Word, Word)>,
) -> Self {
Self {
proof,
entries: raw_key_values.into_iter().collect(),
}
}
pub fn proof(&self) -> &SmtProof {
&self.proof
}
pub fn get(&self, raw_key: &Word) -> Option<Word> {
let hashed_key = StorageMap::hash_key(*raw_key);
self.proof.get(&hashed_key)
}
pub fn entries(&self) -> impl Iterator<Item = (&Word, &Word)> {
self.entries.iter()
}
pub fn authenticated_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
self.proof
.path()
.authenticated_nodes(self.proof.leaf().index().value(), 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 = Word::from([1, 2, 3, 4u32]);
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 = Word::from([5, 6, 7, 8u32]);
let result = StorageMapWitness::new(proof, [missing_key]);
assert_matches!(result, Err(StorageMapError::MissingKey { raw_key }) => {
assert_eq!(raw_key, missing_key);
});
}
}