1use context_interface::{
2 journaled_state::TransferError,
3 result::{HaltReason, OutOfGasError, SuccessReason},
4};
5use core::fmt::Debug;
6
7#[repr(u8)]
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub enum InstructionResult {
15 #[default]
17 Stop = 1, Return,
20 SelfDestruct,
22
23 Revert = 0x10,
26 CallTooDeep,
28 OutOfFunds,
30 CreateInitCodeStartingEF00,
32 InvalidEOFInitCode,
34 InvalidExtDelegateCallTarget,
36
37 OutOfGas = 0x20,
40 MemoryOOG,
42 MemoryLimitOOG,
44 PrecompileOOG,
46 InvalidOperandOOG,
48 ReentrancySentryOOG,
50 OpcodeNotFound,
52 CallNotAllowedInsideStatic,
54 StateChangeDuringStaticCall,
56 InvalidFEOpcode,
58 InvalidJump,
60 NotActivated,
62 StackUnderflow,
64 StackOverflow,
66 OutOfOffset,
68 CreateCollision,
70 OverflowPayment,
72 PrecompileError,
74 NonceOverflow,
76 CreateContractSizeLimit,
78 CreateContractStartingWithEF,
80 CreateInitCodeSizeLimit,
82 FatalExternalError,
84 InvalidImmediateEncoding,
86}
87
88impl From<TransferError> for InstructionResult {
89 fn from(e: TransferError) -> Self {
90 match e {
91 TransferError::OutOfFunds => InstructionResult::OutOfFunds,
92 TransferError::OverflowPayment => InstructionResult::OverflowPayment,
93 TransferError::CreateCollision => InstructionResult::CreateCollision,
94 }
95 }
96}
97
98impl From<SuccessReason> for InstructionResult {
99 fn from(value: SuccessReason) -> Self {
100 match value {
101 SuccessReason::Return => InstructionResult::Return,
102 SuccessReason::Stop => InstructionResult::Stop,
103 SuccessReason::SelfDestruct => InstructionResult::SelfDestruct,
104 }
105 }
106}
107
108impl From<HaltReason> for InstructionResult {
109 fn from(value: HaltReason) -> Self {
110 match value {
111 HaltReason::OutOfGas(error) => match error {
112 OutOfGasError::Basic => Self::OutOfGas,
113 OutOfGasError::InvalidOperand => Self::InvalidOperandOOG,
114 OutOfGasError::Memory => Self::MemoryOOG,
115 OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
116 OutOfGasError::Precompile => Self::PrecompileOOG,
117 OutOfGasError::ReentrancySentry => Self::ReentrancySentryOOG,
118 },
119 HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
120 HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
121 HaltReason::InvalidJump => Self::InvalidJump,
122 HaltReason::NotActivated => Self::NotActivated,
123 HaltReason::StackOverflow => Self::StackOverflow,
124 HaltReason::StackUnderflow => Self::StackUnderflow,
125 HaltReason::OutOfOffset => Self::OutOfOffset,
126 HaltReason::CreateCollision => Self::CreateCollision,
127 HaltReason::PrecompileError => Self::PrecompileError,
128 HaltReason::PrecompileErrorWithContext(_) => Self::PrecompileError,
129 HaltReason::NonceOverflow => Self::NonceOverflow,
130 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
131 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
132 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
133 HaltReason::OverflowPayment => Self::OverflowPayment,
134 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
135 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
136 HaltReason::OutOfFunds => Self::OutOfFunds,
137 HaltReason::CallTooDeep => Self::CallTooDeep,
138 }
139 }
140}
141
142#[macro_export]
145macro_rules! return_ok {
146 () => {
147 $crate::InstructionResult::Stop
148 | $crate::InstructionResult::Return
149 | $crate::InstructionResult::SelfDestruct
150 };
151}
152
153#[macro_export]
156macro_rules! return_revert {
157 () => {
158 $crate::InstructionResult::Revert
159 | $crate::InstructionResult::CallTooDeep
160 | $crate::InstructionResult::OutOfFunds
161 | $crate::InstructionResult::InvalidEOFInitCode
162 | $crate::InstructionResult::CreateInitCodeStartingEF00
163 | $crate::InstructionResult::InvalidExtDelegateCallTarget
164 };
165}
166
167#[macro_export]
170macro_rules! return_error {
171 () => {
172 $crate::InstructionResult::OutOfGas
173 | $crate::InstructionResult::MemoryOOG
174 | $crate::InstructionResult::MemoryLimitOOG
175 | $crate::InstructionResult::PrecompileOOG
176 | $crate::InstructionResult::InvalidOperandOOG
177 | $crate::InstructionResult::ReentrancySentryOOG
178 | $crate::InstructionResult::OpcodeNotFound
179 | $crate::InstructionResult::CallNotAllowedInsideStatic
180 | $crate::InstructionResult::StateChangeDuringStaticCall
181 | $crate::InstructionResult::InvalidFEOpcode
182 | $crate::InstructionResult::InvalidJump
183 | $crate::InstructionResult::NotActivated
184 | $crate::InstructionResult::StackUnderflow
185 | $crate::InstructionResult::StackOverflow
186 | $crate::InstructionResult::OutOfOffset
187 | $crate::InstructionResult::CreateCollision
188 | $crate::InstructionResult::OverflowPayment
189 | $crate::InstructionResult::PrecompileError
190 | $crate::InstructionResult::NonceOverflow
191 | $crate::InstructionResult::CreateContractSizeLimit
192 | $crate::InstructionResult::CreateContractStartingWithEF
193 | $crate::InstructionResult::CreateInitCodeSizeLimit
194 | $crate::InstructionResult::FatalExternalError
195 | $crate::InstructionResult::InvalidImmediateEncoding
196 };
197}
198
199impl InstructionResult {
200 #[inline]
202 pub const fn is_ok(self) -> bool {
203 matches!(self, return_ok!())
204 }
205
206 #[inline]
207 pub const fn is_ok_or_revert(self) -> bool {
209 matches!(self, return_ok!() | return_revert!())
210 }
211
212 #[inline]
214 pub const fn is_revert(self) -> bool {
215 matches!(self, return_revert!())
216 }
217
218 #[inline]
220 pub const fn is_error(self) -> bool {
221 matches!(self, return_error!())
222 }
223}
224
225#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
227pub enum InternalResult {
228 CreateInitCodeStartingEF00,
230 InvalidExtDelegateCallTarget,
232}
233
234#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
235pub enum SuccessOrHalt<HaltReasonTr> {
238 Success(SuccessReason),
240 Revert,
242 Halt(HaltReasonTr),
244 FatalExternalError,
246 Internal(InternalResult),
248}
249
250impl<HaltReasonTr> SuccessOrHalt<HaltReasonTr> {
251 #[inline]
253 pub fn is_success(self) -> bool {
254 matches!(self, SuccessOrHalt::Success(_))
255 }
256
257 #[inline]
259 pub fn to_success(self) -> Option<SuccessReason> {
260 match self {
261 SuccessOrHalt::Success(reason) => Some(reason),
262 _ => None,
263 }
264 }
265
266 #[inline]
268 pub fn is_revert(self) -> bool {
269 matches!(self, SuccessOrHalt::Revert)
270 }
271
272 #[inline]
274 pub fn is_halt(self) -> bool {
275 matches!(self, SuccessOrHalt::Halt(_))
276 }
277
278 #[inline]
280 pub fn to_halt(self) -> Option<HaltReasonTr> {
281 match self {
282 SuccessOrHalt::Halt(reason) => Some(reason),
283 _ => None,
284 }
285 }
286}
287
288impl<HALT: From<HaltReason>> From<HaltReason> for SuccessOrHalt<HALT> {
289 fn from(reason: HaltReason) -> Self {
290 SuccessOrHalt::Halt(reason.into())
291 }
292}
293
294impl<HaltReasonTr: From<HaltReason>> From<InstructionResult> for SuccessOrHalt<HaltReasonTr> {
295 fn from(result: InstructionResult) -> Self {
296 match result {
297 InstructionResult::Stop => Self::Success(SuccessReason::Stop),
298 InstructionResult::Return => Self::Success(SuccessReason::Return),
299 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
300 InstructionResult::Revert => Self::Revert,
301 InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
302 InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep.into()), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds.into()), InstructionResult::OutOfGas => {
305 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic).into())
306 }
307 InstructionResult::MemoryLimitOOG => {
308 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit).into())
309 }
310 InstructionResult::MemoryOOG => {
311 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory).into())
312 }
313 InstructionResult::PrecompileOOG => {
314 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile).into())
315 }
316 InstructionResult::InvalidOperandOOG => {
317 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
318 }
319 InstructionResult::ReentrancySentryOOG => {
320 Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
321 }
322 InstructionResult::OpcodeNotFound => Self::Halt(HaltReason::OpcodeNotFound.into()),
323 InstructionResult::CallNotAllowedInsideStatic => {
324 Self::Halt(HaltReason::CallNotAllowedInsideStatic.into())
325 } InstructionResult::StateChangeDuringStaticCall => {
327 Self::Halt(HaltReason::StateChangeDuringStaticCall.into())
328 }
329 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode.into()),
330 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump.into()),
331 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated.into()),
332 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow.into()),
333 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow.into()),
334 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset.into()),
335 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision.into()),
336 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment.into()), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()),
338 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()),
339 InstructionResult::CreateContractSizeLimit => {
340 Self::Halt(HaltReason::CreateContractSizeLimit.into())
341 }
342 InstructionResult::CreateContractStartingWithEF => {
343 Self::Halt(HaltReason::CreateContractStartingWithEF.into())
344 }
345 InstructionResult::CreateInitCodeSizeLimit => {
346 Self::Halt(HaltReason::CreateInitCodeSizeLimit.into())
347 }
348 InstructionResult::InvalidEOFInitCode => Self::Revert,
350 InstructionResult::FatalExternalError => Self::FatalExternalError,
351 InstructionResult::InvalidExtDelegateCallTarget => {
352 Self::Internal(InternalResult::InvalidExtDelegateCallTarget)
353 }
354 InstructionResult::InvalidImmediateEncoding => {
355 Self::Halt(HaltReason::OpcodeNotFound.into())
356 }
357 }
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use crate::InstructionResult;
364
365 #[test]
366 fn exhaustiveness() {
367 match InstructionResult::Stop {
368 return_error!() => {}
369 return_revert!() => {}
370 return_ok!() => {}
371 }
372 }
373
374 #[test]
375 fn test_results() {
376 let ok_results = [
377 InstructionResult::Stop,
378 InstructionResult::Return,
379 InstructionResult::SelfDestruct,
380 ];
381 for result in ok_results {
382 assert!(result.is_ok());
383 assert!(!result.is_revert());
384 assert!(!result.is_error());
385 }
386
387 let revert_results = [
388 InstructionResult::Revert,
389 InstructionResult::CallTooDeep,
390 InstructionResult::OutOfFunds,
391 ];
392 for result in revert_results {
393 assert!(!result.is_ok());
394 assert!(result.is_revert());
395 assert!(!result.is_error());
396 }
397
398 let error_results = [
399 InstructionResult::OutOfGas,
400 InstructionResult::MemoryOOG,
401 InstructionResult::MemoryLimitOOG,
402 InstructionResult::PrecompileOOG,
403 InstructionResult::InvalidOperandOOG,
404 InstructionResult::OpcodeNotFound,
405 InstructionResult::CallNotAllowedInsideStatic,
406 InstructionResult::StateChangeDuringStaticCall,
407 InstructionResult::InvalidFEOpcode,
408 InstructionResult::InvalidJump,
409 InstructionResult::NotActivated,
410 InstructionResult::StackUnderflow,
411 InstructionResult::StackOverflow,
412 InstructionResult::OutOfOffset,
413 InstructionResult::CreateCollision,
414 InstructionResult::OverflowPayment,
415 InstructionResult::PrecompileError,
416 InstructionResult::NonceOverflow,
417 InstructionResult::CreateContractSizeLimit,
418 InstructionResult::CreateContractStartingWithEF,
419 InstructionResult::CreateInitCodeSizeLimit,
420 InstructionResult::FatalExternalError,
421 ];
422 for result in error_results {
423 assert!(!result.is_ok());
424 assert!(!result.is_revert());
425 assert!(result.is_error());
426 }
427 }
428}