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}
85
86impl From<TransferError> for InstructionResult {
87 fn from(e: TransferError) -> Self {
88 match e {
89 TransferError::OutOfFunds => InstructionResult::OutOfFunds,
90 TransferError::OverflowPayment => InstructionResult::OverflowPayment,
91 TransferError::CreateCollision => InstructionResult::CreateCollision,
92 }
93 }
94}
95
96impl From<SuccessReason> for InstructionResult {
97 fn from(value: SuccessReason) -> Self {
98 match value {
99 SuccessReason::Return => InstructionResult::Return,
100 SuccessReason::Stop => InstructionResult::Stop,
101 SuccessReason::SelfDestruct => InstructionResult::SelfDestruct,
102 }
103 }
104}
105
106impl From<HaltReason> for InstructionResult {
107 fn from(value: HaltReason) -> Self {
108 match value {
109 HaltReason::OutOfGas(error) => match error {
110 OutOfGasError::Basic => Self::OutOfGas,
111 OutOfGasError::InvalidOperand => Self::InvalidOperandOOG,
112 OutOfGasError::Memory => Self::MemoryOOG,
113 OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
114 OutOfGasError::Precompile => Self::PrecompileOOG,
115 OutOfGasError::ReentrancySentry => Self::ReentrancySentryOOG,
116 },
117 HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
118 HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
119 HaltReason::InvalidJump => Self::InvalidJump,
120 HaltReason::NotActivated => Self::NotActivated,
121 HaltReason::StackOverflow => Self::StackOverflow,
122 HaltReason::StackUnderflow => Self::StackUnderflow,
123 HaltReason::OutOfOffset => Self::OutOfOffset,
124 HaltReason::CreateCollision => Self::CreateCollision,
125 HaltReason::PrecompileError => Self::PrecompileError,
126 HaltReason::NonceOverflow => Self::NonceOverflow,
127 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
128 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
129 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
130 HaltReason::OverflowPayment => Self::OverflowPayment,
131 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
132 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
133 HaltReason::OutOfFunds => Self::OutOfFunds,
134 HaltReason::CallTooDeep => Self::CallTooDeep,
135 }
136 }
137}
138
139#[macro_export]
142macro_rules! return_ok {
143 () => {
144 $crate::InstructionResult::Stop
145 | $crate::InstructionResult::Return
146 | $crate::InstructionResult::SelfDestruct
147 };
148}
149
150#[macro_export]
153macro_rules! return_revert {
154 () => {
155 $crate::InstructionResult::Revert
156 | $crate::InstructionResult::CallTooDeep
157 | $crate::InstructionResult::OutOfFunds
158 | $crate::InstructionResult::InvalidEOFInitCode
159 | $crate::InstructionResult::CreateInitCodeStartingEF00
160 | $crate::InstructionResult::InvalidExtDelegateCallTarget
161 };
162}
163
164#[macro_export]
167macro_rules! return_error {
168 () => {
169 $crate::InstructionResult::OutOfGas
170 | $crate::InstructionResult::MemoryOOG
171 | $crate::InstructionResult::MemoryLimitOOG
172 | $crate::InstructionResult::PrecompileOOG
173 | $crate::InstructionResult::InvalidOperandOOG
174 | $crate::InstructionResult::ReentrancySentryOOG
175 | $crate::InstructionResult::OpcodeNotFound
176 | $crate::InstructionResult::CallNotAllowedInsideStatic
177 | $crate::InstructionResult::StateChangeDuringStaticCall
178 | $crate::InstructionResult::InvalidFEOpcode
179 | $crate::InstructionResult::InvalidJump
180 | $crate::InstructionResult::NotActivated
181 | $crate::InstructionResult::StackUnderflow
182 | $crate::InstructionResult::StackOverflow
183 | $crate::InstructionResult::OutOfOffset
184 | $crate::InstructionResult::CreateCollision
185 | $crate::InstructionResult::OverflowPayment
186 | $crate::InstructionResult::PrecompileError
187 | $crate::InstructionResult::NonceOverflow
188 | $crate::InstructionResult::CreateContractSizeLimit
189 | $crate::InstructionResult::CreateContractStartingWithEF
190 | $crate::InstructionResult::CreateInitCodeSizeLimit
191 | $crate::InstructionResult::FatalExternalError
192 };
193}
194
195impl InstructionResult {
196 #[inline]
198 pub const fn is_ok(self) -> bool {
199 matches!(self, return_ok!())
200 }
201
202 #[inline]
203 pub const fn is_ok_or_revert(self) -> bool {
205 matches!(self, return_ok!() | return_revert!())
206 }
207
208 #[inline]
210 pub const fn is_revert(self) -> bool {
211 matches!(self, return_revert!())
212 }
213
214 #[inline]
216 pub const fn is_error(self) -> bool {
217 matches!(self, return_error!())
218 }
219}
220
221#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
223pub enum InternalResult {
224 CreateInitCodeStartingEF00,
226 InvalidExtDelegateCallTarget,
228}
229
230#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
231pub enum SuccessOrHalt<HaltReasonTr> {
234 Success(SuccessReason),
236 Revert,
238 Halt(HaltReasonTr),
240 FatalExternalError,
242 Internal(InternalResult),
244}
245
246impl<HaltReasonTr> SuccessOrHalt<HaltReasonTr> {
247 #[inline]
249 pub fn is_success(self) -> bool {
250 matches!(self, SuccessOrHalt::Success(_))
251 }
252
253 #[inline]
255 pub fn to_success(self) -> Option<SuccessReason> {
256 match self {
257 SuccessOrHalt::Success(reason) => Some(reason),
258 _ => None,
259 }
260 }
261
262 #[inline]
264 pub fn is_revert(self) -> bool {
265 matches!(self, SuccessOrHalt::Revert)
266 }
267
268 #[inline]
270 pub fn is_halt(self) -> bool {
271 matches!(self, SuccessOrHalt::Halt(_))
272 }
273
274 #[inline]
276 pub fn to_halt(self) -> Option<HaltReasonTr> {
277 match self {
278 SuccessOrHalt::Halt(reason) => Some(reason),
279 _ => None,
280 }
281 }
282}
283
284impl<HALT: From<HaltReason>> From<HaltReason> for SuccessOrHalt<HALT> {
285 fn from(reason: HaltReason) -> Self {
286 SuccessOrHalt::Halt(reason.into())
287 }
288}
289
290impl<HaltReasonTr: From<HaltReason>> From<InstructionResult> for SuccessOrHalt<HaltReasonTr> {
291 fn from(result: InstructionResult) -> Self {
292 match result {
293 InstructionResult::Stop => Self::Success(SuccessReason::Stop),
294 InstructionResult::Return => Self::Success(SuccessReason::Return),
295 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
296 InstructionResult::Revert => Self::Revert,
297 InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
298 InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep.into()), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds.into()), InstructionResult::OutOfGas => {
301 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic).into())
302 }
303 InstructionResult::MemoryLimitOOG => {
304 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit).into())
305 }
306 InstructionResult::MemoryOOG => {
307 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory).into())
308 }
309 InstructionResult::PrecompileOOG => {
310 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile).into())
311 }
312 InstructionResult::InvalidOperandOOG => {
313 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
314 }
315 InstructionResult::ReentrancySentryOOG => {
316 Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
317 }
318 InstructionResult::OpcodeNotFound => Self::Halt(HaltReason::OpcodeNotFound.into()),
319 InstructionResult::CallNotAllowedInsideStatic => {
320 Self::Halt(HaltReason::CallNotAllowedInsideStatic.into())
321 } InstructionResult::StateChangeDuringStaticCall => {
323 Self::Halt(HaltReason::StateChangeDuringStaticCall.into())
324 }
325 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode.into()),
326 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump.into()),
327 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated.into()),
328 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow.into()),
329 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow.into()),
330 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset.into()),
331 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision.into()),
332 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment.into()), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()),
334 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()),
335 InstructionResult::CreateContractSizeLimit
336 | InstructionResult::CreateContractStartingWithEF => {
337 Self::Halt(HaltReason::CreateContractSizeLimit.into())
338 }
339 InstructionResult::CreateInitCodeSizeLimit => {
340 Self::Halt(HaltReason::CreateInitCodeSizeLimit.into())
341 }
342 InstructionResult::InvalidEOFInitCode => Self::Revert,
344 InstructionResult::FatalExternalError => Self::FatalExternalError,
345 InstructionResult::InvalidExtDelegateCallTarget => {
346 Self::Internal(InternalResult::InvalidExtDelegateCallTarget)
347 }
348 }
349 }
350}
351
352#[cfg(test)]
353mod tests {
354 use crate::InstructionResult;
355
356 #[test]
357 fn exhaustiveness() {
358 match InstructionResult::Stop {
359 return_error!() => {}
360 return_revert!() => {}
361 return_ok!() => {}
362 }
363 }
364
365 #[test]
366 fn test_results() {
367 let ok_results = [
368 InstructionResult::Stop,
369 InstructionResult::Return,
370 InstructionResult::SelfDestruct,
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 = [
379 InstructionResult::Revert,
380 InstructionResult::CallTooDeep,
381 InstructionResult::OutOfFunds,
382 ];
383 for result in revert_results {
384 assert!(!result.is_ok());
385 assert!(result.is_revert());
386 assert!(!result.is_error());
387 }
388
389 let error_results = [
390 InstructionResult::OutOfGas,
391 InstructionResult::MemoryOOG,
392 InstructionResult::MemoryLimitOOG,
393 InstructionResult::PrecompileOOG,
394 InstructionResult::InvalidOperandOOG,
395 InstructionResult::OpcodeNotFound,
396 InstructionResult::CallNotAllowedInsideStatic,
397 InstructionResult::StateChangeDuringStaticCall,
398 InstructionResult::InvalidFEOpcode,
399 InstructionResult::InvalidJump,
400 InstructionResult::NotActivated,
401 InstructionResult::StackUnderflow,
402 InstructionResult::StackOverflow,
403 InstructionResult::OutOfOffset,
404 InstructionResult::CreateCollision,
405 InstructionResult::OverflowPayment,
406 InstructionResult::PrecompileError,
407 InstructionResult::NonceOverflow,
408 InstructionResult::CreateContractSizeLimit,
409 InstructionResult::CreateContractStartingWithEF,
410 InstructionResult::CreateInitCodeSizeLimit,
411 InstructionResult::FatalExternalError,
412 ];
413 for result in error_results {
414 assert!(!result.is_ok());
415 assert!(!result.is_revert());
416 assert!(result.is_error());
417 }
418 }
419}