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