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, MastForestStore, ProcessorState};
use miden_protocol::Word;
use miden_protocol::account::{AccountDelta, PartialAccount};
use miden_protocol::assembly::debuginfo::Location;
use miden_protocol::assembly::{SourceFile, SourceSpan};
use miden_protocol::transaction::{InputNote, InputNotes, RawOutputNote};
use miden_protocol::vm::{EventId, EventName};
use crate::host::{RecipientData, ScriptMastForestStore, TransactionBaseHost, TransactionEvent};
use crate::{AccountProcedureIndexMap, TransactionKernelError};
pub struct TransactionProverHost<'store, STORE>
where
STORE: MastForestStore,
{
base_host: TransactionBaseHost<'store, STORE>,
}
impl<'store, STORE> TransactionProverHost<'store, STORE>
where
STORE: MastForestStore,
{
pub fn new(
account: &PartialAccount,
input_notes: InputNotes<InputNote>,
mast_store: &'store STORE,
scripts_mast_store: ScriptMastForestStore,
acct_procedure_index_map: AccountProcedureIndexMap,
) -> Self {
let base_host = TransactionBaseHost::new(
account,
input_notes,
mast_store,
scripts_mast_store,
acct_procedure_index_map,
);
Self { base_host }
}
pub fn into_parts(self) -> (AccountDelta, InputNotes<InputNote>, Vec<RawOutputNote>) {
self.base_host.into_parts()
}
}
impl<STORE> Host for TransactionProverHost<'_, STORE>
where
STORE: MastForestStore,
{
fn get_label_and_source_file(
&self,
_location: &Location,
) -> (SourceSpan, Option<Arc<SourceFile>>) {
(SourceSpan::UNKNOWN, None)
}
fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend<Option<Arc<MastForest>>> {
let result = self.base_host.get_mast_forest(node_digest);
async move { result }
}
fn on_event(
&mut self,
process: &ProcessorState,
) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>> {
let result = self.on_event_sync(process);
async move { result }
}
fn resolve_event(&self, event_id: EventId) -> Option<&EventName> {
self.base_host.resolve_event(event_id)
}
}
impl<STORE> TransactionProverHost<'_, STORE>
where
STORE: MastForestStore,
{
fn on_event_sync(
&mut self,
process: &ProcessorState,
) -> Result<Vec<AdviceMutation>, EventError> {
if let Some(advice_mutations) = self.base_host.handle_core_lib_events(process)? {
return Ok(advice_mutations);
}
let tx_event =
TransactionEvent::extract(&self.base_host, process).map_err(EventError::from)?;
let Some(tx_event) = tx_event else {
return Ok(Vec::new());
};
let result = match tx_event {
TransactionEvent::AccountBeforeForeignLoad { .. } => Ok(Vec::new()),
TransactionEvent::AccountVaultAfterRemoveAsset { asset } => {
self.base_host.on_account_vault_after_remove_asset(asset)
},
TransactionEvent::AccountVaultAfterAddAsset { asset } => {
self.base_host.on_account_vault_after_add_asset(asset)
},
TransactionEvent::AccountStorageAfterSetItem { slot_name, new_value } => {
self.base_host.on_account_storage_after_set_item(slot_name, new_value)
},
TransactionEvent::AccountStorageAfterSetMapItem {
slot_name,
key,
old_value,
new_value,
} => self
.base_host
.on_account_storage_after_set_map_item(slot_name, key, old_value, new_value),
TransactionEvent::AccountVaultBeforeAssetAccess { .. } => Ok(Vec::new()),
TransactionEvent::AccountStorageBeforeMapItemAccess { .. } => Ok(Vec::new()),
TransactionEvent::AccountAfterIncrementNonce => {
self.base_host.on_account_after_increment_nonce()
},
TransactionEvent::AccountPushProcedureIndex { code_commitment, procedure_root } => {
self.base_host.on_account_push_procedure_index(code_commitment, procedure_root)
},
TransactionEvent::NoteBeforeCreated { note_idx, metadata, recipient_data } => {
match recipient_data {
RecipientData::Digest(recipient_digest) => self
.base_host
.output_note_from_recipient_digest(note_idx, metadata, recipient_digest),
RecipientData::Recipient(note_recipient) => self
.base_host
.output_note_from_recipient(note_idx, metadata, note_recipient),
RecipientData::ScriptMissing { .. } => Err(TransactionKernelError::other(
"note script should be in the advice provider at proving time",
)),
}
},
TransactionEvent::NoteBeforeAddAsset { note_idx, asset } => {
self.base_host.on_note_before_add_asset(note_idx, asset).map(|_| Vec::new())
},
TransactionEvent::NoteBeforeSetAttachment { note_idx, attachment } => self
.base_host
.on_note_before_set_attachment(note_idx, attachment)
.map(|_| Vec::new()),
TransactionEvent::AuthRequest { signature, .. } => {
if let Some(signature) = signature {
Ok(self.base_host.on_auth_requested(signature))
} else {
Err(TransactionKernelError::other(
"signatures should be in the advice provider at proving time",
))
}
},
TransactionEvent::Unauthorized { tx_summary } => {
Err(TransactionKernelError::other(format!(
"unexpected unauthorized event during proving with tx summary commitment {}",
tx_summary.to_commitment()
)))
},
TransactionEvent::EpilogueBeforeTxFeeRemovedFromAccount { .. } => Ok(Vec::new()),
TransactionEvent::LinkMapSet { advice_mutation } => Ok(advice_mutation),
TransactionEvent::LinkMapGet { advice_mutation } => Ok(advice_mutation),
TransactionEvent::Progress(_) => Ok(Vec::new()),
};
result.map_err(EventError::from)
}
}