1use context_interface::{
2 host::LoadError,
3 journaled_state::TransferError,
4 result::{HaltReason, OutOfGasError, SuccessReason},
5};
6use core::fmt::Debug;
7
8pub type InstructionExecResult<T = (), E = InstructionResult> = Result<T, E>;
13
14#[repr(u8)]
19#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub enum InstructionResult {
22 #[default]
24 Stop = 1, Return,
27 SelfDestruct,
29 Suspend,
31
32 Revert = 0x10,
35 CallTooDeep,
37 OutOfFunds,
39 CreateInitCodeStartingEF00,
41 InvalidEOFInitCode,
43 InvalidExtDelegateCallTarget,
45
46 OutOfGas = 0x20,
49 MemoryOOG,
51 MemoryLimitOOG,
53 PrecompileOOG,
55 InvalidOperandOOG,
57 ReentrancySentryOOG,
59 OpcodeNotFound,
61 CallNotAllowedInsideStatic,
63 StateChangeDuringStaticCall,
65 InvalidFEOpcode,
67 InvalidJump,
69 NotActivated,
71 StackUnderflow,
73 StackOverflow,
75 OutOfOffset,
77 CreateCollision,
79 OverflowPayment,
81 PrecompileError,
83 NonceOverflow,
85 CreateContractSizeLimit,
87 CreateContractStartingWithEF,
89 CreateInitCodeSizeLimit,
91 FatalExternalError,
93 InvalidImmediateEncoding,
95}
96
97impl From<TransferError> for InstructionResult {
98 fn from(e: TransferError) -> Self {
99 match e {
100 TransferError::OutOfFunds => InstructionResult::OutOfFunds,
101 TransferError::OverflowPayment => InstructionResult::OverflowPayment,
102 TransferError::CreateCollision => InstructionResult::CreateCollision,
103 }
104 }
105}
106
107impl From<SuccessReason> for InstructionResult {
108 fn from(value: SuccessReason) -> Self {
109 match value {
110 SuccessReason::Return => InstructionResult::Return,
111 SuccessReason::Stop => InstructionResult::Stop,
112 SuccessReason::SelfDestruct => InstructionResult::SelfDestruct,
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::PrecompileErrorWithContext(_) => Self::PrecompileError,
138 HaltReason::NonceOverflow => Self::NonceOverflow,
139 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
140 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
141 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
142 HaltReason::OverflowPayment => Self::OverflowPayment,
143 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
144 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
145 HaltReason::OutOfFunds => Self::OutOfFunds,
146 HaltReason::CallTooDeep => Self::CallTooDeep,
147 }
148 }
149}
150
151impl From<LoadError> for InstructionResult {
152 fn from(error: LoadError) -> Self {
153 match error {
154 LoadError::ColdLoadSkipped => Self::OutOfGas,
155 LoadError::DBError => Self::FatalExternalError,
156 }
157 }
158}
159
160#[macro_export]
163macro_rules! return_ok {
164 () => {
165 $crate::InstructionResult::Stop
166 | $crate::InstructionResult::Return
167 | $crate::InstructionResult::SelfDestruct
168 | $crate::InstructionResult::Suspend
169 };
170}
171
172#[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]
189macro_rules! return_error {
190 () => {
191 $crate::InstructionResult::OutOfGas
192 | $crate::InstructionResult::MemoryOOG
193 | $crate::InstructionResult::MemoryLimitOOG
194 | $crate::InstructionResult::PrecompileOOG
195 | $crate::InstructionResult::InvalidOperandOOG
196 | $crate::InstructionResult::ReentrancySentryOOG
197 | $crate::InstructionResult::OpcodeNotFound
198 | $crate::InstructionResult::CallNotAllowedInsideStatic
199 | $crate::InstructionResult::StateChangeDuringStaticCall
200 | $crate::InstructionResult::InvalidFEOpcode
201 | $crate::InstructionResult::InvalidJump
202 | $crate::InstructionResult::NotActivated
203 | $crate::InstructionResult::StackUnderflow
204 | $crate::InstructionResult::StackOverflow
205 | $crate::InstructionResult::OutOfOffset
206 | $crate::InstructionResult::CreateCollision
207 | $crate::InstructionResult::OverflowPayment
208 | $crate::InstructionResult::PrecompileError
209 | $crate::InstructionResult::NonceOverflow
210 | $crate::InstructionResult::CreateContractSizeLimit
211 | $crate::InstructionResult::CreateContractStartingWithEF
212 | $crate::InstructionResult::CreateInitCodeSizeLimit
213 | $crate::InstructionResult::FatalExternalError
214 | $crate::InstructionResult::InvalidImmediateEncoding
215 };
216}
217
218impl InstructionResult {
219 #[inline]
221 pub const fn is_ok(self) -> bool {
222 matches!(self, return_ok!())
223 }
224
225 #[inline]
226 pub const fn is_ok_or_revert(self) -> bool {
228 matches!(self, return_ok!() | return_revert!())
229 }
230
231 #[inline]
233 pub const fn is_revert(self) -> bool {
234 matches!(self, return_revert!())
235 }
236
237 #[inline]
239 pub const fn is_error(self) -> bool {
240 matches!(self, return_error!())
241 }
242}
243
244#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
246pub enum InternalResult {
247 CreateInitCodeStartingEF00,
249 InvalidExtDelegateCallTarget,
251 Suspend,
253}
254
255#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
256pub enum SuccessOrHalt<HaltReasonTr> {
259 Success(SuccessReason),
261 Revert,
263 Halt(HaltReasonTr),
265 FatalExternalError,
267 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::Stop => Self::Success(SuccessReason::Stop),
319 InstructionResult::Return => Self::Success(SuccessReason::Return),
320 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
321 InstructionResult::Suspend => Self::Internal(InternalResult::Suspend),
322 InstructionResult::Revert => Self::Revert,
323 InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
324 InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep.into()), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds.into()), InstructionResult::OutOfGas => {
327 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic).into())
328 }
329 InstructionResult::MemoryLimitOOG => {
330 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit).into())
331 }
332 InstructionResult::MemoryOOG => {
333 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory).into())
334 }
335 InstructionResult::PrecompileOOG => {
336 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile).into())
337 }
338 InstructionResult::InvalidOperandOOG => {
339 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
340 }
341 InstructionResult::ReentrancySentryOOG => {
342 Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
343 }
344 InstructionResult::OpcodeNotFound => Self::Halt(HaltReason::OpcodeNotFound.into()),
345 InstructionResult::CallNotAllowedInsideStatic => {
346 Self::Halt(HaltReason::CallNotAllowedInsideStatic.into())
347 } InstructionResult::StateChangeDuringStaticCall => {
349 Self::Halt(HaltReason::StateChangeDuringStaticCall.into())
350 }
351 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode.into()),
352 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump.into()),
353 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated.into()),
354 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow.into()),
355 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow.into()),
356 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset.into()),
357 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision.into()),
358 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment.into()), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()),
360 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()),
361 InstructionResult::CreateContractSizeLimit => {
362 Self::Halt(HaltReason::CreateContractSizeLimit.into())
363 }
364 InstructionResult::CreateContractStartingWithEF => {
365 Self::Halt(HaltReason::CreateContractStartingWithEF.into())
366 }
367 InstructionResult::CreateInitCodeSizeLimit => {
368 Self::Halt(HaltReason::CreateInitCodeSizeLimit.into())
369 }
370 InstructionResult::InvalidEOFInitCode => Self::Revert,
372 InstructionResult::FatalExternalError => Self::FatalExternalError,
373 InstructionResult::InvalidExtDelegateCallTarget => {
374 Self::Internal(InternalResult::InvalidExtDelegateCallTarget)
375 }
376 InstructionResult::InvalidImmediateEncoding => {
377 Self::Halt(HaltReason::OpcodeNotFound.into())
378 }
379 }
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use crate::InstructionResult;
386
387 #[test]
388 fn exhaustiveness() {
389 match InstructionResult::Stop {
390 return_error!() => {}
391 return_revert!() => {}
392 return_ok!() => {}
393 }
394 }
395
396 #[test]
397 fn test_results() {
398 let ok_results = [
399 InstructionResult::Stop,
400 InstructionResult::Return,
401 InstructionResult::SelfDestruct,
402 ];
403 for result in ok_results {
404 assert!(result.is_ok());
405 assert!(!result.is_revert());
406 assert!(!result.is_error());
407 }
408
409 let revert_results = [
410 InstructionResult::Revert,
411 InstructionResult::CallTooDeep,
412 InstructionResult::OutOfFunds,
413 ];
414 for result in revert_results {
415 assert!(!result.is_ok());
416 assert!(result.is_revert());
417 assert!(!result.is_error());
418 }
419
420 let error_results = [
421 InstructionResult::OutOfGas,
422 InstructionResult::MemoryOOG,
423 InstructionResult::MemoryLimitOOG,
424 InstructionResult::PrecompileOOG,
425 InstructionResult::InvalidOperandOOG,
426 InstructionResult::OpcodeNotFound,
427 InstructionResult::CallNotAllowedInsideStatic,
428 InstructionResult::StateChangeDuringStaticCall,
429 InstructionResult::InvalidFEOpcode,
430 InstructionResult::InvalidJump,
431 InstructionResult::NotActivated,
432 InstructionResult::StackUnderflow,
433 InstructionResult::StackOverflow,
434 InstructionResult::OutOfOffset,
435 InstructionResult::CreateCollision,
436 InstructionResult::OverflowPayment,
437 InstructionResult::PrecompileError,
438 InstructionResult::NonceOverflow,
439 InstructionResult::CreateContractSizeLimit,
440 InstructionResult::CreateContractStartingWithEF,
441 InstructionResult::CreateInitCodeSizeLimit,
442 InstructionResult::FatalExternalError,
443 ];
444 for result in error_results {
445 assert!(!result.is_ok());
446 assert!(!result.is_revert());
447 assert!(result.is_error());
448 }
449 }
450}