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 {
14 #[default]
16 Stop,
17 Return,
19 SelfDestruct,
21
22 Revert = 0x10,
25 CallTooDeep,
27 OutOfFunds,
29 CreateInitCodeStartingEF00,
31 InvalidEOFInitCode,
33 InvalidExtDelegateCallTarget,
35
36 OutOfGas = 0x50,
39 MemoryOOG,
41 MemoryLimitOOG,
43 PrecompileOOG,
45 InvalidOperandOOG,
47 ReentrancySentryOOG,
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}
84
85impl From<TransferError> for InstructionResult {
86 fn from(e: TransferError) -> Self {
87 match e {
88 TransferError::OutOfFunds => InstructionResult::OutOfFunds,
89 TransferError::OverflowPayment => InstructionResult::OverflowPayment,
90 TransferError::CreateCollision => InstructionResult::CreateCollision,
91 }
92 }
93}
94
95impl From<SuccessReason> for InstructionResult {
96 fn from(value: SuccessReason) -> Self {
97 match value {
98 SuccessReason::Return => InstructionResult::Return,
99 SuccessReason::Stop => InstructionResult::Stop,
100 SuccessReason::SelfDestruct => InstructionResult::SelfDestruct,
101 }
102 }
103}
104
105impl From<HaltReason> for InstructionResult {
106 fn from(value: HaltReason) -> Self {
107 match value {
108 HaltReason::OutOfGas(error) => match error {
109 OutOfGasError::Basic => Self::OutOfGas,
110 OutOfGasError::InvalidOperand => Self::InvalidOperandOOG,
111 OutOfGasError::Memory => Self::MemoryOOG,
112 OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
113 OutOfGasError::Precompile => Self::PrecompileOOG,
114 OutOfGasError::ReentrancySentry => Self::ReentrancySentryOOG,
115 },
116 HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
117 HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
118 HaltReason::InvalidJump => Self::InvalidJump,
119 HaltReason::NotActivated => Self::NotActivated,
120 HaltReason::StackOverflow => Self::StackOverflow,
121 HaltReason::StackUnderflow => Self::StackUnderflow,
122 HaltReason::OutOfOffset => Self::OutOfOffset,
123 HaltReason::CreateCollision => Self::CreateCollision,
124 HaltReason::PrecompileError => Self::PrecompileError,
125 HaltReason::NonceOverflow => Self::NonceOverflow,
126 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
127 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
128 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
129 HaltReason::OverflowPayment => Self::OverflowPayment,
130 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
131 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
132 HaltReason::OutOfFunds => Self::OutOfFunds,
133 HaltReason::CallTooDeep => Self::CallTooDeep,
134 }
135 }
136}
137
138#[macro_export]
141macro_rules! return_ok {
142 () => {
143 $crate::InstructionResult::Stop
144 | $crate::InstructionResult::Return
145 | $crate::InstructionResult::SelfDestruct
146 };
147}
148
149#[macro_export]
152macro_rules! return_revert {
153 () => {
154 $crate::InstructionResult::Revert
155 | $crate::InstructionResult::CallTooDeep
156 | $crate::InstructionResult::OutOfFunds
157 | $crate::InstructionResult::InvalidEOFInitCode
158 | $crate::InstructionResult::CreateInitCodeStartingEF00
159 | $crate::InstructionResult::InvalidExtDelegateCallTarget
160 };
161}
162
163#[macro_export]
166macro_rules! return_error {
167 () => {
168 $crate::InstructionResult::OutOfGas
169 | $crate::InstructionResult::MemoryOOG
170 | $crate::InstructionResult::MemoryLimitOOG
171 | $crate::InstructionResult::PrecompileOOG
172 | $crate::InstructionResult::InvalidOperandOOG
173 | $crate::InstructionResult::ReentrancySentryOOG
174 | $crate::InstructionResult::OpcodeNotFound
175 | $crate::InstructionResult::CallNotAllowedInsideStatic
176 | $crate::InstructionResult::StateChangeDuringStaticCall
177 | $crate::InstructionResult::InvalidFEOpcode
178 | $crate::InstructionResult::InvalidJump
179 | $crate::InstructionResult::NotActivated
180 | $crate::InstructionResult::StackUnderflow
181 | $crate::InstructionResult::StackOverflow
182 | $crate::InstructionResult::OutOfOffset
183 | $crate::InstructionResult::CreateCollision
184 | $crate::InstructionResult::OverflowPayment
185 | $crate::InstructionResult::PrecompileError
186 | $crate::InstructionResult::NonceOverflow
187 | $crate::InstructionResult::CreateContractSizeLimit
188 | $crate::InstructionResult::CreateContractStartingWithEF
189 | $crate::InstructionResult::CreateInitCodeSizeLimit
190 | $crate::InstructionResult::FatalExternalError
191 };
192}
193
194impl InstructionResult {
195 #[inline]
197 pub const fn is_ok(self) -> bool {
198 matches!(self, crate::return_ok!())
199 }
200
201 #[inline]
202 pub const fn is_ok_or_revert(self) -> bool {
204 matches!(self, crate::return_ok!() | crate::return_revert!())
205 }
206
207 #[inline]
209 pub const fn is_revert(self) -> bool {
210 matches!(self, crate::return_revert!())
211 }
212
213 #[inline]
215 pub const fn is_error(self) -> bool {
216 matches!(self, return_error!())
217 }
218}
219
220#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
222pub enum InternalResult {
223 CreateInitCodeStartingEF00,
225 InvalidExtDelegateCallTarget,
227}
228
229#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
230pub enum SuccessOrHalt<HaltReasonTr> {
233 Success(SuccessReason),
235 Revert,
237 Halt(HaltReasonTr),
239 FatalExternalError,
241 Internal(InternalResult),
243}
244
245impl<HaltReasonTr> SuccessOrHalt<HaltReasonTr> {
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<HaltReasonTr> {
276 match self {
277 SuccessOrHalt::Halt(reason) => Some(reason),
278 _ => None,
279 }
280 }
281}
282
283impl<HALT: From<HaltReason>> From<HaltReason> for SuccessOrHalt<HALT> {
284 fn from(reason: HaltReason) -> Self {
285 SuccessOrHalt::Halt(reason.into())
286 }
287}
288
289impl<HaltReasonTr: From<HaltReason>> From<InstructionResult> for SuccessOrHalt<HaltReasonTr> {
290 fn from(result: InstructionResult) -> Self {
291 match result {
292 InstructionResult::Stop => Self::Success(SuccessReason::Stop),
293 InstructionResult::Return => Self::Success(SuccessReason::Return),
294 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
295 InstructionResult::Revert => Self::Revert,
296 InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
297 InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep.into()), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds.into()), InstructionResult::OutOfGas => {
300 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic).into())
301 }
302 InstructionResult::MemoryLimitOOG => {
303 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit).into())
304 }
305 InstructionResult::MemoryOOG => {
306 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory).into())
307 }
308 InstructionResult::PrecompileOOG => {
309 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile).into())
310 }
311 InstructionResult::InvalidOperandOOG => {
312 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
313 }
314 InstructionResult::ReentrancySentryOOG => {
315 Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
316 }
317 InstructionResult::OpcodeNotFound => Self::Halt(HaltReason::OpcodeNotFound.into()),
318 InstructionResult::CallNotAllowedInsideStatic => {
319 Self::Halt(HaltReason::CallNotAllowedInsideStatic.into())
320 } InstructionResult::StateChangeDuringStaticCall => {
322 Self::Halt(HaltReason::StateChangeDuringStaticCall.into())
323 }
324 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode.into()),
325 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump.into()),
326 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated.into()),
327 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow.into()),
328 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow.into()),
329 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset.into()),
330 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision.into()),
331 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment.into()), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()),
333 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()),
334 InstructionResult::CreateContractSizeLimit
335 | InstructionResult::CreateContractStartingWithEF => {
336 Self::Halt(HaltReason::CreateContractSizeLimit.into())
337 }
338 InstructionResult::CreateInitCodeSizeLimit => {
339 Self::Halt(HaltReason::CreateInitCodeSizeLimit.into())
340 }
341 InstructionResult::InvalidEOFInitCode => Self::Revert,
343 InstructionResult::FatalExternalError => Self::FatalExternalError,
344 InstructionResult::InvalidExtDelegateCallTarget => {
345 Self::Internal(InternalResult::InvalidExtDelegateCallTarget)
346 }
347 }
348 }
349}
350
351#[cfg(test)]
352mod tests {
353 use crate::InstructionResult;
354
355 #[test]
356 fn all_results_are_covered() {
357 match InstructionResult::Stop {
358 return_error!() => {}
359 return_revert!() => {}
360 return_ok!() => {}
361 }
362 }
363
364 #[test]
365 fn test_results() {
366 let ok_results = vec![
367 InstructionResult::Stop,
368 InstructionResult::Return,
369 InstructionResult::SelfDestruct,
370 ];
371
372 for result in ok_results {
373 assert!(result.is_ok());
374 assert!(!result.is_revert());
375 assert!(!result.is_error());
376 }
377
378 let revert_results = vec![
379 InstructionResult::Revert,
380 InstructionResult::CallTooDeep,
381 InstructionResult::OutOfFunds,
382 ];
383
384 for result in revert_results {
385 assert!(!result.is_ok());
386 assert!(result.is_revert());
387 assert!(!result.is_error());
388 }
389
390 let error_results = vec![
391 InstructionResult::OutOfGas,
392 InstructionResult::MemoryOOG,
393 InstructionResult::MemoryLimitOOG,
394 InstructionResult::PrecompileOOG,
395 InstructionResult::InvalidOperandOOG,
396 InstructionResult::OpcodeNotFound,
397 InstructionResult::CallNotAllowedInsideStatic,
398 InstructionResult::StateChangeDuringStaticCall,
399 InstructionResult::InvalidFEOpcode,
400 InstructionResult::InvalidJump,
401 InstructionResult::NotActivated,
402 InstructionResult::StackUnderflow,
403 InstructionResult::StackOverflow,
404 InstructionResult::OutOfOffset,
405 InstructionResult::CreateCollision,
406 InstructionResult::OverflowPayment,
407 InstructionResult::PrecompileError,
408 InstructionResult::NonceOverflow,
409 InstructionResult::CreateContractSizeLimit,
410 InstructionResult::CreateContractStartingWithEF,
411 InstructionResult::CreateInitCodeSizeLimit,
412 InstructionResult::FatalExternalError,
413 ];
414
415 for result in error_results {
416 assert!(!result.is_ok());
417 assert!(!result.is_revert());
418 assert!(result.is_error());
419 }
420 }
421}