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 Stop,
14 Return,
16 SelfDestruct,
18 ReturnContract,
20
21 Revert = 0x10,
24 CallTooDeep,
26 OutOfFunds,
28 CreateInitCodeStartingEF00,
30 InvalidEOFInitCode,
32 InvalidExtDelegateCallTarget,
34
35 OutOfGas = 0x50,
38 MemoryOOG,
40 MemoryLimitOOG,
42 PrecompileOOG,
44 InvalidOperandOOG,
46 ReentrancySentryOOG,
48 OpcodeNotFound,
50 CallNotAllowedInsideStatic,
52 StateChangeDuringStaticCall,
54 InvalidFEOpcode,
56 InvalidJump,
58 NotActivated,
60 StackUnderflow,
62 StackOverflow,
64 OutOfOffset,
66 CreateCollision,
68 OverflowPayment,
70 PrecompileError,
72 NonceOverflow,
74 CreateContractSizeLimit,
76 CreateContractStartingWithEF,
78 CreateInitCodeSizeLimit,
80 FatalExternalError,
82 ReturnContractInNotInitEOF,
84 EOFOpcodeDisabledInLegacy,
86 SubRoutineStackOverflow,
88 EofAuxDataOverflow,
90 EofAuxDataTooSmall,
92 InvalidEXTCALLTarget,
94}
95
96impl From<TransferError> for InstructionResult {
97 fn from(e: TransferError) -> Self {
98 match e {
99 TransferError::OutOfFunds => InstructionResult::OutOfFunds,
100 TransferError::OverflowPayment => InstructionResult::OverflowPayment,
101 TransferError::CreateCollision => InstructionResult::CreateCollision,
102 }
103 }
104}
105
106impl From<SuccessReason> for InstructionResult {
107 fn from(value: SuccessReason) -> Self {
108 match value {
109 SuccessReason::Return => InstructionResult::Return,
110 SuccessReason::Stop => InstructionResult::Stop,
111 SuccessReason::SelfDestruct => InstructionResult::SelfDestruct,
112 SuccessReason::EofReturnContract => InstructionResult::ReturnContract,
113 }
114 }
115}
116
117impl From<HaltReason> for InstructionResult {
118 fn from(value: HaltReason) -> Self {
119 match value {
120 HaltReason::OutOfGas(error) => match error {
121 OutOfGasError::Basic => Self::OutOfGas,
122 OutOfGasError::InvalidOperand => Self::InvalidOperandOOG,
123 OutOfGasError::Memory => Self::MemoryOOG,
124 OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
125 OutOfGasError::Precompile => Self::PrecompileOOG,
126 OutOfGasError::ReentrancySentry => Self::ReentrancySentryOOG,
127 },
128 HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
129 HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
130 HaltReason::InvalidJump => Self::InvalidJump,
131 HaltReason::NotActivated => Self::NotActivated,
132 HaltReason::StackOverflow => Self::StackOverflow,
133 HaltReason::StackUnderflow => Self::StackUnderflow,
134 HaltReason::OutOfOffset => Self::OutOfOffset,
135 HaltReason::CreateCollision => Self::CreateCollision,
136 HaltReason::PrecompileError => Self::PrecompileError,
137 HaltReason::NonceOverflow => Self::NonceOverflow,
138 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
139 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
140 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
141 HaltReason::OverflowPayment => Self::OverflowPayment,
142 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
143 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
144 HaltReason::OutOfFunds => Self::OutOfFunds,
145 HaltReason::CallTooDeep => Self::CallTooDeep,
146 HaltReason::EofAuxDataOverflow => Self::EofAuxDataOverflow,
147 HaltReason::EofAuxDataTooSmall => Self::EofAuxDataTooSmall,
148 HaltReason::SubRoutineStackOverflow => Self::SubRoutineStackOverflow,
149 HaltReason::InvalidEXTCALLTarget => Self::InvalidEXTCALLTarget,
150 }
151 }
152}
153
154#[macro_export]
155macro_rules! return_ok {
156 () => {
157 $crate::InstructionResult::Stop
158 | $crate::InstructionResult::Return
159 | $crate::InstructionResult::SelfDestruct
160 | $crate::InstructionResult::ReturnContract
161 };
162}
163
164#[macro_export]
165macro_rules! return_revert {
166 () => {
167 $crate::InstructionResult::Revert
168 | $crate::InstructionResult::CallTooDeep
169 | $crate::InstructionResult::OutOfFunds
170 | $crate::InstructionResult::InvalidEOFInitCode
171 | $crate::InstructionResult::CreateInitCodeStartingEF00
172 | $crate::InstructionResult::InvalidExtDelegateCallTarget
173 };
174}
175
176#[macro_export]
177macro_rules! return_error {
178 () => {
179 $crate::InstructionResult::OutOfGas
180 | $crate::InstructionResult::MemoryOOG
181 | $crate::InstructionResult::MemoryLimitOOG
182 | $crate::InstructionResult::PrecompileOOG
183 | $crate::InstructionResult::InvalidOperandOOG
184 | $crate::InstructionResult::ReentrancySentryOOG
185 | $crate::InstructionResult::OpcodeNotFound
186 | $crate::InstructionResult::CallNotAllowedInsideStatic
187 | $crate::InstructionResult::StateChangeDuringStaticCall
188 | $crate::InstructionResult::InvalidFEOpcode
189 | $crate::InstructionResult::InvalidJump
190 | $crate::InstructionResult::NotActivated
191 | $crate::InstructionResult::StackUnderflow
192 | $crate::InstructionResult::StackOverflow
193 | $crate::InstructionResult::OutOfOffset
194 | $crate::InstructionResult::CreateCollision
195 | $crate::InstructionResult::OverflowPayment
196 | $crate::InstructionResult::PrecompileError
197 | $crate::InstructionResult::NonceOverflow
198 | $crate::InstructionResult::CreateContractSizeLimit
199 | $crate::InstructionResult::CreateContractStartingWithEF
200 | $crate::InstructionResult::CreateInitCodeSizeLimit
201 | $crate::InstructionResult::FatalExternalError
202 | $crate::InstructionResult::ReturnContractInNotInitEOF
203 | $crate::InstructionResult::EOFOpcodeDisabledInLegacy
204 | $crate::InstructionResult::SubRoutineStackOverflow
205 | $crate::InstructionResult::EofAuxDataTooSmall
206 | $crate::InstructionResult::EofAuxDataOverflow
207 | $crate::InstructionResult::InvalidEXTCALLTarget
208 };
209}
210
211impl InstructionResult {
212 #[inline]
214 pub const fn is_ok(self) -> bool {
215 matches!(self, crate::return_ok!())
216 }
217
218 #[inline]
219 pub const fn is_ok_or_revert(self) -> bool {
220 matches!(self, crate::return_ok!() | crate::return_revert!())
221 }
222
223 #[inline]
225 pub const fn is_revert(self) -> bool {
226 matches!(self, crate::return_revert!())
227 }
228
229 #[inline]
231 pub const fn is_error(self) -> bool {
232 matches!(self, return_error!())
233 }
234}
235
236#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
238pub enum InternalResult {
239 CreateInitCodeStartingEF00,
241 InvalidExtDelegateCallTarget,
243}
244
245#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
246pub enum SuccessOrHalt<HaltReasonTr> {
247 Success(SuccessReason),
248 Revert,
249 Halt(HaltReasonTr),
250 FatalExternalError,
251 Internal(InternalResult),
252}
253
254impl<HaltReasonTr> SuccessOrHalt<HaltReasonTr> {
255 #[inline]
257 pub fn is_success(self) -> bool {
258 matches!(self, SuccessOrHalt::Success(_))
259 }
260
261 #[inline]
263 pub fn to_success(self) -> Option<SuccessReason> {
264 match self {
265 SuccessOrHalt::Success(reason) => Some(reason),
266 _ => None,
267 }
268 }
269
270 #[inline]
272 pub fn is_revert(self) -> bool {
273 matches!(self, SuccessOrHalt::Revert)
274 }
275
276 #[inline]
278 pub fn is_halt(self) -> bool {
279 matches!(self, SuccessOrHalt::Halt(_))
280 }
281
282 #[inline]
284 pub fn to_halt(self) -> Option<HaltReasonTr> {
285 match self {
286 SuccessOrHalt::Halt(reason) => Some(reason),
287 _ => None,
288 }
289 }
290}
291
292impl<HALT: From<HaltReason>> From<HaltReason> for SuccessOrHalt<HALT> {
293 fn from(reason: HaltReason) -> Self {
294 SuccessOrHalt::Halt(reason.into())
295 }
296}
297
298impl<HaltReasonTr: From<HaltReason>> From<InstructionResult> for SuccessOrHalt<HaltReasonTr> {
299 fn from(result: InstructionResult) -> Self {
300 match result {
301 InstructionResult::Stop => Self::Success(SuccessReason::Stop),
302 InstructionResult::Return => Self::Success(SuccessReason::Return),
303 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
304 InstructionResult::Revert => Self::Revert,
305 InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
306 InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep.into()), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds.into()), InstructionResult::OutOfGas => {
309 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic).into())
310 }
311 InstructionResult::MemoryLimitOOG => {
312 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit).into())
313 }
314 InstructionResult::MemoryOOG => {
315 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory).into())
316 }
317 InstructionResult::PrecompileOOG => {
318 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile).into())
319 }
320 InstructionResult::InvalidOperandOOG => {
321 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
322 }
323 InstructionResult::ReentrancySentryOOG => {
324 Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
325 }
326 InstructionResult::OpcodeNotFound | InstructionResult::ReturnContractInNotInitEOF => {
327 Self::Halt(HaltReason::OpcodeNotFound.into())
328 }
329 InstructionResult::CallNotAllowedInsideStatic => {
330 Self::Halt(HaltReason::CallNotAllowedInsideStatic.into())
331 } InstructionResult::StateChangeDuringStaticCall => {
333 Self::Halt(HaltReason::StateChangeDuringStaticCall.into())
334 }
335 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode.into()),
336 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump.into()),
337 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated.into()),
338 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow.into()),
339 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow.into()),
340 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset.into()),
341 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision.into()),
342 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment.into()), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()),
344 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()),
345 InstructionResult::CreateContractSizeLimit
346 | InstructionResult::CreateContractStartingWithEF => {
347 Self::Halt(HaltReason::CreateContractSizeLimit.into())
348 }
349 InstructionResult::CreateInitCodeSizeLimit => {
350 Self::Halt(HaltReason::CreateInitCodeSizeLimit.into())
351 }
352 InstructionResult::InvalidEOFInitCode => Self::Revert,
354 InstructionResult::FatalExternalError => Self::FatalExternalError,
355 InstructionResult::EOFOpcodeDisabledInLegacy => {
356 Self::Halt(HaltReason::OpcodeNotFound.into())
357 }
358 InstructionResult::SubRoutineStackOverflow => {
359 Self::Halt(HaltReason::SubRoutineStackOverflow.into())
360 }
361 InstructionResult::ReturnContract => Self::Success(SuccessReason::EofReturnContract),
362 InstructionResult::EofAuxDataOverflow => {
363 Self::Halt(HaltReason::EofAuxDataOverflow.into())
364 }
365 InstructionResult::EofAuxDataTooSmall => {
366 Self::Halt(HaltReason::EofAuxDataTooSmall.into())
367 }
368 InstructionResult::InvalidEXTCALLTarget => {
369 Self::Halt(HaltReason::InvalidEXTCALLTarget.into())
370 }
371 InstructionResult::InvalidExtDelegateCallTarget => {
372 Self::Internal(InternalResult::InvalidExtDelegateCallTarget)
373 }
374 }
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use crate::InstructionResult;
381
382 #[test]
383 fn all_results_are_covered() {
384 match InstructionResult::Stop {
385 return_error!() => {}
386 return_revert!() => {}
387 return_ok!() => {}
388 }
389 }
390
391 #[test]
392 fn test_results() {
393 let ok_results = vec![
394 InstructionResult::Stop,
395 InstructionResult::Return,
396 InstructionResult::SelfDestruct,
397 ];
398
399 for result in ok_results {
400 assert!(result.is_ok());
401 assert!(!result.is_revert());
402 assert!(!result.is_error());
403 }
404
405 let revert_results = vec![
406 InstructionResult::Revert,
407 InstructionResult::CallTooDeep,
408 InstructionResult::OutOfFunds,
409 ];
410
411 for result in revert_results {
412 assert!(!result.is_ok());
413 assert!(result.is_revert());
414 assert!(!result.is_error());
415 }
416
417 let error_results = vec![
418 InstructionResult::OutOfGas,
419 InstructionResult::MemoryOOG,
420 InstructionResult::MemoryLimitOOG,
421 InstructionResult::PrecompileOOG,
422 InstructionResult::InvalidOperandOOG,
423 InstructionResult::OpcodeNotFound,
424 InstructionResult::CallNotAllowedInsideStatic,
425 InstructionResult::StateChangeDuringStaticCall,
426 InstructionResult::InvalidFEOpcode,
427 InstructionResult::InvalidJump,
428 InstructionResult::NotActivated,
429 InstructionResult::StackUnderflow,
430 InstructionResult::StackOverflow,
431 InstructionResult::OutOfOffset,
432 InstructionResult::CreateCollision,
433 InstructionResult::OverflowPayment,
434 InstructionResult::PrecompileError,
435 InstructionResult::NonceOverflow,
436 InstructionResult::CreateContractSizeLimit,
437 InstructionResult::CreateContractStartingWithEF,
438 InstructionResult::CreateInitCodeSizeLimit,
439 InstructionResult::FatalExternalError,
440 ];
441
442 for result in error_results {
443 assert!(!result.is_ok());
444 assert!(!result.is_revert());
445 assert!(result.is_error());
446 }
447 }
448}