1use crate::{Address, Bytes, EvmState, Log, 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: EvmState,
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 Precompile(String),
153}
154
155impl<DBError> EVMError<DBError> {
156 pub fn map_db_err<F, E>(self, op: F) -> EVMError<E>
158 where
159 F: FnOnce(DBError) -> E,
160 {
161 match self {
162 Self::Transaction(e) => EVMError::Transaction(e),
163 Self::Header(e) => EVMError::Header(e),
164 Self::Database(e) => EVMError::Database(op(e)),
165 Self::Precompile(e) => EVMError::Precompile(e),
166 Self::Custom(e) => EVMError::Custom(e),
167 }
168 }
169}
170
171#[cfg(feature = "std")]
172impl<DBError: std::error::Error + 'static> std::error::Error for EVMError<DBError> {
173 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
174 match self {
175 Self::Transaction(e) => Some(e),
176 Self::Header(e) => Some(e),
177 Self::Database(e) => Some(e),
178 Self::Precompile(_) | Self::Custom(_) => None,
179 }
180 }
181}
182
183impl<DBError: fmt::Display> fmt::Display for EVMError<DBError> {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 match self {
186 Self::Transaction(e) => write!(f, "transaction validation error: {e}"),
187 Self::Header(e) => write!(f, "header validation error: {e}"),
188 Self::Database(e) => write!(f, "database error: {e}"),
189 Self::Precompile(e) | Self::Custom(e) => f.write_str(e),
190 }
191 }
192}
193
194impl<DBError> From<InvalidTransaction> for EVMError<DBError> {
195 fn from(value: InvalidTransaction) -> Self {
196 Self::Transaction(value)
197 }
198}
199
200impl<DBError> From<InvalidHeader> for EVMError<DBError> {
201 fn from(value: InvalidHeader) -> Self {
202 Self::Header(value)
203 }
204}
205
206#[cfg(feature = "optimism")]
208#[derive(Debug, Clone, PartialEq, Eq, Hash)]
209#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
210pub enum OptimismInvalidTransaction {
211 #[cfg(feature = "optimism")]
226 DepositSystemTxPostRegolith,
227 #[cfg(feature = "optimism")]
242 HaltedDepositPostRegolith,
243}
244
245#[derive(Debug, Clone, PartialEq, Eq, Hash)]
247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
248pub enum InvalidTransaction {
249 PriorityFeeGreaterThanMaxFee,
255 GasPriceLessThanBasefee,
257 CallerGasLimitMoreThanBlock,
259 CallGasCostMoreThanGasLimit,
265 RejectCallerWithCode,
267 LackOfFundForMaxFee {
269 fee: Box<U256>,
270 balance: Box<U256>,
271 },
272 OverflowPaymentInTransaction,
274 NonceOverflowInTransaction,
276 NonceTooHigh {
277 tx: u64,
278 state: u64,
279 },
280 NonceTooLow {
281 tx: u64,
282 state: u64,
283 },
284 CreateInitCodeSizeLimit,
286 InvalidChainId,
288 AccessListNotSupported,
290 MaxFeePerBlobGasNotSupported,
292 BlobVersionedHashesNotSupported,
294 BlobGasPriceGreaterThanMax,
296 EmptyBlobs,
298 BlobCreateTransaction,
301 TooManyBlobs {
303 max: usize,
304 have: usize,
305 },
306 BlobVersionNotSupported,
308 EofCrateShouldHaveToAddress,
310 AuthorizationListNotSupported,
312 AuthorizationListInvalidFields,
314 EmptyAuthorizationList,
316 #[cfg(feature = "optimism")]
318 OptimismError(OptimismInvalidTransaction),
319}
320
321#[cfg(feature = "std")]
322impl std::error::Error for InvalidTransaction {}
323
324#[cfg(feature = "optimism")]
325impl fmt::Display for OptimismInvalidTransaction {
326 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327 match self {
328 Self::DepositSystemTxPostRegolith => write!(
329 f,
330 "deposit system transactions post regolith hardfork are not supported"
331 ),
332 Self::HaltedDepositPostRegolith => write!(
333 f,
334 "deposit transaction halted post-regolith; error will be bubbled up to main return handler"
335 ),
336 }
337 }
338}
339
340impl fmt::Display for InvalidTransaction {
341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342 match self {
343 Self::PriorityFeeGreaterThanMaxFee => {
344 write!(f, "priority fee is greater than max fee")
345 }
346 Self::GasPriceLessThanBasefee => {
347 write!(f, "gas price is less than basefee")
348 }
349 Self::CallerGasLimitMoreThanBlock => {
350 write!(f, "caller gas limit exceeds the block gas limit")
351 }
352 Self::CallGasCostMoreThanGasLimit => {
353 write!(f, "call gas cost exceeds the gas limit")
354 }
355 Self::RejectCallerWithCode => {
356 write!(f, "reject transactions from senders with deployed code")
357 }
358 Self::LackOfFundForMaxFee { fee, balance } => {
359 write!(f, "lack of funds ({balance}) for max fee ({fee})")
360 }
361 Self::OverflowPaymentInTransaction => {
362 write!(f, "overflow payment in transaction")
363 }
364 Self::NonceOverflowInTransaction => {
365 write!(f, "nonce overflow in transaction")
366 }
367 Self::NonceTooHigh { tx, state } => {
368 write!(f, "nonce {tx} too high, expected {state}")
369 }
370 Self::NonceTooLow { tx, state } => {
371 write!(f, "nonce {tx} too low, expected {state}")
372 }
373 Self::CreateInitCodeSizeLimit => {
374 write!(f, "create initcode size limit")
375 }
376 Self::InvalidChainId => write!(f, "invalid chain ID"),
377 Self::AccessListNotSupported => write!(f, "access list not supported"),
378 Self::MaxFeePerBlobGasNotSupported => {
379 write!(f, "max fee per blob gas not supported")
380 }
381 Self::BlobVersionedHashesNotSupported => {
382 write!(f, "blob versioned hashes not supported")
383 }
384 Self::BlobGasPriceGreaterThanMax => {
385 write!(f, "blob gas price is greater than max fee per blob gas")
386 }
387 Self::EmptyBlobs => write!(f, "empty blobs"),
388 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
389 Self::TooManyBlobs { max, have } => {
390 write!(f, "too many blobs, have {have}, max {max}")
391 }
392 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
393 Self::EofCrateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"),
394 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
395 Self::AuthorizationListInvalidFields => {
396 write!(f, "authorization list tx has invalid fields")
397 }
398 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
399 #[cfg(feature = "optimism")]
400 Self::OptimismError(op_error) => op_error.fmt(f),
401 }
402 }
403}
404
405#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
407#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
408pub enum InvalidHeader {
409 PrevrandaoNotSet,
411 ExcessBlobGasNotSet,
413}
414
415#[cfg(feature = "std")]
416impl std::error::Error for InvalidHeader {}
417
418impl fmt::Display for InvalidHeader {
419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420 match self {
421 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
422 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
423 }
424 }
425}
426
427#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
429#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
430pub enum SuccessReason {
431 Stop,
432 Return,
433 SelfDestruct,
434 EofReturnContract,
435}
436
437#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
440#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
441pub enum HaltReason {
442 OutOfGas(OutOfGasError),
443 OpcodeNotFound,
444 InvalidFEOpcode,
445 InvalidJump,
446 NotActivated,
447 StackUnderflow,
448 StackOverflow,
449 OutOfOffset,
450 CreateCollision,
451 PrecompileError,
452 NonceOverflow,
453 CreateContractSizeLimit,
455 CreateContractStartingWithEF,
457 CreateInitCodeSizeLimit,
459
460 OverflowPayment,
462 StateChangeDuringStaticCall,
463 CallNotAllowedInsideStatic,
464 OutOfFunds,
465 CallTooDeep,
466
467 EofAuxDataOverflow,
469 EofAuxDataTooSmall,
471 EOFFunctionStackOverflow,
473 InvalidEXTCALLTarget,
475
476 #[cfg(feature = "optimism")]
478 FailedDeposit,
479}
480
481#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
482#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
483pub enum OutOfGasError {
484 Basic,
486 MemoryLimit,
488 Memory,
490 Precompile,
492 InvalidOperand,
495}