1use crate::primitives::{HaltReason, OutOfGasError, SuccessReason};
2
3#[repr(u8)]
4#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub enum InstructionResult {
7 #[default]
9 Continue = 0x00,
11 Stop,
13 Return,
15 SelfDestruct,
17 ReturnContract,
19
20 Revert = 0x10,
23 CallTooDeep,
25 OutOfFunds,
27 CreateInitCodeStartingEF00,
29 InvalidEOFInitCode,
31 InvalidExtDelegateCallTarget,
33
34 CallOrCreate = 0x20,
37
38 OutOfGas = 0x50,
41 MemoryOOG,
43 MemoryLimitOOG,
45 PrecompileOOG,
47 InvalidOperandOOG,
49 OpcodeNotFound,
51 CallNotAllowedInsideStatic,
53 StateChangeDuringStaticCall,
55 InvalidFEOpcode,
57 InvalidJump,
59 NotActivated,
61 StackUnderflow,
63 StackOverflow,
65 OutOfOffset,
67 CreateCollision,
69 OverflowPayment,
71 PrecompileError,
73 NonceOverflow,
75 CreateContractSizeLimit,
77 CreateContractStartingWithEF,
79 CreateInitCodeSizeLimit,
81 FatalExternalError,
83 ReturnContractInNotInitEOF,
85 EOFOpcodeDisabledInLegacy,
87 EOFFunctionStackOverflow,
89 EofAuxDataOverflow,
91 EofAuxDataTooSmall,
93 InvalidEXTCALLTarget,
95}
96
97impl From<SuccessReason> for InstructionResult {
98 fn from(value: SuccessReason) -> Self {
99 match value {
100 SuccessReason::Return => InstructionResult::Return,
101 SuccessReason::Stop => InstructionResult::Stop,
102 SuccessReason::SelfDestruct => InstructionResult::SelfDestruct,
103 SuccessReason::EofReturnContract => InstructionResult::ReturnContract,
104 }
105 }
106}
107
108impl From<HaltReason> for InstructionResult {
109 fn from(value: HaltReason) -> Self {
110 match value {
111 HaltReason::OutOfGas(error) => match error {
112 OutOfGasError::Basic => Self::OutOfGas,
113 OutOfGasError::InvalidOperand => Self::InvalidOperandOOG,
114 OutOfGasError::Memory => Self::MemoryOOG,
115 OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
116 OutOfGasError::Precompile => Self::PrecompileOOG,
117 },
118 HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
119 HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
120 HaltReason::InvalidJump => Self::InvalidJump,
121 HaltReason::NotActivated => Self::NotActivated,
122 HaltReason::StackOverflow => Self::StackOverflow,
123 HaltReason::StackUnderflow => Self::StackUnderflow,
124 HaltReason::OutOfOffset => Self::OutOfOffset,
125 HaltReason::CreateCollision => Self::CreateCollision,
126 HaltReason::PrecompileError => Self::PrecompileError,
127 HaltReason::NonceOverflow => Self::NonceOverflow,
128 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
129 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
130 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
131 HaltReason::OverflowPayment => Self::OverflowPayment,
132 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
133 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
134 HaltReason::OutOfFunds => Self::OutOfFunds,
135 HaltReason::CallTooDeep => Self::CallTooDeep,
136 HaltReason::EofAuxDataOverflow => Self::EofAuxDataOverflow,
137 HaltReason::EofAuxDataTooSmall => Self::EofAuxDataTooSmall,
138 HaltReason::EOFFunctionStackOverflow => Self::EOFFunctionStackOverflow,
139 HaltReason::InvalidEXTCALLTarget => Self::InvalidEXTCALLTarget,
140 #[cfg(feature = "optimism")]
141 HaltReason::FailedDeposit => Self::FatalExternalError,
142 }
143 }
144}
145
146#[macro_export]
147macro_rules! return_ok {
148 () => {
149 InstructionResult::Continue
150 | InstructionResult::Stop
151 | InstructionResult::Return
152 | InstructionResult::SelfDestruct
153 | InstructionResult::ReturnContract
154 };
155}
156
157#[macro_export]
158macro_rules! return_revert {
159 () => {
160 InstructionResult::Revert
161 | InstructionResult::CallTooDeep
162 | InstructionResult::OutOfFunds
163 | InstructionResult::InvalidEOFInitCode
164 | InstructionResult::CreateInitCodeStartingEF00
165 | InstructionResult::InvalidExtDelegateCallTarget
166 };
167}
168
169#[macro_export]
170macro_rules! return_error {
171 () => {
172 InstructionResult::OutOfGas
173 | InstructionResult::MemoryOOG
174 | InstructionResult::MemoryLimitOOG
175 | InstructionResult::PrecompileOOG
176 | InstructionResult::InvalidOperandOOG
177 | InstructionResult::OpcodeNotFound
178 | InstructionResult::CallNotAllowedInsideStatic
179 | InstructionResult::StateChangeDuringStaticCall
180 | InstructionResult::InvalidFEOpcode
181 | InstructionResult::InvalidJump
182 | InstructionResult::NotActivated
183 | InstructionResult::StackUnderflow
184 | InstructionResult::StackOverflow
185 | InstructionResult::OutOfOffset
186 | InstructionResult::CreateCollision
187 | InstructionResult::OverflowPayment
188 | InstructionResult::PrecompileError
189 | InstructionResult::NonceOverflow
190 | InstructionResult::CreateContractSizeLimit
191 | InstructionResult::CreateContractStartingWithEF
192 | InstructionResult::CreateInitCodeSizeLimit
193 | InstructionResult::FatalExternalError
194 | InstructionResult::ReturnContractInNotInitEOF
195 | InstructionResult::EOFOpcodeDisabledInLegacy
196 | InstructionResult::EOFFunctionStackOverflow
197 | InstructionResult::EofAuxDataTooSmall
198 | InstructionResult::EofAuxDataOverflow
199 | InstructionResult::InvalidEXTCALLTarget
200 };
201}
202
203impl InstructionResult {
204 #[inline]
206 pub const fn is_ok(self) -> bool {
207 matches!(self, crate::return_ok!())
208 }
209
210 #[inline]
212 pub const fn is_revert(self) -> bool {
213 matches!(self, crate::return_revert!())
214 }
215
216 #[inline]
218 pub const fn is_error(self) -> bool {
219 matches!(self, return_error!())
220 }
221}
222
223#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
225pub enum InternalResult {
226 InternalContinue,
228 InternalCallOrCreate,
230 CreateInitCodeStartingEF00,
232 InvalidExtDelegateCallTarget,
234}
235
236#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
237pub enum SuccessOrHalt {
238 Success(SuccessReason),
239 Revert,
240 Halt(HaltReason),
241 FatalExternalError,
242 Internal(InternalResult),
243}
244
245impl SuccessOrHalt {
246 #[inline]
248 pub fn is_success(self) -> bool {
249 matches!(self, SuccessOrHalt::Success(_))
250 }
251
252 #[inline]
254 pub fn to_success(self) -> Option<SuccessReason> {
255 match self {
256 SuccessOrHalt::Success(reason) => Some(reason),
257 _ => None,
258 }
259 }
260
261 #[inline]
263 pub fn is_revert(self) -> bool {
264 matches!(self, SuccessOrHalt::Revert)
265 }
266
267 #[inline]
269 pub fn is_halt(self) -> bool {
270 matches!(self, SuccessOrHalt::Halt(_))
271 }
272
273 #[inline]
275 pub fn to_halt(self) -> Option<HaltReason> {
276 match self {
277 SuccessOrHalt::Halt(reason) => Some(reason),
278 _ => None,
279 }
280 }
281}
282
283impl From<InstructionResult> for SuccessOrHalt {
284 fn from(result: InstructionResult) -> Self {
285 match result {
286 InstructionResult::Continue => Self::Internal(InternalResult::InternalContinue), InstructionResult::Stop => Self::Success(SuccessReason::Stop),
288 InstructionResult::Return => Self::Success(SuccessReason::Return),
289 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
290 InstructionResult::Revert => Self::Revert,
291 InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
292 InstructionResult::CallOrCreate => Self::Internal(InternalResult::InternalCallOrCreate), InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds), InstructionResult::OutOfGas => Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic)),
296 InstructionResult::MemoryLimitOOG => {
297 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit))
298 }
299 InstructionResult::MemoryOOG => Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory)),
300 InstructionResult::PrecompileOOG => {
301 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile))
302 }
303 InstructionResult::InvalidOperandOOG => {
304 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand))
305 }
306 InstructionResult::OpcodeNotFound | InstructionResult::ReturnContractInNotInitEOF => {
307 Self::Halt(HaltReason::OpcodeNotFound)
308 }
309 InstructionResult::CallNotAllowedInsideStatic => {
310 Self::Halt(HaltReason::CallNotAllowedInsideStatic)
311 } InstructionResult::StateChangeDuringStaticCall => {
313 Self::Halt(HaltReason::StateChangeDuringStaticCall)
314 }
315 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode),
316 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump),
317 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated),
318 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow),
319 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow),
320 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset),
321 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision),
322 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError),
324 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow),
325 InstructionResult::CreateContractSizeLimit
326 | InstructionResult::CreateContractStartingWithEF => {
327 Self::Halt(HaltReason::CreateContractSizeLimit)
328 }
329 InstructionResult::CreateInitCodeSizeLimit => {
330 Self::Halt(HaltReason::CreateInitCodeSizeLimit)
331 }
332 InstructionResult::InvalidEOFInitCode => Self::Revert,
334 InstructionResult::FatalExternalError => Self::FatalExternalError,
335 InstructionResult::EOFOpcodeDisabledInLegacy => Self::Halt(HaltReason::OpcodeNotFound),
336 InstructionResult::EOFFunctionStackOverflow => {
337 Self::Halt(HaltReason::EOFFunctionStackOverflow)
338 }
339 InstructionResult::ReturnContract => Self::Success(SuccessReason::EofReturnContract),
340 InstructionResult::EofAuxDataOverflow => Self::Halt(HaltReason::EofAuxDataOverflow),
341 InstructionResult::EofAuxDataTooSmall => Self::Halt(HaltReason::EofAuxDataTooSmall),
342 InstructionResult::InvalidEXTCALLTarget => Self::Halt(HaltReason::InvalidEXTCALLTarget),
343 InstructionResult::InvalidExtDelegateCallTarget => {
344 Self::Internal(InternalResult::InvalidExtDelegateCallTarget)
345 }
346 }
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use crate::InstructionResult;
353
354 #[test]
355 fn all_results_are_covered() {
356 match InstructionResult::Continue {
357 return_error!() => {}
358 return_revert!() => {}
359 return_ok!() => {}
360 InstructionResult::CallOrCreate => {}
361 }
362 }
363
364 #[test]
365 fn test_results() {
366 let ok_results = vec![
367 InstructionResult::Continue,
368 InstructionResult::Stop,
369 InstructionResult::Return,
370 InstructionResult::SelfDestruct,
371 ];
372
373 for result in ok_results {
374 assert!(result.is_ok());
375 assert!(!result.is_revert());
376 assert!(!result.is_error());
377 }
378
379 let revert_results = vec![
380 InstructionResult::Revert,
381 InstructionResult::CallTooDeep,
382 InstructionResult::OutOfFunds,
383 ];
384
385 for result in revert_results {
386 assert!(!result.is_ok());
387 assert!(result.is_revert());
388 assert!(!result.is_error());
389 }
390
391 let error_results = vec![
392 InstructionResult::OutOfGas,
393 InstructionResult::MemoryOOG,
394 InstructionResult::MemoryLimitOOG,
395 InstructionResult::PrecompileOOG,
396 InstructionResult::InvalidOperandOOG,
397 InstructionResult::OpcodeNotFound,
398 InstructionResult::CallNotAllowedInsideStatic,
399 InstructionResult::StateChangeDuringStaticCall,
400 InstructionResult::InvalidFEOpcode,
401 InstructionResult::InvalidJump,
402 InstructionResult::NotActivated,
403 InstructionResult::StackUnderflow,
404 InstructionResult::StackOverflow,
405 InstructionResult::OutOfOffset,
406 InstructionResult::CreateCollision,
407 InstructionResult::OverflowPayment,
408 InstructionResult::PrecompileError,
409 InstructionResult::NonceOverflow,
410 InstructionResult::CreateContractSizeLimit,
411 InstructionResult::CreateContractStartingWithEF,
412 InstructionResult::CreateInitCodeSizeLimit,
413 InstructionResult::FatalExternalError,
414 ];
415
416 for result in error_results {
417 assert!(!result.is_ok());
418 assert!(!result.is_revert());
419 assert!(result.is_error());
420 }
421 }
422}