evm_core/
error.rs

1use crate::Opcode;
2use alloc::borrow::Cow;
3
4/// Trap which indicates that an `ExternalOpcode` has to be handled.
5pub type Trap = Opcode;
6
7/// Capture represents the result of execution.
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub enum Capture<E, T> {
10	/// The machine has exited. It cannot be executed again.
11	Exit(E),
12	/// The machine has trapped. It is waiting for external information, and can
13	/// be executed again.
14	Trap(T),
15}
16
17/// Exit reason.
18#[derive(Clone, Debug, Eq, PartialEq)]
19#[cfg_attr(
20	feature = "with-codec",
21	derive(
22		scale_codec::Encode,
23		scale_codec::Decode,
24		scale_codec::DecodeWithMemTracking,
25		scale_info::TypeInfo
26	)
27)]
28#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
29pub enum ExitReason {
30	/// Machine has succeeded.
31	Succeed(ExitSucceed),
32	/// Machine returns a normal EVM error.
33	Error(ExitError),
34	/// Machine encountered an explicit revert.
35	Revert(ExitRevert),
36	/// Machine encountered an error that is not supposed to be normal EVM
37	/// errors, such as requiring too much memory to execute.
38	Fatal(ExitFatal),
39}
40
41impl ExitReason {
42	/// Whether the exit is succeeded.
43	pub fn is_succeed(&self) -> bool {
44		matches!(self, Self::Succeed(_))
45	}
46
47	/// Whether the exit is error.
48	pub fn is_error(&self) -> bool {
49		matches!(self, Self::Error(_))
50	}
51
52	/// Whether the exit is revert.
53	pub fn is_revert(&self) -> bool {
54		matches!(self, Self::Revert(_))
55	}
56
57	/// Whether the exit is fatal.
58	pub fn is_fatal(&self) -> bool {
59		matches!(self, Self::Fatal(_))
60	}
61}
62
63/// Exit succeed reason.
64#[derive(Clone, Copy, Debug, Eq, PartialEq)]
65#[cfg_attr(
66	feature = "with-codec",
67	derive(
68		scale_codec::Encode,
69		scale_codec::Decode,
70		scale_codec::DecodeWithMemTracking,
71		scale_info::TypeInfo
72	)
73)]
74#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
75pub enum ExitSucceed {
76	/// Machine encountered an explicit stop.
77	Stopped,
78	/// Machine encountered an explicit return.
79	Returned,
80	/// Machine encountered an explicit suicide.
81	Suicided,
82}
83
84impl From<ExitSucceed> for ExitReason {
85	fn from(s: ExitSucceed) -> Self {
86		Self::Succeed(s)
87	}
88}
89
90/// Exit revert reason.
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
92#[cfg_attr(
93	feature = "with-codec",
94	derive(
95		scale_codec::Encode,
96		scale_codec::Decode,
97		scale_codec::DecodeWithMemTracking,
98		scale_info::TypeInfo
99	)
100)]
101#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
102pub enum ExitRevert {
103	/// Machine encountered an explicit revert.
104	Reverted,
105}
106
107impl From<ExitRevert> for ExitReason {
108	fn from(s: ExitRevert) -> Self {
109		Self::Revert(s)
110	}
111}
112
113/// Exit error reason.
114#[derive(Clone, Debug, Eq, PartialEq)]
115#[cfg_attr(
116	feature = "with-codec",
117	derive(
118		scale_codec::Encode,
119		scale_codec::Decode,
120		scale_codec::DecodeWithMemTracking,
121		scale_info::TypeInfo
122	)
123)]
124#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
125pub enum ExitError {
126	/// Trying to pop from an empty stack.
127	#[cfg_attr(feature = "with-codec", codec(index = 0))]
128	StackUnderflow,
129	/// Trying to push into a stack over stack limit.
130	#[cfg_attr(feature = "with-codec", codec(index = 1))]
131	StackOverflow,
132	/// Jump destination is invalid.
133	#[cfg_attr(feature = "with-codec", codec(index = 2))]
134	InvalidJump,
135	/// An opcode accesses memory region, but the region is invalid.
136	#[cfg_attr(feature = "with-codec", codec(index = 3))]
137	InvalidRange,
138	/// Encountered the designated invalid opcode.
139	#[cfg_attr(feature = "with-codec", codec(index = 4))]
140	DesignatedInvalid,
141	/// Call stack is too deep (runtime).
142	#[cfg_attr(feature = "with-codec", codec(index = 5))]
143	CallTooDeep,
144	/// Create opcode encountered collision (runtime).
145	#[cfg_attr(feature = "with-codec", codec(index = 6))]
146	CreateCollision,
147	/// Create init code exceeds limit (runtime).
148	#[cfg_attr(feature = "with-codec", codec(index = 7))]
149	CreateContractLimit,
150
151	/// Invalid opcode during execution or starting byte is 0xef. See [EIP-3541](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3541.md).
152	#[cfg_attr(feature = "with-codec", codec(index = 15))]
153	InvalidCode(Opcode),
154
155	/// An opcode accesses external information, but the request is off offset
156	/// limit (runtime).
157	#[cfg_attr(feature = "with-codec", codec(index = 8))]
158	OutOfOffset,
159	/// Execution runs out of gas (runtime).
160	#[cfg_attr(feature = "with-codec", codec(index = 9))]
161	OutOfGas,
162	/// Not enough fund to start the execution (runtime).
163	#[cfg_attr(feature = "with-codec", codec(index = 10))]
164	OutOfFund,
165
166	/// PC underflowed (unused).
167	#[allow(clippy::upper_case_acronyms)]
168	#[cfg_attr(feature = "with-codec", codec(index = 11))]
169	PCUnderflow,
170
171	/// Attempt to create an empty account (runtime, unused).
172	#[cfg_attr(feature = "with-codec", codec(index = 12))]
173	CreateEmpty,
174
175	/// Other normal errors.
176	#[cfg_attr(feature = "with-codec", codec(index = 13))]
177	Other(Cow<'static, str>),
178
179	/// Nonce reached maximum value of 2^64-1
180	/// https://eips.ethereum.org/EIPS/eip-2681
181	#[cfg_attr(feature = "with-codec", codec(index = 14))]
182	MaxNonce,
183}
184
185impl From<ExitError> for ExitReason {
186	fn from(s: ExitError) -> Self {
187		Self::Error(s)
188	}
189}
190
191/// Exit fatal reason.
192#[derive(Clone, Debug, Eq, PartialEq)]
193#[cfg_attr(
194	feature = "with-codec",
195	derive(
196		scale_codec::Encode,
197		scale_codec::Decode,
198		scale_codec::DecodeWithMemTracking,
199		scale_info::TypeInfo
200	)
201)]
202#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
203pub enum ExitFatal {
204	/// The operation is not supported.
205	NotSupported,
206	/// The trap (interrupt) is unhandled.
207	UnhandledInterrupt,
208	/// The environment explicitly set call errors as fatal error.
209	CallErrorAsFatal(ExitError),
210
211	/// Other fatal errors.
212	Other(Cow<'static, str>),
213}
214
215impl From<ExitFatal> for ExitReason {
216	fn from(s: ExitFatal) -> Self {
217		Self::Fatal(s)
218	}
219}