use miden_core::{EventId, Felt, mast::MastForest, sys_events::SystemEvent};
use super::{super::ONE, ExecutionError, Process};
use crate::{
SyncHost, errors::ErrorContext, operations::sys_ops::sys_event_handlers::handle_system_event,
};
pub(crate) mod sys_event_handlers;
impl Process {
pub(super) fn op_assert<H>(
&mut self,
err_code: Felt,
program: &MastForest,
host: &mut H,
err_ctx: &impl ErrorContext,
) -> Result<(), ExecutionError>
where
H: SyncHost,
{
if self.stack.get(0) != ONE {
let process = &mut self.state();
host.on_assert_failed(process, err_code);
let err_msg = program.resolve_error_message(err_code);
return Err(ExecutionError::failed_assertion(
process.clk(),
err_code,
err_msg,
err_ctx,
));
}
self.stack.shift_left(1);
Ok(())
}
pub(super) fn op_sdepth(&mut self) -> Result<(), ExecutionError> {
let stack_depth = self.stack.depth();
self.stack.set(0, Felt::new(stack_depth as u64));
self.stack.shift_right(0);
Ok(())
}
pub(super) fn op_caller(&mut self) -> Result<(), ExecutionError> {
let fn_hash = self.system.fn_hash();
self.stack.set(0, fn_hash[3]);
self.stack.set(1, fn_hash[2]);
self.stack.set(2, fn_hash[1]);
self.stack.set(3, fn_hash[0]);
self.stack.copy_state(4);
Ok(())
}
pub(super) fn op_clk(&mut self) -> Result<(), ExecutionError> {
let clk = self.system.clk();
self.stack.set(0, Felt::from(clk));
self.stack.shift_right(0);
Ok(())
}
pub(super) fn op_emit<H>(
&mut self,
host: &mut H,
err_ctx: &impl ErrorContext,
) -> Result<(), ExecutionError>
where
H: SyncHost,
{
self.stack.copy_state(0);
let mut process = self.state();
let event_id = EventId::from_felt(process.get_stack_item(0));
if let Some(system_event) = SystemEvent::from_event_id(event_id) {
handle_system_event(&mut process, system_event, err_ctx)
} else {
let clk = process.clk();
let mutations = host.on_event(&process).map_err(|err| {
let event_name = host.resolve_event(event_id).cloned();
ExecutionError::event_error(err, event_id, event_name, err_ctx)
})?;
self.advice
.apply_mutations(mutations)
.map_err(|err| ExecutionError::advice_error(err, clk, err_ctx))?;
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use miden_core::mast::MastForest;
use super::{
super::{MIN_STACK_DEPTH, Operation},
Felt, Process,
};
use crate::{DefaultHost, ONE, ZERO};
#[test]
fn op_assert() {
let mut host = DefaultHost::default();
let mut process = Process::new_dummy_with_empty_stack();
let program = &MastForest::default();
process.execute_op(Operation::Push(ONE), program, &mut host).unwrap();
process.execute_op(Operation::Swap, program, &mut host).unwrap();
process.execute_op(Operation::Drop, program, &mut host).unwrap();
assert!(process.execute_op(Operation::Assert(ZERO), program, &mut host).is_ok());
}
#[test]
fn op_sdepth() {
let mut host = DefaultHost::default();
let mut process = Process::new_dummy_with_empty_stack();
let program = &MastForest::default();
process.execute_op(Operation::SDepth, program, &mut host).unwrap();
let expected = build_expected_stack(&[MIN_STACK_DEPTH as u64]);
assert_eq!(expected, process.stack.trace_state());
assert_eq!(MIN_STACK_DEPTH + 1, process.stack.depth());
process.execute_op(Operation::SDepth, program, &mut host).unwrap();
let expected = build_expected_stack(&[MIN_STACK_DEPTH as u64 + 1, MIN_STACK_DEPTH as u64]);
assert_eq!(expected, process.stack.trace_state());
assert_eq!(MIN_STACK_DEPTH + 2, process.stack.depth());
process.execute_op(Operation::Pad, program, &mut host).unwrap();
process.execute_op(Operation::SDepth, program, &mut host).unwrap();
let expected = build_expected_stack(&[
MIN_STACK_DEPTH as u64 + 3,
0,
MIN_STACK_DEPTH as u64 + 1,
MIN_STACK_DEPTH as u64,
]);
assert_eq!(expected, process.stack.trace_state());
assert_eq!(MIN_STACK_DEPTH + 4, process.stack.depth());
}
#[test]
fn op_clk() {
let mut host = DefaultHost::default();
let mut process = Process::new_dummy_with_empty_stack();
let program = &MastForest::default();
process.execute_op(Operation::Clk, program, &mut host).unwrap();
let expected = build_expected_stack(&[1]);
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::Push(Felt::new(2)), program, &mut host).unwrap();
process.execute_op(Operation::Clk, program, &mut host).unwrap();
let expected = build_expected_stack(&[3, 2, 1]);
assert_eq!(expected, process.stack.trace_state());
process.execute_op(Operation::Push(Felt::new(3)), program, &mut host).unwrap();
process.execute_op(Operation::Clk, program, &mut host).unwrap();
let expected = build_expected_stack(&[5, 3, 3, 2, 1]);
assert_eq!(expected, process.stack.trace_state());
}
fn build_expected_stack(values: &[u64]) -> [Felt; 16] {
let mut expected = [ZERO; 16];
for (&value, result) in values.iter().zip(expected.iter_mut()) {
*result = Felt::new(value);
}
expected
}
}