use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use miden_processor::MastForestStore;
use miden_protocol::account::AccountCode;
use miden_protocol::assembly::mast::MastForest;
use miden_protocol::transaction::TransactionKernel;
use miden_protocol::utils::sync::RwLock;
use miden_protocol::{CoreLibrary, ProtocolLib, Word};
use miden_standards::StandardsLib;
pub struct TransactionMastStore {
mast_forests: RwLock<BTreeMap<Word, Arc<MastForest>>>,
}
#[allow(clippy::new_without_default)]
impl TransactionMastStore {
pub fn new() -> Self {
let mast_forests = RwLock::new(BTreeMap::new());
let store = Self { mast_forests };
let kernels_forest = TransactionKernel::kernel().mast_forest().clone();
store.insert(kernels_forest);
let miden_core_lib_forest = CoreLibrary::default().mast_forest().clone();
store.insert(miden_core_lib_forest);
let protocol_lib_forest = ProtocolLib::default().mast_forest().clone();
store.insert(protocol_lib_forest);
let standards_lib_forest = StandardsLib::default().mast_forest().clone();
store.insert(standards_lib_forest);
store
}
pub fn insert(&self, mast_forest: Arc<MastForest>) {
let mut mast_forests = self.mast_forests.write();
for proc_digest in mast_forest.local_procedure_digests() {
mast_forests.insert(proc_digest, mast_forest.clone());
}
}
pub fn load_account_code(&self, code: &AccountCode) {
self.insert(code.mast().clone());
}
}
impl MastForestStore for TransactionMastStore {
fn get(&self, procedure_root: &Word) -> Option<Arc<MastForest>> {
self.mast_forests.read().get(procedure_root).cloned()
}
}
#[cfg(test)]
impl TransactionMastStore {
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.mast_forests.read().len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fresh_stores_have_same_baseline_size() {
let store1 = TransactionMastStore::new();
let store2 = TransactionMastStore::new();
assert_eq!(store1.len(), store2.len());
assert!(store1.len() > 0, "default libraries should populate the store");
}
#[test]
fn insert_does_not_affect_other_stores() {
let store1 = TransactionMastStore::new();
let baseline = store1.len();
let kernel_forest = TransactionKernel::kernel().mast_forest().clone();
store1.insert(kernel_forest);
let store2 = TransactionMastStore::new();
assert_eq!(store2.len(), baseline, "new store must not inherit entries from others");
}
}