miden_testing/
executor.rs1use alloc::boxed::Box;
2
3#[cfg(test)]
4use miden_processor::DefaultHost;
5use miden_processor::advice::AdviceInputs;
6use miden_processor::{
7 ExecutionError,
8 ExecutionOptions,
9 ExecutionOutput,
10 FastProcessor,
11 Host,
12 Program,
13 StackInputs,
14};
15#[cfg(test)]
16use miden_protocol::assembly::Assembler;
17use miden_protocol::vm::{DebugSourceNodeId, Package, PackageDebugInfo};
18
19use crate::ExecError;
20
21pub(crate) struct CodeExecutor<H> {
26 host: H,
27 stack_inputs: Option<StackInputs>,
28 advice_inputs: AdviceInputs,
29 execution_options: Option<ExecutionOptions>,
30}
31
32impl<H: Host> CodeExecutor<H> {
33 pub(crate) fn new(host: H) -> Self {
36 Self {
37 host,
38 stack_inputs: None,
39 advice_inputs: AdviceInputs::default(),
40 execution_options: None,
41 }
42 }
43
44 pub fn extend_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
45 self.advice_inputs.extend(advice_inputs);
46 self
47 }
48
49 pub fn stack_inputs(mut self, stack_inputs: StackInputs) -> Self {
50 self.stack_inputs = Some(stack_inputs);
51 self
52 }
53
54 #[cfg(test)]
56 pub fn execution_options(mut self, options: ExecutionOptions) -> Self {
57 self.execution_options = Some(options);
58 self
59 }
60
61 #[cfg(test)]
63 pub async fn run(self, code: &str) -> Result<ExecutionOutput, ExecError> {
64 use alloc::borrow::ToOwned;
65 use alloc::sync::Arc;
66
67 use miden_protocol::assembly::debuginfo::{SourceLanguage, Uri};
68 use miden_protocol::assembly::{DefaultSourceManager, SourceManagerSync};
69 use miden_standards::code_builder::CodeBuilder;
70
71 let source_manager: Arc<dyn SourceManagerSync> = Arc::new(DefaultSourceManager::default());
72 let assembler: Assembler = CodeBuilder::with_kernel_library(source_manager.clone()).into();
73
74 let virtual_source_file =
76 source_manager.load(SourceLanguage::Masm, Uri::new("_user_code"), code.to_owned());
77 let package = assembler.assemble_program("tx-context-code", virtual_source_file).unwrap();
78
79 self.execute_package(package).await
80 }
81
82 pub async fn execute_package(
86 self,
87 package: impl Into<Box<Package>>,
88 ) -> Result<ExecutionOutput, ExecError> {
89 let package = package.into();
90 let package_debug_info = package.debug_info().ok().flatten();
91 let entrypoint_source_node = package.entrypoint_source_node();
92 let program = package.try_into_program().expect("package should be executable");
93
94 self.execute_program_with_package_debug_info(
95 program,
96 package_debug_info,
97 entrypoint_source_node,
98 )
99 .await
100 }
101
102 async fn execute_program_with_package_debug_info(
103 mut self,
104 program: Program,
105 package_debug_info: Option<PackageDebugInfo>,
106 entrypoint_source_node: Option<DebugSourceNodeId>,
107 ) -> Result<ExecutionOutput, ExecError> {
108 let stack_inputs = self.stack_inputs.unwrap_or_default();
109
110 let processor = FastProcessor::new(stack_inputs)
111 .with_advice(self.advice_inputs)
112 .map_err(ExecutionError::advice_error_no_context)
113 .map_err(ExecError::new)?
114 .with_options(self.execution_options.unwrap_or_default())
115 .map_err(ExecutionError::advice_error_no_context)
116 .map_err(ExecError::new)?;
117
118 let execution_output = match package_debug_info {
119 Some(package_debug_info) => match entrypoint_source_node {
120 Some(entrypoint_source_node) => {
121 processor
122 .execute_with_package_debug_info_at_source_node(
123 &program,
124 &package_debug_info,
125 entrypoint_source_node,
126 &mut self.host,
127 )
128 .await
129 },
130 None => {
131 processor
132 .execute_with_package_debug_info(
133 &program,
134 &package_debug_info,
135 &mut self.host,
136 )
137 .await
138 },
139 },
140 None => processor.execute(&program, &mut self.host).await,
141 }
142 .map_err(ExecError::new)?;
143
144 Ok(execution_output)
145 }
146}
147
148#[cfg(test)]
149impl CodeExecutor<DefaultHost> {
150 pub fn with_default_host() -> Self {
151 use miden_core_lib::CoreLibrary;
152 use miden_protocol::ProtocolLib;
153 use miden_protocol::transaction::TransactionKernel;
154 use miden_standards::StandardsLib;
155
156 let mut host = DefaultHost::default();
157
158 let core_lib = CoreLibrary::default();
159 host.load_library(core_lib.mast_forest()).unwrap();
160
161 let standards_lib = StandardsLib::default();
162 host.load_library(standards_lib.mast_forest()).unwrap();
163
164 let protocol_lib = ProtocolLib::default();
165 host.load_library(protocol_lib.mast_forest()).unwrap();
166
167 let kernel_lib = TransactionKernel::library();
168 host.load_library(kernel_lib.mast_forest()).unwrap();
169
170 CodeExecutor::new(host)
171 }
172}