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::PrecompileErrorWithContext(_) => Self::PrecompileError,
127 HaltReason::NonceOverflow => Self::NonceOverflow,
128 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
129 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
130 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
131 HaltReason::OverflowPayment => Self::OverflowPayment,
132 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
133 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
134 HaltReason::OutOfFunds => Self::OutOfFunds,
135 HaltReason::CallTooDeep => Self::CallTooDeep,
136 }
137 }
138}
139
140#[macro_export]
143macro_rules! return_ok {
144 () => {
145 $crate::InstructionResult::Stop
146 | $crate::InstructionResult::Return
147 | $crate::InstructionResult::SelfDestruct
148 };
149}
150
151#[macro_export]
154macro_rules! return_revert {
155 () => {
156 $crate::InstructionResult::Revert
157 | $crate::InstructionResult::CallTooDeep
158 | $crate::InstructionResult::OutOfFunds
159 | $crate::InstructionResult::InvalidEOFInitCode
160 | $crate::InstructionResult::CreateInitCodeStartingEF00
161 | $crate::InstructionResult::InvalidExtDelegateCallTarget
162 };
163}
164
165#[macro_export]
168macro_rules! return_error {
169 () => {
170 $crate::InstructionResult::OutOfGas
171 | $crate::InstructionResult::MemoryOOG
172 | $crate::InstructionResult::MemoryLimitOOG
173 | $crate::InstructionResult::PrecompileOOG
174 | $crate::InstructionResult::InvalidOperandOOG
175 | $crate::InstructionResult::ReentrancySentryOOG
176 | $crate::InstructionResult::OpcodeNotFound
177 | $crate::InstructionResult::CallNotAllowedInsideStatic
178 | $crate::InstructionResult::StateChangeDuringStaticCall
179 | $crate::InstructionResult::InvalidFEOpcode
180 | $crate::InstructionResult::InvalidJump
181 | $crate::InstructionResult::NotActivated
182 | $crate::InstructionResult::StackUnderflow
183 | $crate::InstructionResult::StackOverflow
184 | $crate::InstructionResult::OutOfOffset
185 | $crate::InstructionResult::CreateCollision
186 | $crate::InstructionResult::OverflowPayment
187 | $crate::InstructionResult::PrecompileError
188 | $crate::InstructionResult::NonceOverflow
189 | $crate::InstructionResult::CreateContractSizeLimit
190 | $crate::InstructionResult::CreateContractStartingWithEF
191 | $crate::InstructionResult::CreateInitCodeSizeLimit
192 | $crate::InstructionResult::FatalExternalError
193 };
194}
195
196impl InstructionResult {
197 #[inline]
199 pub const fn is_ok(self) -> bool {
200 matches!(self, return_ok!())
201 }
202
203 #[inline]
204 pub const fn is_ok_or_revert(self) -> bool {
206 matches!(self, return_ok!() | return_revert!())
207 }
208
209 #[inline]
211 pub const fn is_revert(self) -> bool {
212 matches!(self, return_revert!())
213 }
214
215 #[inline]
217 pub const fn is_error(self) -> bool {
218 matches!(self, return_error!())
219 }
220}
221
222#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
224pub enum InternalResult {
225 CreateInitCodeStartingEF00,
227 InvalidExtDelegateCallTarget,
229}
230
231#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
232pub enum SuccessOrHalt<HaltReasonTr> {
235 Success(SuccessReason),
237 Revert,
239 Halt(HaltReasonTr),
241 FatalExternalError,
243 Internal(InternalResult),
245}
246
247impl<HaltReasonTr> SuccessOrHalt<HaltReasonTr> {
248 #[inline]
250 pub fn is_success(self) -> bool {
251 matches!(self, SuccessOrHalt::Success(_))
252 }
253
254 #[inline]
256 pub fn to_success(self) -> Option<SuccessReason> {
257 match self {
258 SuccessOrHalt::Success(reason) => Some(reason),
259 _ => None,
260 }
261 }
262
263 #[inline]
265 pub fn is_revert(self) -> bool {
266 matches!(self, SuccessOrHalt::Revert)
267 }
268
269 #[inline]
271 pub fn is_halt(self) -> bool {
272 matches!(self, SuccessOrHalt::Halt(_))
273 }
274
275 #[inline]
277 pub fn to_halt(self) -> Option<HaltReasonTr> {
278 match self {
279 SuccessOrHalt::Halt(reason) => Some(reason),
280 _ => None,
281 }
282 }
283}
284
285impl<HALT: From<HaltReason>> From<HaltReason> for SuccessOrHalt<HALT> {
286 fn from(reason: HaltReason) -> Self {
287 SuccessOrHalt::Halt(reason.into())
288 }
289}
290
291impl<HaltReasonTr: From<HaltReason>> From<InstructionResult> for SuccessOrHalt<HaltReasonTr> {
292 fn from(result: InstructionResult) -> Self {
293 match result {
294 InstructionResult::Stop => Self::Success(SuccessReason::Stop),
295 InstructionResult::Return => Self::Success(SuccessReason::Return),
296 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
297 InstructionResult::Revert => Self::Revert,
298 InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
299 InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep.into()), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds.into()), InstructionResult::OutOfGas => {
302 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic).into())
303 }
304 InstructionResult::MemoryLimitOOG => {
305 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit).into())
306 }
307 InstructionResult::MemoryOOG => {
308 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory).into())
309 }
310 InstructionResult::PrecompileOOG => {
311 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile).into())
312 }
313 InstructionResult::InvalidOperandOOG => {
314 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
315 }
316 InstructionResult::ReentrancySentryOOG => {
317 Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
318 }
319 InstructionResult::OpcodeNotFound => Self::Halt(HaltReason::OpcodeNotFound.into()),
320 InstructionResult::CallNotAllowedInsideStatic => {
321 Self::Halt(HaltReason::CallNotAllowedInsideStatic.into())
322 } InstructionResult::StateChangeDuringStaticCall => {
324 Self::Halt(HaltReason::StateChangeDuringStaticCall.into())
325 }
326 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode.into()),
327 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump.into()),
328 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated.into()),
329 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow.into()),
330 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow.into()),
331 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset.into()),
332 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision.into()),
333 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment.into()), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()),
335 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()),
336 InstructionResult::CreateContractSizeLimit => {
337 Self::Halt(HaltReason::CreateContractSizeLimit.into())
338 }
339 InstructionResult::CreateContractStartingWithEF => {
340 Self::Halt(HaltReason::CreateContractStartingWithEF.into())
341 }
342 InstructionResult::CreateInitCodeSizeLimit => {
343 Self::Halt(HaltReason::CreateInitCodeSizeLimit.into())
344 }
345 InstructionResult::InvalidEOFInitCode => Self::Revert,
347 InstructionResult::FatalExternalError => Self::FatalExternalError,
348 InstructionResult::InvalidExtDelegateCallTarget => {
349 Self::Internal(InternalResult::InvalidExtDelegateCallTarget)
350 }
351 }
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use crate::InstructionResult;
358
359 #[test]
360 fn exhaustiveness() {
361 match InstructionResult::Stop {
362 return_error!() => {}
363 return_revert!() => {}
364 return_ok!() => {}
365 }
366 }
367
368 #[test]
369 fn test_results() {
370 let ok_results = [
371 InstructionResult::Stop,
372 InstructionResult::Return,
373 InstructionResult::SelfDestruct,
374 ];
375 for result in ok_results {
376 assert!(result.is_ok());
377 assert!(!result.is_revert());
378 assert!(!result.is_error());
379 }
380
381 let revert_results = [
382 InstructionResult::Revert,
383 InstructionResult::CallTooDeep,
384 InstructionResult::OutOfFunds,
385 ];
386 for result in revert_results {
387 assert!(!result.is_ok());
388 assert!(result.is_revert());
389 assert!(!result.is_error());
390 }
391
392 let error_results = [
393 InstructionResult::OutOfGas,
394 InstructionResult::MemoryOOG,
395 InstructionResult::MemoryLimitOOG,
396 InstructionResult::PrecompileOOG,
397 InstructionResult::InvalidOperandOOG,
398 InstructionResult::OpcodeNotFound,
399 InstructionResult::CallNotAllowedInsideStatic,
400 InstructionResult::StateChangeDuringStaticCall,
401 InstructionResult::InvalidFEOpcode,
402 InstructionResult::InvalidJump,
403 InstructionResult::NotActivated,
404 InstructionResult::StackUnderflow,
405 InstructionResult::StackOverflow,
406 InstructionResult::OutOfOffset,
407 InstructionResult::CreateCollision,
408 InstructionResult::OverflowPayment,
409 InstructionResult::PrecompileError,
410 InstructionResult::NonceOverflow,
411 InstructionResult::CreateContractSizeLimit,
412 InstructionResult::CreateContractStartingWithEF,
413 InstructionResult::CreateInitCodeSizeLimit,
414 InstructionResult::FatalExternalError,
415 ];
416 for result in error_results {
417 assert!(!result.is_ok());
418 assert!(!result.is_revert());
419 assert!(result.is_error());
420 }
421 }
422}