1use crate::primitives::{HaltReason, OutOfGasError, SuccessReason};
2
3#[repr(u8)]
4#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub enum InstructionResult {
7 #[default]
9 Continue = 0x00,
10 Stop,
11 Return,
12 SelfDestruct,
13 ReturnContract,
14
15 Revert = 0x10, CallTooDeep,
18 OutOfFunds,
19
20 CallOrCreate = 0x20,
22
23 OutOfGas = 0x50,
25 MemoryOOG,
26 MemoryLimitOOG,
27 PrecompileOOG,
28 InvalidOperandOOG,
29 OpcodeNotFound,
30 CallNotAllowedInsideStatic,
31 StateChangeDuringStaticCall,
32 InvalidFEOpcode,
33 InvalidJump,
34 NotActivated,
35 StackUnderflow,
36 StackOverflow,
37 OutOfOffset,
38 CreateCollision,
39 OverflowPayment,
40 PrecompileError,
41 NonceOverflow,
42 CreateContractSizeLimit,
44 CreateContractStartingWithEF,
46 CreateInitCodeSizeLimit,
48 FatalExternalError,
50 ReturnContractInNotInitEOF,
52 EOFOpcodeDisabledInLegacy,
54 EOFFunctionStackOverflow,
56}
57
58impl From<SuccessReason> for InstructionResult {
59 fn from(value: SuccessReason) -> Self {
60 match value {
61 SuccessReason::Return => InstructionResult::Return,
62 SuccessReason::Stop => InstructionResult::Stop,
63 SuccessReason::SelfDestruct => InstructionResult::SelfDestruct,
64 }
65 }
66}
67
68impl From<HaltReason> for InstructionResult {
69 fn from(value: HaltReason) -> Self {
70 match value {
71 HaltReason::OutOfGas(error) => match error {
72 OutOfGasError::Basic => Self::OutOfGas,
73 OutOfGasError::InvalidOperand => Self::InvalidOperandOOG,
74 OutOfGasError::Memory => Self::MemoryOOG,
75 OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
76 OutOfGasError::Precompile => Self::PrecompileOOG,
77 },
78 HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
79 HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
80 HaltReason::InvalidJump => Self::InvalidJump,
81 HaltReason::NotActivated => Self::NotActivated,
82 HaltReason::StackOverflow => Self::StackOverflow,
83 HaltReason::StackUnderflow => Self::StackUnderflow,
84 HaltReason::OutOfOffset => Self::OutOfOffset,
85 HaltReason::CreateCollision => Self::CreateCollision,
86 HaltReason::PrecompileError => Self::PrecompileError,
87 HaltReason::NonceOverflow => Self::NonceOverflow,
88 HaltReason::CreateContractSizeLimit => Self::CreateContractSizeLimit,
89 HaltReason::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
90 HaltReason::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
91 HaltReason::OverflowPayment => Self::OverflowPayment,
92 HaltReason::StateChangeDuringStaticCall => Self::StateChangeDuringStaticCall,
93 HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
94 HaltReason::OutOfFunds => Self::OutOfFunds,
95 HaltReason::CallTooDeep => Self::CallTooDeep,
96 #[cfg(feature = "optimism")]
97 HaltReason::FailedDeposit => Self::FatalExternalError,
98 }
99 }
100}
101
102#[macro_export]
103macro_rules! return_ok {
104 () => {
105 InstructionResult::Continue
106 | InstructionResult::Stop
107 | InstructionResult::Return
108 | InstructionResult::SelfDestruct
109 | InstructionResult::ReturnContract
110 };
111}
112
113#[macro_export]
114macro_rules! return_revert {
115 () => {
116 InstructionResult::Revert | InstructionResult::CallTooDeep | InstructionResult::OutOfFunds
117 };
118}
119
120#[macro_export]
121macro_rules! return_error {
122 () => {
123 InstructionResult::OutOfGas
124 | InstructionResult::MemoryOOG
125 | InstructionResult::MemoryLimitOOG
126 | InstructionResult::PrecompileOOG
127 | InstructionResult::InvalidOperandOOG
128 | InstructionResult::OpcodeNotFound
129 | InstructionResult::CallNotAllowedInsideStatic
130 | InstructionResult::StateChangeDuringStaticCall
131 | InstructionResult::InvalidFEOpcode
132 | InstructionResult::InvalidJump
133 | InstructionResult::NotActivated
134 | InstructionResult::StackUnderflow
135 | InstructionResult::StackOverflow
136 | InstructionResult::OutOfOffset
137 | InstructionResult::CreateCollision
138 | InstructionResult::OverflowPayment
139 | InstructionResult::PrecompileError
140 | InstructionResult::NonceOverflow
141 | InstructionResult::CreateContractSizeLimit
142 | InstructionResult::CreateContractStartingWithEF
143 | InstructionResult::CreateInitCodeSizeLimit
144 | InstructionResult::FatalExternalError
145 | InstructionResult::ReturnContractInNotInitEOF
146 | InstructionResult::EOFOpcodeDisabledInLegacy
147 | InstructionResult::EOFFunctionStackOverflow
148 };
149}
150
151impl InstructionResult {
152 #[inline]
154 pub const fn is_ok(self) -> bool {
155 matches!(self, crate::return_ok!())
156 }
157
158 #[inline]
160 pub const fn is_revert(self) -> bool {
161 matches!(self, crate::return_revert!())
162 }
163
164 #[inline]
166 pub const fn is_error(self) -> bool {
167 matches!(self, return_error!())
168 }
169}
170
171#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
172pub enum SuccessOrHalt {
173 Success(SuccessReason),
174 Revert,
175 Halt(HaltReason),
176 FatalExternalError,
177 InternalContinue,
179 InternalCallOrCreate,
181}
182
183impl SuccessOrHalt {
184 #[inline]
186 pub fn is_success(self) -> bool {
187 matches!(self, SuccessOrHalt::Success(_))
188 }
189
190 #[inline]
192 pub fn to_success(self) -> Option<SuccessReason> {
193 match self {
194 SuccessOrHalt::Success(reason) => Some(reason),
195 _ => None,
196 }
197 }
198
199 #[inline]
201 pub fn is_revert(self) -> bool {
202 matches!(self, SuccessOrHalt::Revert)
203 }
204
205 #[inline]
207 pub fn is_halt(self) -> bool {
208 matches!(self, SuccessOrHalt::Halt(_))
209 }
210
211 #[inline]
213 pub fn to_halt(self) -> Option<HaltReason> {
214 match self {
215 SuccessOrHalt::Halt(reason) => Some(reason),
216 _ => None,
217 }
218 }
219}
220
221impl From<InstructionResult> for SuccessOrHalt {
222 fn from(result: InstructionResult) -> Self {
223 match result {
224 InstructionResult::Continue => Self::InternalContinue, InstructionResult::Stop => Self::Success(SuccessReason::Stop),
226 InstructionResult::Return => Self::Success(SuccessReason::Return),
227 InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
228 InstructionResult::Revert => Self::Revert,
229 InstructionResult::CallOrCreate => Self::InternalCallOrCreate, InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep), InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds), InstructionResult::OutOfGas => Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic)),
233 InstructionResult::MemoryLimitOOG => {
234 Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit))
235 }
236 InstructionResult::MemoryOOG => Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory)),
237 InstructionResult::PrecompileOOG => {
238 Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile))
239 }
240 InstructionResult::InvalidOperandOOG => {
241 Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand))
242 }
243 InstructionResult::OpcodeNotFound | InstructionResult::ReturnContractInNotInitEOF => {
244 Self::Halt(HaltReason::OpcodeNotFound)
245 }
246 InstructionResult::CallNotAllowedInsideStatic => {
247 Self::Halt(HaltReason::CallNotAllowedInsideStatic)
248 } InstructionResult::StateChangeDuringStaticCall => {
250 Self::Halt(HaltReason::StateChangeDuringStaticCall)
251 }
252 InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode),
253 InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump),
254 InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated),
255 InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow),
256 InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow),
257 InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset),
258 InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision),
259 InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment), InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError),
261 InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow),
262 InstructionResult::CreateContractSizeLimit
263 | InstructionResult::CreateContractStartingWithEF => {
264 Self::Halt(HaltReason::CreateContractSizeLimit)
265 }
266 InstructionResult::CreateInitCodeSizeLimit => {
267 Self::Halt(HaltReason::CreateInitCodeSizeLimit)
268 }
269 InstructionResult::FatalExternalError => Self::FatalExternalError,
270 InstructionResult::EOFOpcodeDisabledInLegacy => Self::Halt(HaltReason::OpcodeNotFound),
271 InstructionResult::EOFFunctionStackOverflow => Self::FatalExternalError,
272 InstructionResult::ReturnContract => {
273 panic!("Unexpected EOF internal Return Contract")
274 }
275 }
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use crate::InstructionResult;
282
283 #[test]
284 fn all_results_are_covered() {
285 match InstructionResult::Continue {
286 return_error!() => {}
287 return_revert!() => {}
288 return_ok!() => {}
289 InstructionResult::CallOrCreate => {}
290 }
291 }
292
293 #[test]
294 fn test_results() {
295 let ok_results = vec![
296 InstructionResult::Continue,
297 InstructionResult::Stop,
298 InstructionResult::Return,
299 InstructionResult::SelfDestruct,
300 ];
301
302 for result in ok_results {
303 assert!(result.is_ok());
304 assert!(!result.is_revert());
305 assert!(!result.is_error());
306 }
307
308 let revert_results = vec![
309 InstructionResult::Revert,
310 InstructionResult::CallTooDeep,
311 InstructionResult::OutOfFunds,
312 ];
313
314 for result in revert_results {
315 assert!(!result.is_ok());
316 assert!(result.is_revert());
317 assert!(!result.is_error());
318 }
319
320 let error_results = vec![
321 InstructionResult::OutOfGas,
322 InstructionResult::MemoryOOG,
323 InstructionResult::MemoryLimitOOG,
324 InstructionResult::PrecompileOOG,
325 InstructionResult::InvalidOperandOOG,
326 InstructionResult::OpcodeNotFound,
327 InstructionResult::CallNotAllowedInsideStatic,
328 InstructionResult::StateChangeDuringStaticCall,
329 InstructionResult::InvalidFEOpcode,
330 InstructionResult::InvalidJump,
331 InstructionResult::NotActivated,
332 InstructionResult::StackUnderflow,
333 InstructionResult::StackOverflow,
334 InstructionResult::OutOfOffset,
335 InstructionResult::CreateCollision,
336 InstructionResult::OverflowPayment,
337 InstructionResult::PrecompileError,
338 InstructionResult::NonceOverflow,
339 InstructionResult::CreateContractSizeLimit,
340 InstructionResult::CreateContractStartingWithEF,
341 InstructionResult::CreateInitCodeSizeLimit,
342 InstructionResult::FatalExternalError,
343 ];
344
345 for result in error_results {
346 assert!(!result.is_ok());
347 assert!(!result.is_revert());
348 assert!(result.is_error());
349 }
350 }
351}