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 InstructionResult {}
114
115impl From<SuccessReason> for InstructionResult {
116 fn from(value: SuccessReason) -> Self {
117 match value {
118 SuccessReason::Return => InstructionResult::Return,
119 SuccessReason::Stop => InstructionResult::Stop,
120 SuccessReason::SelfDestruct => InstructionResult::SelfDestruct,
121 SuccessReason::EofReturnContract => InstructionResult::ReturnContract,
122 }
123 }
124}
125
126impl From<HaltReason> for InstructionResult {
127 fn from(value: HaltReason) -> Self {
128 match value {
129 HaltReason::OutOfGas(error) => match error {
130 OutOfGasError::Basic => Self::OutOfGas,
131 OutOfGasError::InvalidOperand => Self::InvalidOperandOOG,
132 OutOfGasError::Memory => Self::MemoryOOG,
133 OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
134 OutOfGasError::Precompile => Self::PrecompileOOG,
135 OutOfGasError::ReentrancySentry => Self::ReentrancySentryOOG,
136 },
137 HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
138 HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
139 HaltReason::InvalidJump => Self::InvalidJump,
140 HaltReason::NotActivated => Self::NotActivated,
141 HaltReason::StackOverflow => Self::StackOverflow,
142 HaltReason::StackUnderflow => Self::StackUnderflow,
143 HaltReason::OutOfOffset => Self::OutOfOffset,
144 HaltReason::CreateCollision => Self::CreateCollision,
145 HaltReason::PrecompileError => Self::PrecompileError,
146 HaltReason::NonceOverflow => Self::NonceOverflow,
147 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
148 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
149 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
150 HaltReason::OverflowPayment => Self::OverflowPayment,
151 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
152 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
153 HaltReason::OutOfFunds => Self::OutOfFunds,
154 HaltReason::CallTooDeep => Self::CallTooDeep,
155 HaltReason::EofAuxDataOverflow => Self::EofAuxDataOverflow,
156 HaltReason::EofAuxDataTooSmall => Self::EofAuxDataTooSmall,
157 HaltReason::SubRoutineStackOverflow => Self::SubRoutineStackOverflow,
158 HaltReason::InvalidEXTCALLTarget => Self::InvalidEXTCALLTarget,
159 }
160 }
161}
162
163#[macro_export]
164macro_rules! return_ok {
165 () => {
166 $crate::InstructionResult::Continue
167 | $crate::InstructionResult::Stop
168 | $crate::InstructionResult::Return
169 | $crate::InstructionResult::SelfDestruct
170 | $crate::InstructionResult::ReturnContract
171 };
172}
173
174#[macro_export]
175macro_rules! return_revert {
176 () => {
177 $crate::InstructionResult::Revert
178 | $crate::InstructionResult::CallTooDeep
179 | $crate::InstructionResult::OutOfFunds
180 | $crate::InstructionResult::InvalidEOFInitCode
181 | $crate::InstructionResult::CreateInitCodeStartingEF00
182 | $crate::InstructionResult::InvalidExtDelegateCallTarget
183 };
184}
185
186#[macro_export]
187macro_rules! return_error {
188 () => {
189 $crate::InstructionResult::OutOfGas
190 | $crate::InstructionResult::MemoryOOG
191 | $crate::InstructionResult::MemoryLimitOOG
192 | $crate::InstructionResult::PrecompileOOG
193 | $crate::InstructionResult::InvalidOperandOOG
194 | $crate::InstructionResult::ReentrancySentryOOG
195 | $crate::InstructionResult::OpcodeNotFound
196 | $crate::InstructionResult::CallNotAllowedInsideStatic
197 | $crate::InstructionResult::StateChangeDuringStaticCall
198 | $crate::InstructionResult::InvalidFEOpcode
199 | $crate::InstructionResult::InvalidJump
200 | $crate::InstructionResult::NotActivated
201 | $crate::InstructionResult::StackUnderflow
202 | $crate::InstructionResult::StackOverflow
203 | $crate::InstructionResult::OutOfOffset
204 | $crate::InstructionResult::CreateCollision
205 | $crate::InstructionResult::OverflowPayment
206 | $crate::InstructionResult::PrecompileError
207 | $crate::InstructionResult::NonceOverflow
208 | $crate::InstructionResult::CreateContractSizeLimit
209 | $crate::InstructionResult::CreateContractStartingWithEF
210 | $crate::InstructionResult::CreateInitCodeSizeLimit
211 | $crate::InstructionResult::FatalExternalError
212 | $crate::InstructionResult::ReturnContractInNotInitEOF
213 | $crate::InstructionResult::EOFOpcodeDisabledInLegacy
214 | $crate::InstructionResult::SubRoutineStackOverflow
215 | $crate::InstructionResult::EofAuxDataTooSmall
216 | $crate::InstructionResult::EofAuxDataOverflow
217 | $crate::InstructionResult::InvalidEXTCALLTarget
218 };
219}
220
221impl InstructionResult {
222 #[inline]
224 pub const fn is_ok(self) -> bool {
225 matches!(self, crate::return_ok!())
226 }
227
228 #[inline]
229 pub const fn is_ok_or_revert(self) -> bool {
230 matches!(self, crate::return_ok!() | crate::return_revert!())
231 }
232
233 #[inline]
234 pub const fn is_continue(self) -> bool {
235 matches!(self, InstructionResult::Continue)
236 }
237
238 #[inline]
240 pub const fn is_revert(self) -> bool {
241 matches!(self, crate::return_revert!())
242 }
243
244 #[inline]
246 pub const fn is_error(self) -> bool {
247 matches!(self, return_error!())
248 }
249}
250
251#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
253pub enum InternalResult {
254 InternalContinue,
256 InternalCallOrCreate,
258 CreateInitCodeStartingEF00,
260 InvalidExtDelegateCallTarget,
262}
263
264#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
265pub enum SuccessOrHalt<HaltReasonTr> {
266 Success(SuccessReason),
267 Revert,
268 Halt(HaltReasonTr),
269 FatalExternalError,
270 Internal(InternalResult),
271}
272
273impl<HaltReasonTr> SuccessOrHalt<HaltReasonTr> {
274 #[inline]
276 pub fn is_success(self) -> bool {
277 matches!(self, SuccessOrHalt::Success(_))
278 }
279
280 #[inline]
282 pub fn to_success(self) -> Option<SuccessReason> {
283 match self {
284 SuccessOrHalt::Success(reason) => Some(reason),
285 _ => None,
286 }
287 }
288
289 #[inline]
291 pub fn is_revert(self) -> bool {
292 matches!(self, SuccessOrHalt::Revert)
293 }
294
295 #[inline]
297 pub fn is_halt(self) -> bool {
298 matches!(self, SuccessOrHalt::Halt(_))
299 }
300
301 #[inline]
303 pub fn to_halt(self) -> Option<HaltReasonTr> {
304 match self {
305 SuccessOrHalt::Halt(reason) => Some(reason),
306 _ => None,
307 }
308 }
309}
310
311impl<HALT: From<HaltReason>> From<HaltReason> for SuccessOrHalt<HALT> {
312 fn from(reason: HaltReason) -> Self {
313 SuccessOrHalt::Halt(reason.into())
314 }
315}
316
317impl<HaltReasonTr: From<HaltReason>> From<InstructionResult> for SuccessOrHalt<HaltReasonTr> {
318 fn from(result: InstructionResult) -> Self {
319 match result {
320 InstructionResult::Continue => Self::Internal(InternalResult::InternalContinue), InstructionResult::Stop => Self::Success(SuccessReason::Stop),
322 InstructionResult::Return => Self::Success(SuccessReason::Return),
323 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
324 InstructionResult::Revert => Self::Revert,
325 InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
326 InstructionResult::CallOrCreate => Self::Internal(InternalResult::InternalCallOrCreate), InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep.into()), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds.into()), InstructionResult::OutOfGas => {
330 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic).into())
331 }
332 InstructionResult::MemoryLimitOOG => {
333 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit).into())
334 }
335 InstructionResult::MemoryOOG => {
336 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory).into())
337 }
338 InstructionResult::PrecompileOOG => {
339 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile).into())
340 }
341 InstructionResult::InvalidOperandOOG => {
342 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
343 }
344 InstructionResult::ReentrancySentryOOG => {
345 Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
346 }
347 InstructionResult::OpcodeNotFound | InstructionResult::ReturnContractInNotInitEOF => {
348 Self::Halt(HaltReason::OpcodeNotFound.into())
349 }
350 InstructionResult::CallNotAllowedInsideStatic => {
351 Self::Halt(HaltReason::CallNotAllowedInsideStatic.into())
352 } InstructionResult::StateChangeDuringStaticCall => {
354 Self::Halt(HaltReason::StateChangeDuringStaticCall.into())
355 }
356 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode.into()),
357 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump.into()),
358 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated.into()),
359 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow.into()),
360 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow.into()),
361 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset.into()),
362 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision.into()),
363 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment.into()), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()),
365 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()),
366 InstructionResult::CreateContractSizeLimit
367 | InstructionResult::CreateContractStartingWithEF => {
368 Self::Halt(HaltReason::CreateContractSizeLimit.into())
369 }
370 InstructionResult::CreateInitCodeSizeLimit => {
371 Self::Halt(HaltReason::CreateInitCodeSizeLimit.into())
372 }
373 InstructionResult::InvalidEOFInitCode => Self::Revert,
375 InstructionResult::FatalExternalError => Self::FatalExternalError,
376 InstructionResult::EOFOpcodeDisabledInLegacy => {
377 Self::Halt(HaltReason::OpcodeNotFound.into())
378 }
379 InstructionResult::SubRoutineStackOverflow => {
380 Self::Halt(HaltReason::SubRoutineStackOverflow.into())
381 }
382 InstructionResult::ReturnContract => Self::Success(SuccessReason::EofReturnContract),
383 InstructionResult::EofAuxDataOverflow => {
384 Self::Halt(HaltReason::EofAuxDataOverflow.into())
385 }
386 InstructionResult::EofAuxDataTooSmall => {
387 Self::Halt(HaltReason::EofAuxDataTooSmall.into())
388 }
389 InstructionResult::InvalidEXTCALLTarget => {
390 Self::Halt(HaltReason::InvalidEXTCALLTarget.into())
391 }
392 InstructionResult::InvalidExtDelegateCallTarget => {
393 Self::Internal(InternalResult::InvalidExtDelegateCallTarget)
394 }
395 }
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use crate::InstructionResult;
402
403 #[test]
404 fn all_results_are_covered() {
405 match InstructionResult::Continue {
406 return_error!() => {}
407 return_revert!() => {}
408 return_ok!() => {}
409 InstructionResult::CallOrCreate => {}
410 }
411 }
412
413 #[test]
414 fn test_results() {
415 let ok_results = vec![
416 InstructionResult::Continue,
417 InstructionResult::Stop,
418 InstructionResult::Return,
419 InstructionResult::SelfDestruct,
420 ];
421
422 for result in ok_results {
423 assert!(result.is_ok());
424 assert!(!result.is_revert());
425 assert!(!result.is_error());
426 }
427
428 let revert_results = vec![
429 InstructionResult::Revert,
430 InstructionResult::CallTooDeep,
431 InstructionResult::OutOfFunds,
432 ];
433
434 for result in revert_results {
435 assert!(!result.is_ok());
436 assert!(result.is_revert());
437 assert!(!result.is_error());
438 }
439
440 let error_results = vec![
441 InstructionResult::OutOfGas,
442 InstructionResult::MemoryOOG,
443 InstructionResult::MemoryLimitOOG,
444 InstructionResult::PrecompileOOG,
445 InstructionResult::InvalidOperandOOG,
446 InstructionResult::OpcodeNotFound,
447 InstructionResult::CallNotAllowedInsideStatic,
448 InstructionResult::StateChangeDuringStaticCall,
449 InstructionResult::InvalidFEOpcode,
450 InstructionResult::InvalidJump,
451 InstructionResult::NotActivated,
452 InstructionResult::StackUnderflow,
453 InstructionResult::StackOverflow,
454 InstructionResult::OutOfOffset,
455 InstructionResult::CreateCollision,
456 InstructionResult::OverflowPayment,
457 InstructionResult::PrecompileError,
458 InstructionResult::NonceOverflow,
459 InstructionResult::CreateContractSizeLimit,
460 InstructionResult::CreateContractStartingWithEF,
461 InstructionResult::CreateInitCodeSizeLimit,
462 InstructionResult::FatalExternalError,
463 ];
464
465 for result in error_results {
466 assert!(!result.is_ok());
467 assert!(!result.is_revert());
468 assert!(result.is_error());
469 }
470 }
471}