use alloc::collections::BTreeSet;
use alloc::sync::Arc;
use alloc::vec::Vec;
use miden_processor::advice::AdviceMutation;
use miden_processor::event::EventError;
use miden_processor::mast::MastForest;
use miden_processor::{FutureMaybeSend, Host, ProcessorState};
use miden_protocol::transaction::TransactionEventId;
use miden_protocol::vm::{EventId, EventName};
use miden_protocol::{CoreLibrary, Word};
use miden_tx::TransactionExecutorHost;
use miden_tx::auth::UnreachableAuth;
use crate::TransactionContext;
pub(crate) struct MockHost<'store> {
exec_host: TransactionExecutorHost<'store, 'static, TransactionContext, UnreachableAuth>,
handled_events: BTreeSet<EventId>,
}
impl<'store> MockHost<'store> {
pub fn new(
exec_host: TransactionExecutorHost<'store, 'static, TransactionContext, UnreachableAuth>,
) -> Self {
let core_lib_handlers = CoreLibrary::default()
.handlers()
.into_iter()
.map(|(handler_event_name, _)| handler_event_name.to_event_id());
let mut handled_events = BTreeSet::from_iter(core_lib_handlers);
handled_events.extend(
[
&TransactionEventId::AccountPushProcedureIndex,
&TransactionEventId::LinkMapSet,
&TransactionEventId::LinkMapGet,
&TransactionEventId::EpilogueBeforeTxFeeRemovedFromAccount,
]
.map(TransactionEventId::event_id),
);
Self { exec_host, handled_events }
}
pub fn enable_lazy_loading(&mut self) {
self.handled_events.extend(
[
&TransactionEventId::AccountBeforeForeignLoad,
&TransactionEventId::AccountVaultBeforeGetAsset,
&TransactionEventId::AccountVaultBeforeAddAsset,
&TransactionEventId::AccountVaultBeforeRemoveAsset,
&TransactionEventId::AccountStorageBeforeSetMapItem,
&TransactionEventId::AccountStorageBeforeGetMapItem,
]
.map(TransactionEventId::event_id),
);
}
}
impl<'store> Host for MockHost<'store> {
fn get_label_and_source_file(
&self,
location: &miden_protocol::assembly::debuginfo::Location,
) -> (
miden_protocol::assembly::debuginfo::SourceSpan,
Option<Arc<miden_protocol::assembly::SourceFile>>,
) {
self.exec_host.get_label_and_source_file(location)
}
fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend<Option<Arc<MastForest>>> {
self.exec_host.get_mast_forest(node_digest)
}
fn on_event(
&mut self,
process: &ProcessorState,
) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>> {
let event_id = EventId::from_felt(process.get_stack_item(0));
async move {
if self.handled_events.contains(&event_id) {
self.exec_host.on_event(process).await
} else {
Ok(Vec::new())
}
}
}
fn resolve_event(&self, event_id: EventId) -> Option<&EventName> {
self.exec_host.resolve_event(event_id)
}
}