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