1use crate::transaction::TransactionError;
11use core::fmt::{self, Debug};
12use database_interface::DBErrorMarker;
13use primitives::{Address, Bytes, Log, U256};
14use std::{boxed::Box, string::String, vec::Vec};
15
16pub trait HaltReasonTr: Clone + Debug + PartialEq + Eq + From<HaltReason> {}
18
19impl<T> HaltReasonTr for T where T: Clone + Debug + PartialEq + Eq + From<HaltReason> {}
20
21#[derive(Clone, Debug, PartialEq, Eq, Hash)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct ResultAndState<R, S> {
25 pub result: R,
27 pub state: S,
29}
30
31pub type ResultVecAndState<R, S> = ResultAndState<Vec<R>, S>;
33
34impl<R, S> ResultAndState<R, S> {
35 pub fn new(result: R, state: S) -> Self {
37 Self { result, state }
38 }
39}
40
41#[derive(Clone, Debug, PartialEq, Eq, Hash)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44pub enum ExecutionResult<HaltReasonTy = HaltReason> {
45 Success {
47 reason: SuccessReason,
49 gas_used: u64,
51 gas_refunded: u64,
53 logs: Vec<Log>,
55 output: Output,
57 },
58 Revert {
60 gas_used: u64,
62 output: Bytes,
64 },
65 Halt {
67 reason: HaltReasonTy,
69 gas_used: u64,
73 },
74}
75
76impl<HaltReasonTy> ExecutionResult<HaltReasonTy> {
77 pub fn is_success(&self) -> bool {
83 matches!(self, Self::Success { .. })
84 }
85
86 pub fn map_haltreason<F, OHR>(self, op: F) -> ExecutionResult<OHR>
88 where
89 F: FnOnce(HaltReasonTy) -> OHR,
90 {
91 match self {
92 Self::Success {
93 reason,
94 gas_used,
95 gas_refunded,
96 logs,
97 output,
98 } => ExecutionResult::Success {
99 reason,
100 gas_used,
101 gas_refunded,
102 logs,
103 output,
104 },
105 Self::Revert { gas_used, output } => ExecutionResult::Revert { gas_used, output },
106 Self::Halt { reason, gas_used } => ExecutionResult::Halt {
107 reason: op(reason),
108 gas_used,
109 },
110 }
111 }
112
113 pub fn created_address(&self) -> Option<Address> {
116 match self {
117 Self::Success { output, .. } => output.address().cloned(),
118 _ => None,
119 }
120 }
121
122 pub fn is_halt(&self) -> bool {
124 matches!(self, Self::Halt { .. })
125 }
126
127 pub fn output(&self) -> Option<&Bytes> {
131 match self {
132 Self::Success { output, .. } => Some(output.data()),
133 Self::Revert { output, .. } => Some(output),
134 _ => None,
135 }
136 }
137
138 pub fn into_output(self) -> Option<Bytes> {
142 match self {
143 Self::Success { output, .. } => Some(output.into_data()),
144 Self::Revert { output, .. } => Some(output),
145 _ => None,
146 }
147 }
148
149 pub fn logs(&self) -> &[Log] {
151 match self {
152 Self::Success { logs, .. } => logs.as_slice(),
153 _ => &[],
154 }
155 }
156
157 pub fn into_logs(self) -> Vec<Log> {
159 match self {
160 Self::Success { logs, .. } => logs,
161 _ => Vec::new(),
162 }
163 }
164
165 pub fn gas_used(&self) -> u64 {
167 match *self {
168 Self::Success { gas_used, .. }
169 | Self::Revert { gas_used, .. }
170 | Self::Halt { gas_used, .. } => gas_used,
171 }
172 }
173}
174
175#[derive(Debug, Clone, PartialEq, Eq, Hash)]
177#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
178pub enum Output {
179 Call(Bytes),
181 Create(Bytes, Option<Address>),
183}
184
185impl Output {
186 pub fn into_data(self) -> Bytes {
188 match self {
189 Output::Call(data) => data,
190 Output::Create(data, _) => data,
191 }
192 }
193
194 pub fn data(&self) -> &Bytes {
196 match self {
197 Output::Call(data) => data,
198 Output::Create(data, _) => data,
199 }
200 }
201
202 pub fn address(&self) -> Option<&Address> {
204 match self {
205 Output::Call(_) => None,
206 Output::Create(_, address) => address.as_ref(),
207 }
208 }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq)]
213#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
214pub enum EVMError<DBError, TransactionError = InvalidTransaction> {
215 Transaction(TransactionError),
217 Header(InvalidHeader),
219 Database(DBError),
221 Custom(String),
225}
226
227impl<DBError: DBErrorMarker, TX> From<DBError> for EVMError<DBError, TX> {
228 fn from(value: DBError) -> Self {
229 Self::Database(value)
230 }
231}
232
233pub trait FromStringError {
235 fn from_string(value: String) -> Self;
237}
238
239impl<DB, TX> FromStringError for EVMError<DB, TX> {
240 fn from_string(value: String) -> Self {
241 Self::Custom(value)
242 }
243}
244
245impl<DB, TXE: From<InvalidTransaction>> From<InvalidTransaction> for EVMError<DB, TXE> {
246 fn from(value: InvalidTransaction) -> Self {
247 Self::Transaction(TXE::from(value))
248 }
249}
250
251impl<DBError, TransactionValidationErrorT> EVMError<DBError, TransactionValidationErrorT> {
252 pub fn map_db_err<F, E>(self, op: F) -> EVMError<E, TransactionValidationErrorT>
254 where
255 F: FnOnce(DBError) -> E,
256 {
257 match self {
258 Self::Transaction(e) => EVMError::Transaction(e),
259 Self::Header(e) => EVMError::Header(e),
260 Self::Database(e) => EVMError::Database(op(e)),
261 Self::Custom(e) => EVMError::Custom(e),
262 }
263 }
264}
265
266impl<DBError, TransactionValidationErrorT> core::error::Error
267 for EVMError<DBError, TransactionValidationErrorT>
268where
269 DBError: core::error::Error + 'static,
270 TransactionValidationErrorT: core::error::Error + 'static,
271{
272 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
273 match self {
274 Self::Transaction(e) => Some(e),
275 Self::Header(e) => Some(e),
276 Self::Database(e) => Some(e),
277 Self::Custom(_) => None,
278 }
279 }
280}
281
282impl<DBError, TransactionValidationErrorT> fmt::Display
283 for EVMError<DBError, TransactionValidationErrorT>
284where
285 DBError: fmt::Display,
286 TransactionValidationErrorT: fmt::Display,
287{
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 match self {
290 Self::Transaction(e) => write!(f, "transaction validation error: {e}"),
291 Self::Header(e) => write!(f, "header validation error: {e}"),
292 Self::Database(e) => write!(f, "database error: {e}"),
293 Self::Custom(e) => f.write_str(e),
294 }
295 }
296}
297
298impl<DBError, TransactionValidationErrorT> From<InvalidHeader>
299 for EVMError<DBError, TransactionValidationErrorT>
300{
301 fn from(value: InvalidHeader) -> Self {
302 Self::Header(value)
303 }
304}
305
306#[derive(Debug, Clone, PartialEq, Eq, Hash)]
308#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
309pub enum InvalidTransaction {
310 PriorityFeeGreaterThanMaxFee,
316 GasPriceLessThanBasefee,
318 CallerGasLimitMoreThanBlock,
320 CallGasCostMoreThanGasLimit {
326 initial_gas: u64,
328 gas_limit: u64,
330 },
331 GasFloorMoreThanGasLimit {
336 gas_floor: u64,
338 gas_limit: u64,
340 },
341 RejectCallerWithCode,
343 LackOfFundForMaxFee {
345 fee: Box<U256>,
347 balance: Box<U256>,
349 },
350 OverflowPaymentInTransaction,
352 NonceOverflowInTransaction,
354 NonceTooHigh {
356 tx: u64,
358 state: u64,
360 },
361 NonceTooLow {
363 tx: u64,
365 state: u64,
367 },
368 CreateInitCodeSizeLimit,
370 InvalidChainId,
372 MissingChainId,
374 TxGasLimitGreaterThanCap {
376 gas_limit: u64,
378 cap: u64,
380 },
381 AccessListNotSupported,
383 MaxFeePerBlobGasNotSupported,
385 BlobVersionedHashesNotSupported,
387 BlobGasPriceGreaterThanMax,
389 EmptyBlobs,
391 BlobCreateTransaction,
395 TooManyBlobs {
397 max: usize,
399 have: usize,
401 },
402 BlobVersionNotSupported,
404 EofCreateShouldHaveToAddress,
406 AuthorizationListNotSupported,
408 AuthorizationListInvalidFields,
410 EmptyAuthorizationList,
412 Eip2930NotSupported,
414 Eip1559NotSupported,
416 Eip4844NotSupported,
418 Eip7702NotSupported,
420 Eip7873NotSupported,
422 Eip7873MissingTarget,
440}
441
442impl TransactionError for InvalidTransaction {}
443
444impl core::error::Error for InvalidTransaction {}
445
446impl fmt::Display for InvalidTransaction {
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 match self {
449 Self::PriorityFeeGreaterThanMaxFee => {
450 write!(f, "priority fee is greater than max fee")
451 }
452 Self::GasPriceLessThanBasefee => {
453 write!(f, "gas price is less than basefee")
454 }
455 Self::CallerGasLimitMoreThanBlock => {
456 write!(f, "caller gas limit exceeds the block gas limit")
457 }
458 Self::TxGasLimitGreaterThanCap { gas_limit, cap } => {
459 write!(
460 f,
461 "transaction gas limit ({gas_limit}) is greater than the cap ({cap})"
462 )
463 }
464 Self::CallGasCostMoreThanGasLimit {
465 initial_gas,
466 gas_limit,
467 } => {
468 write!(
469 f,
470 "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
471 )
472 }
473 Self::GasFloorMoreThanGasLimit {
474 gas_floor,
475 gas_limit,
476 } => {
477 write!(
478 f,
479 "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
480 )
481 }
482 Self::RejectCallerWithCode => {
483 write!(f, "reject transactions from senders with deployed code")
484 }
485 Self::LackOfFundForMaxFee { fee, balance } => {
486 write!(f, "lack of funds ({balance}) for max fee ({fee})")
487 }
488 Self::OverflowPaymentInTransaction => {
489 write!(f, "overflow payment in transaction")
490 }
491 Self::NonceOverflowInTransaction => {
492 write!(f, "nonce overflow in transaction")
493 }
494 Self::NonceTooHigh { tx, state } => {
495 write!(f, "nonce {tx} too high, expected {state}")
496 }
497 Self::NonceTooLow { tx, state } => {
498 write!(f, "nonce {tx} too low, expected {state}")
499 }
500 Self::CreateInitCodeSizeLimit => {
501 write!(f, "create initcode size limit")
502 }
503 Self::InvalidChainId => write!(f, "invalid chain ID"),
504 Self::MissingChainId => write!(f, "missing chain ID"),
505 Self::AccessListNotSupported => write!(f, "access list not supported"),
506 Self::MaxFeePerBlobGasNotSupported => {
507 write!(f, "max fee per blob gas not supported")
508 }
509 Self::BlobVersionedHashesNotSupported => {
510 write!(f, "blob versioned hashes not supported")
511 }
512 Self::BlobGasPriceGreaterThanMax => {
513 write!(f, "blob gas price is greater than max fee per blob gas")
514 }
515 Self::EmptyBlobs => write!(f, "empty blobs"),
516 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
517 Self::TooManyBlobs { max, have } => {
518 write!(f, "too many blobs, have {have}, max {max}")
519 }
520 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
521 Self::EofCreateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"),
522 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
523 Self::AuthorizationListInvalidFields => {
524 write!(f, "authorization list tx has invalid fields")
525 }
526 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
527 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
528 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
529 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
530 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
531 Self::Eip7873NotSupported => write!(f, "Eip7873 is not supported"),
532 Self::Eip7873MissingTarget => {
552 write!(f, "Eip7873 initcode transaction should have `to` address")
553 }
554 }
555 }
556}
557
558#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
560#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
561pub enum InvalidHeader {
562 PrevrandaoNotSet,
564 ExcessBlobGasNotSet,
566}
567
568impl core::error::Error for InvalidHeader {}
569
570impl fmt::Display for InvalidHeader {
571 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
572 match self {
573 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
574 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
575 }
576 }
577}
578
579#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
581#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
582pub enum SuccessReason {
583 Stop,
585 Return,
587 SelfDestruct,
589 EofReturnContract,
591}
592
593#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
597#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
598pub enum HaltReason {
599 OutOfGas(OutOfGasError),
601 OpcodeNotFound,
603 InvalidFEOpcode,
605 InvalidJump,
607 NotActivated,
609 StackUnderflow,
611 StackOverflow,
613 OutOfOffset,
615 CreateCollision,
617 PrecompileError,
619 NonceOverflow,
621 CreateContractSizeLimit,
623 CreateContractStartingWithEF,
625 CreateInitCodeSizeLimit,
627
628 OverflowPayment,
631 StateChangeDuringStaticCall,
633 CallNotAllowedInsideStatic,
635 OutOfFunds,
637 CallTooDeep,
639
640 EofAuxDataOverflow,
642 EofAuxDataTooSmall,
644 SubRoutineStackOverflow,
646 InvalidEXTCALLTarget,
648}
649
650#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
652#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
653pub enum OutOfGasError {
654 Basic,
656 MemoryLimit,
658 Memory,
660 Precompile,
662 InvalidOperand,
665 ReentrancySentry,
667}