use super::{ExecutionError, Felt, ProcessState};
use crate::MemAdviceProvider;
use vm_core::{crypto::merkle::MerklePath, AdviceInjector, DebugOptions, Word};
pub(super) mod advice;
use advice::{AdviceExtractor, AdviceProvider};
#[cfg(feature = "std")]
mod debug;
pub trait Host {
fn get_advice<S: ProcessState>(
&mut self,
process: &S,
extractor: AdviceExtractor,
) -> Result<HostResponse, ExecutionError>;
fn set_advice<S: ProcessState>(
&mut self,
process: &S,
injector: AdviceInjector,
) -> Result<HostResponse, ExecutionError>;
fn by_ref(&mut self) -> &mut Self {
self
}
fn on_event<S: ProcessState>(
&mut self,
process: &S,
event_id: u32,
) -> Result<HostResponse, ExecutionError> {
#[cfg(feature = "std")]
std::println!(
"Event with id {} emitted at step {} in context {}",
event_id,
process.clk(),
process.ctx()
);
Ok(HostResponse::None)
}
fn on_debug<S: ProcessState>(
&mut self,
process: &S,
options: &DebugOptions,
) -> Result<HostResponse, ExecutionError> {
#[cfg(feature = "std")]
debug::print_debug_info(process, options);
Ok(HostResponse::None)
}
fn on_trace<S: ProcessState>(
&mut self,
process: &S,
trace_id: u32,
) -> Result<HostResponse, ExecutionError> {
#[cfg(feature = "std")]
std::println!(
"Trace with id {} emitted at step {} in context {}",
trace_id,
process.clk(),
process.ctx()
);
Ok(HostResponse::None)
}
fn on_assert_failed<S: ProcessState>(&mut self, process: &S, err_code: u32) -> ExecutionError {
ExecutionError::FailedAssertion {
clk: process.clk(),
err_code,
err_msg: None,
}
}
fn pop_adv_stack<S: ProcessState>(&mut self, process: &S) -> Result<Felt, ExecutionError> {
let response = self.get_advice(process, AdviceExtractor::PopStack)?;
Ok(response.into())
}
fn pop_adv_stack_word<S: ProcessState>(&mut self, process: &S) -> Result<Word, ExecutionError> {
let response = self.get_advice(process, AdviceExtractor::PopStackWord)?;
Ok(response.into())
}
fn pop_adv_stack_dword<S: ProcessState>(
&mut self,
process: &S,
) -> Result<[Word; 2], ExecutionError> {
let response = self.get_advice(process, AdviceExtractor::PopStackDWord)?;
Ok(response.into())
}
fn get_adv_merkle_path<S: ProcessState>(
&mut self,
process: &S,
) -> Result<MerklePath, ExecutionError> {
let response = self.get_advice(process, AdviceExtractor::GetMerklePath)?;
Ok(response.into())
}
}
impl<'a, H> Host for &'a mut H
where
H: Host,
{
fn get_advice<S: ProcessState>(
&mut self,
process: &S,
extractor: AdviceExtractor,
) -> Result<HostResponse, ExecutionError> {
H::get_advice(self, process, extractor)
}
fn set_advice<S: ProcessState>(
&mut self,
process: &S,
injector: AdviceInjector,
) -> Result<HostResponse, ExecutionError> {
H::set_advice(self, process, injector)
}
fn on_debug<S: ProcessState>(
&mut self,
process: &S,
options: &DebugOptions,
) -> Result<HostResponse, ExecutionError> {
H::on_debug(self, process, options)
}
fn on_event<S: ProcessState>(
&mut self,
process: &S,
event_id: u32,
) -> Result<HostResponse, ExecutionError> {
H::on_event(self, process, event_id)
}
fn on_trace<S: ProcessState>(
&mut self,
process: &S,
trace_id: u32,
) -> Result<HostResponse, ExecutionError> {
H::on_trace(self, process, trace_id)
}
fn on_assert_failed<S: ProcessState>(&mut self, process: &S, err_code: u32) -> ExecutionError {
H::on_assert_failed(self, process, err_code)
}
}
#[derive(Debug)]
pub enum HostResponse {
MerklePath(MerklePath),
DoubleWord([Word; 2]),
Word(Word),
Element(Felt),
None,
}
impl From<HostResponse> for MerklePath {
fn from(response: HostResponse) -> Self {
match response {
HostResponse::MerklePath(path) => path,
_ => panic!("expected MerklePath, but got {:?}", response),
}
}
}
impl From<HostResponse> for Word {
fn from(response: HostResponse) -> Self {
match response {
HostResponse::Word(word) => word,
_ => panic!("expected Word, but got {:?}", response),
}
}
}
impl From<HostResponse> for [Word; 2] {
fn from(response: HostResponse) -> Self {
match response {
HostResponse::DoubleWord(word) => word,
_ => panic!("expected DoubleWord, but got {:?}", response),
}
}
}
impl From<HostResponse> for Felt {
fn from(response: HostResponse) -> Self {
match response {
HostResponse::Element(element) => element,
_ => panic!("expected Element, but got {:?}", response),
}
}
}
pub struct DefaultHost<A> {
adv_provider: A,
}
impl Default for DefaultHost<MemAdviceProvider> {
fn default() -> Self {
Self {
adv_provider: MemAdviceProvider::default(),
}
}
}
impl<A: AdviceProvider> DefaultHost<A> {
pub fn new(adv_provider: A) -> Self {
Self { adv_provider }
}
#[cfg(any(test, feature = "internals"))]
pub fn advice_provider(&self) -> &A {
&self.adv_provider
}
#[cfg(any(test, feature = "internals"))]
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> {
fn get_advice<S: ProcessState>(
&mut self,
process: &S,
extractor: AdviceExtractor,
) -> Result<HostResponse, ExecutionError> {
self.adv_provider.get_advice(process, &extractor)
}
fn set_advice<S: ProcessState>(
&mut self,
process: &S,
injector: AdviceInjector,
) -> Result<HostResponse, ExecutionError> {
self.adv_provider.set_advice(process, &injector)
}
}