use alloc::sync::Arc;
use vm_core::{
DebugOptions,
crypto::hash::RpoDigest,
mast::{MastForest, MastNodeExt},
};
use super::{ExecutionError, ProcessState};
use crate::{Felt, KvMap, MemAdviceProvider, errors::ErrorContext};
pub(super) mod advice;
use advice::AdviceProvider;
#[cfg(feature = "std")]
mod debug;
mod mast_forest_store;
pub use mast_forest_store::{MastForestStore, MemMastForestStore};
pub trait Host {
type AdviceProvider: AdviceProvider;
fn advice_provider(&self) -> &Self::AdviceProvider;
fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider;
fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>>;
fn on_event(
&mut self,
_process: ProcessState,
_event_id: u32,
_err_ctx: &ErrorContext<'_, impl MastNodeExt>,
) -> Result<(), ExecutionError> {
#[cfg(feature = "std")]
std::println!(
"Event with id {} emitted at step {} in context {}",
_event_id,
_process.clk(),
_process.ctx()
);
Ok(())
}
fn on_debug(
&mut self,
_process: ProcessState,
_options: &DebugOptions,
) -> Result<(), ExecutionError> {
#[cfg(feature = "std")]
debug::print_debug_info(_process, _options);
Ok(())
}
fn on_trace(&mut self, _process: ProcessState, _trace_id: u32) -> Result<(), ExecutionError> {
#[cfg(feature = "std")]
std::println!(
"Trace with id {} emitted at step {} in context {}",
_trace_id,
_process.clk(),
_process.ctx()
);
Ok(())
}
fn on_assert_failed(&mut self, _process: ProcessState, _err_code: Felt) {}
}
impl<H> Host for &mut H
where
H: Host,
{
type AdviceProvider = H::AdviceProvider;
fn advice_provider(&self) -> &Self::AdviceProvider {
H::advice_provider(self)
}
fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider {
H::advice_provider_mut(self)
}
fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
H::get_mast_forest(self, node_digest)
}
fn on_debug(
&mut self,
process: ProcessState,
options: &DebugOptions,
) -> Result<(), ExecutionError> {
H::on_debug(self, process, options)
}
fn on_event(
&mut self,
process: ProcessState,
event_id: u32,
err_ctx: &ErrorContext<'_, impl MastNodeExt>,
) -> Result<(), ExecutionError> {
H::on_event(self, process, event_id, err_ctx)
}
fn on_trace(&mut self, process: ProcessState, trace_id: u32) -> Result<(), ExecutionError> {
H::on_trace(self, process, trace_id)
}
fn on_assert_failed(&mut self, process: ProcessState, err_code: Felt) {
H::on_assert_failed(self, process, err_code)
}
}
pub struct DefaultHost<A> {
adv_provider: A,
store: MemMastForestStore,
}
impl<A: Clone> Clone for DefaultHost<A> {
fn clone(&self) -> Self {
Self {
adv_provider: self.adv_provider.clone(),
store: self.store.clone(),
}
}
}
impl Default for DefaultHost<MemAdviceProvider> {
fn default() -> Self {
Self {
adv_provider: MemAdviceProvider::default(),
store: MemMastForestStore::default(),
}
}
}
impl<A: AdviceProvider> DefaultHost<A> {
pub fn new(adv_provider: A) -> Self {
Self {
adv_provider,
store: MemMastForestStore::default(),
}
}
pub fn load_mast_forest(&mut self, mast_forest: Arc<MastForest>) -> Result<(), ExecutionError> {
for (digest, values) in mast_forest.advice_map().iter() {
if let Some(stored_values) = self.advice_provider().get_mapped_values(digest) {
if stored_values != values {
return Err(ExecutionError::AdviceMapKeyAlreadyPresent {
key: digest.into(),
prev_values: stored_values.to_vec(),
new_values: values.clone(),
});
}
} else {
self.advice_provider_mut().insert_into_map(digest.into(), values.clone());
}
}
self.store.insert(mast_forest);
Ok(())
}
#[cfg(any(test, feature = "testing"))]
pub fn advice_provider(&self) -> &A {
&self.adv_provider
}
#[cfg(any(test, feature = "testing"))]
pub fn advice_provider_mut(&mut self) -> &mut A {
&mut self.adv_provider
}
pub fn into_inner(self) -> A {
self.adv_provider
}
}
impl<A: AdviceProvider> Host for DefaultHost<A> {
type AdviceProvider = A;
fn advice_provider(&self) -> &Self::AdviceProvider {
&self.adv_provider
}
fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider {
&mut self.adv_provider
}
fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
self.store.get(node_digest)
}
fn on_event(
&mut self,
_process: ProcessState,
_event_id: u32,
_err_ctx: &ErrorContext<'_, impl MastNodeExt>,
) -> Result<(), ExecutionError> {
#[cfg(feature = "std")]
std::println!(
"Event with id {} emitted at step {} in context {}",
_event_id,
_process.clk(),
_process.ctx()
);
Ok(())
}
}