Skip to main content

sp1_core_executor/
minimal.rs

1#![allow(clippy::items_after_statements)]
2use std::sync::Arc;
3
4use crate::{Program, SupervisorMode, UserMode};
5pub use arch::*;
6pub use postprocess::chunked_memory_init_events;
7pub use sp1_jit::{MemValue, TraceChunkRaw};
8
9mod arch;
10mod debug;
11mod ecall;
12mod hint;
13mod postprocess;
14mod precompiles;
15mod write;
16
17#[cfg(test)]
18mod tests;
19
20/// Wrapper enum to handle `MinimalExecutor` with different execution modes at runtime.
21pub enum MinimalExecutorEnum {
22    /// `MinimalExecutor` for `SupervisorMode`.
23    Supervisor(MinimalExecutor<SupervisorMode>),
24    /// `MinimalExecutor` for `UserMode`.
25    User(MinimalExecutor<UserMode>),
26}
27
28impl MinimalExecutorEnum {
29    /// Create a new `MinimalExecutorEnum` based on program's `enable_untrusted_programs` flag.
30    #[must_use]
31    pub fn new(program: Arc<Program>, debug: bool, max_trace_entries: Option<u64>) -> Self {
32        if program.enable_untrusted_programs {
33            Self::User(MinimalExecutor::<UserMode>::new(program, debug, max_trace_entries))
34        } else {
35            Self::Supervisor(MinimalExecutor::<SupervisorMode>::new(
36                program,
37                debug,
38                max_trace_entries,
39            ))
40        }
41    }
42
43    /// Create a new `MinimalExecutorEnum` with memory limit (portable executor only).
44    #[cfg(sp1_use_portable_executor)]
45    #[must_use]
46    pub fn new_with_limit(
47        program: Arc<Program>,
48        debug: bool,
49        max_trace_size: Option<u64>,
50        memory_limit: Option<u64>,
51    ) -> Self {
52        if program.enable_untrusted_programs {
53            Self::User(MinimalExecutor::<UserMode>::new_with_limit(
54                program,
55                debug,
56                max_trace_size,
57                memory_limit,
58            ))
59        } else {
60            Self::Supervisor(MinimalExecutor::<SupervisorMode>::new_with_limit(
61                program,
62                debug,
63                max_trace_size,
64                memory_limit,
65            ))
66        }
67    }
68
69    /// Create a new `MinimalExecutorEnum` with memory limit (native executor fallback — ignores limit).
70    #[cfg(not(sp1_use_portable_executor))]
71    #[must_use]
72    pub fn new_with_limit(
73        program: Arc<Program>,
74        debug: bool,
75        max_trace_size: Option<u64>,
76        _memory_limit: Option<u64>,
77    ) -> Self {
78        Self::new(program, debug, max_trace_size)
79    }
80
81    /// Calls `with_input` to respective `MinimalExecutor`.
82    pub fn with_input(&mut self, input: &[u8]) {
83        match self {
84            Self::Supervisor(e) => e.with_input(input),
85            Self::User(e) => e.with_input(input),
86        }
87    }
88
89    /// Calls `execute_chunk` to respective `MinimalExecutor`.
90    pub fn execute_chunk(&mut self) -> Option<TraceChunkRaw> {
91        match self {
92            Self::Supervisor(e) => e.execute_chunk(),
93            Self::User(e) => e.execute_chunk(),
94        }
95    }
96
97    /// Calls `global_clk` to respective `MinimalExecutor`.
98    #[must_use]
99    pub fn global_clk(&self) -> u64 {
100        match self {
101            Self::Supervisor(e) => e.global_clk(),
102            Self::User(e) => e.global_clk(),
103        }
104    }
105
106    /// Calls `exit_code` to respective `MinimalExecutor`.
107    #[must_use]
108    pub fn exit_code(&self) -> u32 {
109        match self {
110            Self::Supervisor(e) => e.exit_code(),
111            Self::User(e) => e.exit_code(),
112        }
113    }
114
115    /// Calls `pc` to respective `MinimalExecutor`.
116    #[must_use]
117    pub fn pc(&self) -> u64 {
118        match self {
119            Self::Supervisor(e) => e.pc(),
120            Self::User(e) => e.pc(),
121        }
122    }
123
124    /// Calls `registers` to respective `MinimalExecutor`.
125    #[must_use]
126    pub fn registers(&self) -> [u64; 32] {
127        match self {
128            Self::Supervisor(e) => e.registers(),
129            Self::User(e) => e.registers(),
130        }
131    }
132
133    /// Calls `clk` to respective `MinimalExecutor`.
134    #[must_use]
135    pub fn clk(&self) -> u64 {
136        match self {
137            Self::Supervisor(e) => e.clk(),
138            Self::User(e) => e.clk(),
139        }
140    }
141
142    /// Calls `public_values_stream` to respective `MinimalExecutor`.
143    #[must_use]
144    pub fn public_values_stream(&self) -> &Vec<u8> {
145        match self {
146            Self::Supervisor(e) => e.public_values_stream(),
147            Self::User(e) => e.public_values_stream(),
148        }
149    }
150
151    /// Calls `into_public_values_stream` to respective `MinimalExecutor`.
152    #[must_use]
153    pub fn into_public_values_stream(self) -> Vec<u8> {
154        match self {
155            Self::Supervisor(e) => e.into_public_values_stream(),
156            Self::User(e) => e.into_public_values_stream(),
157        }
158    }
159
160    /// Calls `public_value_digest` to respective `MinimalExecutor`.
161    #[must_use]
162    pub fn public_value_digest(&self) -> [u32; sp1_jit::PUBLIC_VALUE_DIGEST_WORDS] {
163        match self {
164            Self::Supervisor(e) => e.public_value_digest(),
165            Self::User(e) => e.public_value_digest(),
166        }
167    }
168
169    /// Calls `hints` to respective `MinimalExecutor`.
170    #[must_use]
171    pub fn hints(&self) -> &[(u64, Vec<u8>)] {
172        match self {
173            Self::Supervisor(e) => e.hints(),
174            Self::User(e) => e.hints(),
175        }
176    }
177
178    /// Calls `hint_lens` to respective `MinimalExecutor`.
179    #[must_use]
180    pub fn hint_lens(&self) -> Vec<usize> {
181        match self {
182            Self::Supervisor(e) => e.hint_lens(),
183            Self::User(e) => e.hint_lens(),
184        }
185    }
186
187    /// Calls `get_memory_value` to respective `MinimalExecutor`.
188    #[must_use]
189    pub fn get_memory_value(&self, addr: u64) -> MemValue {
190        match self {
191            Self::Supervisor(e) => e.get_memory_value(addr),
192            Self::User(e) => e.get_memory_value(addr),
193        }
194    }
195
196    /// Calls `is_done` to respective `MinimalExecutor`.
197    #[must_use]
198    pub fn is_done(&self) -> bool {
199        match self {
200            Self::Supervisor(e) => e.is_done(),
201            Self::User(e) => e.is_done(),
202        }
203    }
204
205    /// Calls `program` to respective `MinimalExecutor`.
206    #[must_use]
207    pub fn program(&self) -> Arc<Program> {
208        match self {
209            Self::Supervisor(e) => e.program(),
210            Self::User(e) => e.program(),
211        }
212    }
213
214    /// Calls `unsafe_memory` to respective `MinimalExecutor`.
215    #[must_use]
216    pub fn unsafe_memory(&self) -> UnsafeMemory {
217        match self {
218            Self::Supervisor(e) => e.unsafe_memory(),
219            Self::User(e) => e.unsafe_memory(),
220        }
221    }
222
223    /// Calls `reset` to respective `MinimalExecutor`.
224    pub fn reset(&mut self) {
225        match self {
226            Self::Supervisor(e) => e.reset(),
227            Self::User(e) => e.reset(),
228        }
229    }
230
231    /// Calls `try_execute_chunk` to respective `MinimalExecutor` (portable executor only).
232    #[cfg(sp1_use_portable_executor)]
233    pub fn try_execute_chunk(&mut self) -> Result<Option<TraceChunkRaw>, crate::ExecutionError> {
234        match self {
235            Self::Supervisor(e) => e.try_execute_chunk(),
236            Self::User(e) => e.try_execute_chunk(),
237        }
238    }
239
240    /// Calls `try_execute_chunk` (native executor fallback — infallible).
241    #[cfg(not(sp1_use_portable_executor))]
242    pub fn try_execute_chunk(&mut self) -> Result<Option<TraceChunkRaw>, crate::ExecutionError> {
243        Ok(self.execute_chunk())
244    }
245
246    /// Calls `get_page_prot_record` to respective `MinimalExecutor`.
247    #[must_use]
248    pub fn get_page_prot_record(&self, page_idx: u64) -> Option<sp1_jit::PageProtValue> {
249        match self {
250            Self::Supervisor(e) => e.get_page_prot_record(page_idx),
251            Self::User(e) => e.get_page_prot_record(page_idx),
252        }
253    }
254
255    /// Take the cycle tracker totals, consuming them.
256    #[cfg(feature = "profiling")]
257    #[must_use]
258    pub fn take_cycle_tracker_totals(&mut self) -> hashbrown::HashMap<String, u64> {
259        match self {
260            Self::Supervisor(e) => e.take_cycle_tracker_totals(),
261            Self::User(e) => e.take_cycle_tracker_totals(),
262        }
263    }
264
265    /// Take the invocation tracker, consuming it.
266    #[cfg(feature = "profiling")]
267    #[must_use]
268    pub fn take_invocation_tracker(&mut self) -> hashbrown::HashMap<String, u64> {
269        match self {
270            Self::Supervisor(e) => e.take_invocation_tracker(),
271            Self::User(e) => e.take_invocation_tracker(),
272        }
273    }
274}