use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use miden_agglayer::agglayer_package;
use miden_processor::{LoadedMastForest, MastForestStore};
use miden_protocol::account::AccountCode;
use miden_protocol::assembly::mast::MastForest;
use miden_protocol::package::loaded_mast_forest_from_package;
use miden_protocol::transaction::TransactionKernel;
use miden_protocol::utils::sync::RwLock;
use miden_protocol::vm::Package;
use miden_protocol::{CoreLibrary, ProtocolLib, Word};
use miden_standards::StandardsLib;
pub struct TransactionMastStore {
mast_forests: RwLock<BTreeMap<Word, LoadedMastForest>>,
}
#[allow(clippy::new_without_default)]
impl TransactionMastStore {
pub fn new() -> Self {
let mast_forests = RwLock::new(BTreeMap::new());
let store = Self { mast_forests };
let kernel = TransactionKernel::package();
store.insert_package(kernel.as_ref());
let miden_core_lib = CoreLibrary::default();
for package in miden_core_lib.packages() {
store.insert_package(package.as_ref());
}
let protocol_lib = ProtocolLib::default();
store.insert_package(protocol_lib.as_ref());
let standards_lib = StandardsLib::default();
store.insert_package(standards_lib.as_ref());
store.insert_package(&agglayer_package());
store
}
pub fn insert(&self, mast_forest: Arc<MastForest>) {
self.insert_loaded(LoadedMastForest::new(mast_forest));
}
pub fn insert_package(&self, package: &Package) {
self.insert_loaded(loaded_mast_forest_from_package(package));
}
pub fn insert_loaded(&self, loaded_mast_forest: LoadedMastForest) {
let mut mast_forests = self.mast_forests.write();
for proc_digest in loaded_mast_forest.mast_forest().local_procedure_digests() {
mast_forests.insert(proc_digest, loaded_mast_forest.clone());
}
}
pub fn load_account_code(&self, code: &AccountCode) {
self.insert_loaded(code.loaded_mast_forest());
}
}
impl MastForestStore for TransactionMastStore {
fn get(&self, procedure_root: &Word) -> Option<LoadedMastForest> {
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::package().mast_forest().clone();
store1.insert(kernel_forest);
let store2 = TransactionMastStore::new();
assert_eq!(store2.len(), baseline, "new store must not inherit entries from others");
}
}