1use miden_air::trace::MIN_TRACE_LEN;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct ExecutionOptions {
12 max_cycles: u32,
13 expected_cycles: u32,
14 core_trace_fragment_size: usize,
15 enable_tracing: bool,
16 enable_debugging: bool,
17 max_adv_map_value_size: usize,
20 max_hash_len_bytes: usize,
22 max_num_continuations: usize,
25}
26
27impl Default for ExecutionOptions {
28 fn default() -> Self {
29 ExecutionOptions {
30 max_cycles: Self::MAX_CYCLES,
31 expected_cycles: MIN_TRACE_LEN as u32,
32 core_trace_fragment_size: Self::DEFAULT_CORE_TRACE_FRAGMENT_SIZE,
33 enable_tracing: false,
34 enable_debugging: false,
35 max_adv_map_value_size: Self::DEFAULT_MAX_ADV_MAP_VALUE_SIZE,
36 max_hash_len_bytes: Self::DEFAULT_MAX_HASH_LEN_BYTES,
37 max_num_continuations: Self::DEFAULT_MAX_NUM_CONTINUATIONS,
38 }
39 }
40}
41
42impl ExecutionOptions {
43 pub const MAX_CYCLES: u32 = 1 << 29;
48
49 pub const DEFAULT_CORE_TRACE_FRAGMENT_SIZE: usize = 4096; pub const DEFAULT_MAX_ADV_MAP_VALUE_SIZE: usize = 1 << 17;
55
56 pub const DEFAULT_MAX_HASH_LEN_BYTES: usize = 1 << 20;
59
60 pub const DEFAULT_MAX_NUM_CONTINUATIONS: usize = 1 << 16;
63
64 pub fn new(
77 max_cycles: Option<u32>,
78 expected_cycles: u32,
79 core_trace_fragment_size: usize,
80 enable_tracing: bool,
81 enable_debugging: bool,
82 ) -> Result<Self, ExecutionOptionsError> {
83 let max_cycles = if let Some(max_cycles) = max_cycles {
85 if max_cycles > Self::MAX_CYCLES {
86 return Err(ExecutionOptionsError::MaxCycleNumTooBig {
87 max_cycles,
88 max_cycles_limit: Self::MAX_CYCLES,
89 });
90 }
91 if max_cycles < MIN_TRACE_LEN as u32 {
92 return Err(ExecutionOptionsError::MaxCycleNumTooSmall {
93 max_cycles,
94 min_cycles_limit: MIN_TRACE_LEN,
95 });
96 }
97 max_cycles
98 } else {
99 Self::MAX_CYCLES
100 };
101 let expected_cycles = expected_cycles.next_power_of_two().max(MIN_TRACE_LEN as u32);
104 if max_cycles < expected_cycles {
106 return Err(ExecutionOptionsError::ExpectedCyclesTooBig {
107 max_cycles,
108 expected_cycles,
109 });
110 }
111
112 if core_trace_fragment_size == 0 {
114 return Err(ExecutionOptionsError::CoreTraceFragmentSizeTooSmall);
115 }
116
117 Ok(ExecutionOptions {
118 max_cycles,
119 expected_cycles,
120 core_trace_fragment_size,
121 enable_tracing,
122 enable_debugging,
123 max_adv_map_value_size: Self::DEFAULT_MAX_ADV_MAP_VALUE_SIZE,
124 max_hash_len_bytes: Self::DEFAULT_MAX_HASH_LEN_BYTES,
125 max_num_continuations: Self::DEFAULT_MAX_NUM_CONTINUATIONS,
126 })
127 }
128
129 pub fn with_core_trace_fragment_size(
133 mut self,
134 size: usize,
135 ) -> Result<Self, ExecutionOptionsError> {
136 if size == 0 {
137 return Err(ExecutionOptionsError::CoreTraceFragmentSizeTooSmall);
138 }
139 self.core_trace_fragment_size = size;
140 Ok(self)
141 }
142
143 pub fn with_tracing(mut self, enable_tracing: bool) -> Self {
145 self.enable_tracing = enable_tracing;
146 self
147 }
148
149 pub fn with_debugging(mut self, enable_debugging: bool) -> Self {
157 self.enable_debugging = enable_debugging;
158 self
159 }
160
161 #[inline(always)]
166 pub fn max_cycles(&self) -> u32 {
167 self.max_cycles
168 }
169
170 pub fn expected_cycles(&self) -> u32 {
176 self.expected_cycles
177 }
178
179 pub fn core_trace_fragment_size(&self) -> usize {
181 self.core_trace_fragment_size
182 }
183
184 #[inline]
186 pub fn enable_tracing(&self) -> bool {
187 self.enable_tracing
188 }
189
190 #[inline]
192 pub fn enable_debugging(&self) -> bool {
193 self.enable_debugging
194 }
195
196 #[inline]
199 pub fn max_adv_map_value_size(&self) -> usize {
200 self.max_adv_map_value_size
201 }
202
203 #[inline]
205 pub fn max_hash_len_bytes(&self) -> usize {
206 self.max_hash_len_bytes
207 }
208
209 pub fn with_max_adv_map_value_size(mut self, size: usize) -> Self {
212 self.max_adv_map_value_size = size;
213 self
214 }
215
216 pub fn with_max_hash_len_bytes(mut self, size: usize) -> Self {
218 self.max_hash_len_bytes = size;
219 self
220 }
221
222 #[inline]
224 pub fn max_num_continuations(&self) -> usize {
225 self.max_num_continuations
226 }
227
228 pub fn with_max_num_continuations(mut self, max_num_continuations: usize) -> Self {
230 self.max_num_continuations = max_num_continuations;
231 self
232 }
233}
234
235#[derive(Debug, thiserror::Error)]
239pub enum ExecutionOptionsError {
240 #[error(
241 "expected number of cycles {expected_cycles} must be smaller than the maximum number of cycles {max_cycles}"
242 )]
243 ExpectedCyclesTooBig { max_cycles: u32, expected_cycles: u32 },
244 #[error("maximum number of cycles {max_cycles} must be greater than {min_cycles_limit}")]
245 MaxCycleNumTooSmall { max_cycles: u32, min_cycles_limit: usize },
246 #[error("maximum number of cycles {max_cycles} must be less than {max_cycles_limit}")]
247 MaxCycleNumTooBig { max_cycles: u32, max_cycles_limit: u32 },
248 #[error("core trace fragment size must be greater than 0")]
249 CoreTraceFragmentSizeTooSmall,
250}
251
252#[cfg(test)]
256mod tests {
257 use super::*;
258
259 #[test]
260 fn valid_fragment_size() {
261 let opts = ExecutionOptions::new(None, 64, 1024, false, false);
263 assert!(opts.is_ok());
264 assert_eq!(opts.unwrap().core_trace_fragment_size(), 1024);
265
266 let opts = ExecutionOptions::new(None, 64, 4096, false, false);
267 assert!(opts.is_ok());
268
269 let opts = ExecutionOptions::new(None, 64, 1, false, false);
270 assert!(opts.is_ok());
271 }
272
273 #[test]
274 fn zero_fragment_size_fails() {
275 let opts = ExecutionOptions::new(None, 64, 0, false, false);
276 assert!(matches!(opts, Err(ExecutionOptionsError::CoreTraceFragmentSizeTooSmall)));
277 }
278
279 #[test]
280 fn with_core_trace_fragment_size_validates() {
281 let result = ExecutionOptions::default().with_core_trace_fragment_size(2048);
283 assert!(result.is_ok());
284 assert_eq!(result.unwrap().core_trace_fragment_size(), 2048);
285
286 let result = ExecutionOptions::default().with_core_trace_fragment_size(0);
288 assert!(matches!(result, Err(ExecutionOptionsError::CoreTraceFragmentSizeTooSmall)));
289 }
290
291 #[test]
292 fn expected_cycles_validated_after_rounding() {
293 let opts = ExecutionOptions::new(Some(100), 65, 1024, false, false);
295 assert!(matches!(
296 opts,
297 Err(ExecutionOptionsError::ExpectedCyclesTooBig {
298 max_cycles: 100,
299 expected_cycles: 128
300 })
301 ));
302
303 let opts = ExecutionOptions::new(Some(100), 64, 1024, false, false);
305 assert!(opts.is_ok());
306 assert_eq!(opts.unwrap().expected_cycles(), 64);
307 }
308}