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