1use crate::{Address, Bytes, Log, State, U256};
2use core::fmt;
3use std::{boxed::Box, string::String, vec::Vec};
4
5pub type EVMResult<DBError> = EVMResultGeneric<ResultAndState, DBError>;
7
8pub type EVMResultGeneric<T, DBError> = core::result::Result<T, EVMError<DBError>>;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct ResultAndState {
14 pub result: ExecutionResult,
16 pub state: State,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub enum ExecutionResult {
24 Success {
26 reason: SuccessReason,
27 gas_used: u64,
28 gas_refunded: u64,
29 logs: Vec<Log>,
30 output: Output,
31 },
32 Revert { gas_used: u64, output: Bytes },
34 Halt {
36 reason: HaltReason,
37 gas_used: u64,
39 },
40}
41
42impl ExecutionResult {
43 pub fn is_success(&self) -> bool {
47 matches!(self, Self::Success { .. })
48 }
49
50 pub fn is_halt(&self) -> bool {
52 matches!(self, Self::Halt { .. })
53 }
54
55 pub fn output(&self) -> Option<&Bytes> {
59 match self {
60 Self::Success { output, .. } => Some(output.data()),
61 Self::Revert { output, .. } => Some(output),
62 _ => None,
63 }
64 }
65
66 pub fn into_output(self) -> Option<Bytes> {
70 match self {
71 Self::Success { output, .. } => Some(output.into_data()),
72 Self::Revert { output, .. } => Some(output),
73 _ => None,
74 }
75 }
76
77 pub fn logs(&self) -> &[Log] {
79 match self {
80 Self::Success { logs, .. } => logs,
81 _ => &[],
82 }
83 }
84
85 pub fn into_logs(self) -> Vec<Log> {
87 match self {
88 Self::Success { logs, .. } => logs,
89 _ => Vec::new(),
90 }
91 }
92
93 pub fn gas_used(&self) -> u64 {
95 match *self {
96 Self::Success { gas_used, .. }
97 | Self::Revert { gas_used, .. }
98 | Self::Halt { gas_used, .. } => gas_used,
99 }
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Eq, Hash)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
106pub enum Output {
107 Call(Bytes),
108 Create(Bytes, Option<Address>),
109}
110
111impl Output {
112 pub fn into_data(self) -> Bytes {
114 match self {
115 Output::Call(data) => data,
116 Output::Create(data, _) => data,
117 }
118 }
119
120 pub fn data(&self) -> &Bytes {
122 match self {
123 Output::Call(data) => data,
124 Output::Create(data, _) => data,
125 }
126 }
127
128 pub fn address(&self) -> Option<&Address> {
130 match self {
131 Output::Call(_) => None,
132 Output::Create(_, address) => address.as_ref(),
133 }
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, Hash)]
139#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
140pub enum EVMError<DBError> {
141 Transaction(InvalidTransaction),
143 Header(InvalidHeader),
145 Database(DBError),
147 Custom(String),
151}
152
153#[cfg(feature = "std")]
154impl<DBError: std::error::Error + 'static> std::error::Error for EVMError<DBError> {
155 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
156 match self {
157 Self::Transaction(e) => Some(e),
158 Self::Header(e) => Some(e),
159 Self::Database(e) => Some(e),
160 Self::Custom(_) => None,
161 }
162 }
163}
164
165impl<DBError: fmt::Display> fmt::Display for EVMError<DBError> {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 match self {
168 Self::Transaction(e) => write!(f, "transaction validation error: {e}"),
169 Self::Header(e) => write!(f, "header validation error: {e}"),
170 Self::Database(e) => write!(f, "database error: {e}"),
171 Self::Custom(e) => f.write_str(e),
172 }
173 }
174}
175
176impl<DBError> From<InvalidTransaction> for EVMError<DBError> {
177 fn from(value: InvalidTransaction) -> Self {
178 Self::Transaction(value)
179 }
180}
181
182impl<DBError> From<InvalidHeader> for EVMError<DBError> {
183 fn from(value: InvalidHeader) -> Self {
184 Self::Header(value)
185 }
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Hash)]
190#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
191pub enum InvalidTransaction {
192 PriorityFeeGreaterThanMaxFee,
198 GasPriceLessThanBasefee,
200 CallerGasLimitMoreThanBlock,
202 CallGasCostMoreThanGasLimit,
208 RejectCallerWithCode,
210 LackOfFundForMaxFee {
212 fee: Box<U256>,
213 balance: Box<U256>,
214 },
215 OverflowPaymentInTransaction,
217 NonceOverflowInTransaction,
219 NonceTooHigh {
220 tx: u64,
221 state: u64,
222 },
223 NonceTooLow {
224 tx: u64,
225 state: u64,
226 },
227 CreateInitCodeSizeLimit,
229 InvalidChainId,
231 AccessListNotSupported,
233 MaxFeePerBlobGasNotSupported,
235 BlobVersionedHashesNotSupported,
237 BlobGasPriceGreaterThanMax,
239 EmptyBlobs,
241 BlobCreateTransaction,
244 TooManyBlobs,
246 BlobVersionNotSupported,
248 EofInitcodesNotSupported,
250 EofInitcodesNumberLimit,
252 EofInitcodesSizeLimit,
254 EofCrateShouldHaveToAddress,
256 #[cfg(feature = "optimism")]
271 DepositSystemTxPostRegolith,
272 #[cfg(feature = "optimism")]
287 HaltedDepositPostRegolith,
288}
289
290#[cfg(feature = "std")]
291impl std::error::Error for InvalidTransaction {}
292
293impl fmt::Display for InvalidTransaction {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 match self {
296 Self::PriorityFeeGreaterThanMaxFee => {
297 write!(f, "priority fee is greater than max fee")
298 }
299 Self::GasPriceLessThanBasefee => {
300 write!(f, "gas price is less than basefee")
301 }
302 Self::CallerGasLimitMoreThanBlock => {
303 write!(f, "caller gas limit exceeds the block gas limit")
304 }
305 Self::CallGasCostMoreThanGasLimit => {
306 write!(f, "call gas cost exceeds the gas limit")
307 }
308 Self::RejectCallerWithCode => {
309 write!(f, "reject transactions from senders with deployed code")
310 }
311 Self::LackOfFundForMaxFee { fee, balance } => {
312 write!(f, "lack of funds ({balance}) for max fee ({fee})")
313 }
314 Self::OverflowPaymentInTransaction => {
315 write!(f, "overflow payment in transaction")
316 }
317 Self::NonceOverflowInTransaction => {
318 write!(f, "nonce overflow in transaction")
319 }
320 Self::NonceTooHigh { tx, state } => {
321 write!(f, "nonce {tx} too high, expected {state}")
322 }
323 Self::NonceTooLow { tx, state } => {
324 write!(f, "nonce {tx} too low, expected {state}")
325 }
326 Self::CreateInitCodeSizeLimit => {
327 write!(f, "create initcode size limit")
328 }
329 Self::InvalidChainId => write!(f, "invalid chain ID"),
330 Self::AccessListNotSupported => write!(f, "access list not supported"),
331 Self::MaxFeePerBlobGasNotSupported => {
332 write!(f, "max fee per blob gas not supported")
333 }
334 Self::BlobVersionedHashesNotSupported => {
335 write!(f, "blob versioned hashes not supported")
336 }
337 Self::BlobGasPriceGreaterThanMax => {
338 write!(f, "blob gas price is greater than max fee per blob gas")
339 }
340 Self::EmptyBlobs => write!(f, "empty blobs"),
341 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
342 Self::TooManyBlobs => write!(f, "too many blobs"),
343 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
344 Self::EofInitcodesNotSupported => write!(f, "EOF initcodes not supported"),
345 Self::EofCrateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"),
346 Self::EofInitcodesSizeLimit => write!(f, "EOF initcodes size limit"),
347 Self::EofInitcodesNumberLimit => write!(f, "EOF initcodes number limit"),
348 #[cfg(feature = "optimism")]
349 Self::DepositSystemTxPostRegolith => {
350 write!(
351 f,
352 "deposit system transactions post regolith hardfork are not supported"
353 )
354 }
355 #[cfg(feature = "optimism")]
356 Self::HaltedDepositPostRegolith => {
357 write!(
358 f,
359 "deposit transaction halted post-regolith; error will be bubbled up to main return handler"
360 )
361 }
362 }
363 }
364}
365
366#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
368#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
369pub enum InvalidHeader {
370 PrevrandaoNotSet,
372 ExcessBlobGasNotSet,
374}
375
376#[cfg(feature = "std")]
377impl std::error::Error for InvalidHeader {}
378
379impl fmt::Display for InvalidHeader {
380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 match self {
382 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
383 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
384 }
385 }
386}
387
388#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
390#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
391pub enum SuccessReason {
392 Stop,
393 Return,
394 SelfDestruct,
395}
396
397#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
400#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
401pub enum HaltReason {
402 OutOfGas(OutOfGasError),
403 OpcodeNotFound,
404 InvalidFEOpcode,
405 InvalidJump,
406 NotActivated,
407 StackUnderflow,
408 StackOverflow,
409 OutOfOffset,
410 CreateCollision,
411 PrecompileError,
412 NonceOverflow,
413 CreateContractSizeLimit,
415 CreateContractStartingWithEF,
417 CreateInitCodeSizeLimit,
419
420 OverflowPayment,
422 StateChangeDuringStaticCall,
423 CallNotAllowedInsideStatic,
424 OutOfFunds,
425 CallTooDeep,
426
427 #[cfg(feature = "optimism")]
429 FailedDeposit,
430}
431
432#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
433#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
434pub enum OutOfGasError {
435 Basic,
437 MemoryLimit,
439 Memory,
441 Precompile,
443 InvalidOperand,
446}