miden_testing/
executor.rs1#[cfg(test)]
2use miden_processor::DefaultHost;
3use miden_processor::advice::AdviceInputs;
4use miden_processor::{
5 ExecutionError,
6 ExecutionOptions,
7 ExecutionOutput,
8 FastProcessor,
9 Host,
10 Program,
11 StackInputs,
12};
13#[cfg(test)]
14use miden_protocol::assembly::Assembler;
15
16use crate::ExecError;
17
18pub(crate) struct CodeExecutor<H> {
23 host: H,
24 stack_inputs: Option<StackInputs>,
25 advice_inputs: AdviceInputs,
26 execution_options: Option<ExecutionOptions>,
27}
28
29impl<H: Host> CodeExecutor<H> {
30 pub(crate) fn new(host: H) -> Self {
33 Self {
34 host,
35 stack_inputs: None,
36 advice_inputs: AdviceInputs::default(),
37 execution_options: None,
38 }
39 }
40
41 pub fn extend_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
42 self.advice_inputs.extend(advice_inputs);
43 self
44 }
45
46 pub fn stack_inputs(mut self, stack_inputs: StackInputs) -> Self {
47 self.stack_inputs = Some(stack_inputs);
48 self
49 }
50
51 #[cfg(test)]
53 pub fn execution_options(mut self, options: ExecutionOptions) -> Self {
54 self.execution_options = Some(options);
55 self
56 }
57
58 #[cfg(test)]
60 pub async fn run(self, code: &str) -> Result<ExecutionOutput, ExecError> {
61 use alloc::borrow::ToOwned;
62 use alloc::sync::Arc;
63
64 use miden_protocol::assembly::debuginfo::{SourceLanguage, Uri};
65 use miden_protocol::assembly::{DefaultSourceManager, SourceManagerSync};
66 use miden_standards::code_builder::CodeBuilder;
67
68 let source_manager: Arc<dyn SourceManagerSync> = Arc::new(DefaultSourceManager::default());
69 let assembler: Assembler = CodeBuilder::with_kernel_library(source_manager.clone()).into();
70
71 let virtual_source_file =
73 source_manager.load(SourceLanguage::Masm, Uri::new("_user_code"), code.to_owned());
74 let program = assembler.assemble_program(virtual_source_file).unwrap();
75
76 self.execute_program(program).await
77 }
78
79 pub async fn execute_program(mut self, program: Program) -> Result<ExecutionOutput, ExecError> {
84 let stack_inputs = self.stack_inputs.unwrap_or_default();
85
86 let processor = FastProcessor::new(stack_inputs)
87 .with_advice(self.advice_inputs)
88 .map_err(ExecutionError::advice_error_no_context)
89 .map_err(ExecError::new)?
90 .with_options(self.execution_options.unwrap_or_default())
91 .map_err(ExecutionError::advice_error_no_context)
92 .map_err(ExecError::new)?
93 .with_debugging(true);
94
95 let execution_output =
96 processor.execute(&program, &mut self.host).await.map_err(ExecError::new)?;
97
98 Ok(execution_output)
99 }
100}
101
102#[cfg(test)]
103impl CodeExecutor<DefaultHost> {
104 pub fn with_default_host() -> Self {
105 use miden_core_lib::CoreLibrary;
106 use miden_protocol::ProtocolLib;
107 use miden_protocol::transaction::TransactionKernel;
108 use miden_standards::StandardsLib;
109
110 let mut host = DefaultHost::default();
111
112 let core_lib = CoreLibrary::default();
113 host.load_library(core_lib.mast_forest()).unwrap();
114
115 let standards_lib = StandardsLib::default();
116 host.load_library(standards_lib.mast_forest()).unwrap();
117
118 let protocol_lib = ProtocolLib::default();
119 host.load_library(protocol_lib.mast_forest()).unwrap();
120
121 let kernel_lib = TransactionKernel::library();
122 host.load_library(kernel_lib.mast_forest()).unwrap();
123
124 CodeExecutor::new(host)
125 }
126}