1use crate::{context::ContextError, transaction::TransactionError};
11use core::fmt::{self, Debug};
12use database_interface::DBErrorMarker;
13use primitives::{Address, Bytes, Log, U256};
14use state::EvmState;
15use std::{borrow::Cow, boxed::Box, string::String, vec::Vec};
16
17pub trait HaltReasonTr: Clone + Debug + PartialEq + Eq + From<HaltReason> {}
19
20impl<T> HaltReasonTr for T where T: Clone + Debug + PartialEq + Eq + From<HaltReason> {}
21
22#[derive(Clone, Debug, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct ExecResultAndState<R, S = EvmState> {
26 pub result: R,
28 pub state: S,
30}
31
32pub type ResultAndState<H = HaltReason, S = EvmState> = ExecResultAndState<ExecutionResult<H>, S>;
34
35pub type ResultVecAndState<R, S> = ExecResultAndState<Vec<R>, S>;
37
38impl<R, S> ExecResultAndState<R, S> {
39 pub fn new(result: R, state: S) -> Self {
41 Self { result, state }
42 }
43}
44
45#[derive(Clone, Debug, PartialEq, Eq, Hash)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub enum ExecutionResult<HaltReasonTy = HaltReason> {
49 Success {
51 reason: SuccessReason,
53 gas_used: u64,
55 gas_refunded: u64,
57 logs: Vec<Log>,
59 output: Output,
61 },
62 Revert {
64 gas_used: u64,
66 output: Bytes,
68 },
69 Halt {
71 reason: HaltReasonTy,
73 gas_used: u64,
77 },
78}
79
80impl<HaltReasonTy> ExecutionResult<HaltReasonTy> {
81 pub fn is_success(&self) -> bool {
87 matches!(self, Self::Success { .. })
88 }
89
90 pub fn map_haltreason<F, OHR>(self, op: F) -> ExecutionResult<OHR>
92 where
93 F: FnOnce(HaltReasonTy) -> OHR,
94 {
95 match self {
96 Self::Success {
97 reason,
98 gas_used,
99 gas_refunded,
100 logs,
101 output,
102 } => ExecutionResult::Success {
103 reason,
104 gas_used,
105 gas_refunded,
106 logs,
107 output,
108 },
109 Self::Revert { gas_used, output } => ExecutionResult::Revert { gas_used, output },
110 Self::Halt { reason, gas_used } => ExecutionResult::Halt {
111 reason: op(reason),
112 gas_used,
113 },
114 }
115 }
116
117 pub fn created_address(&self) -> Option<Address> {
120 match self {
121 Self::Success { output, .. } => output.address().cloned(),
122 _ => None,
123 }
124 }
125
126 pub fn is_halt(&self) -> bool {
128 matches!(self, Self::Halt { .. })
129 }
130
131 pub fn output(&self) -> Option<&Bytes> {
135 match self {
136 Self::Success { output, .. } => Some(output.data()),
137 Self::Revert { output, .. } => Some(output),
138 _ => None,
139 }
140 }
141
142 pub fn into_output(self) -> Option<Bytes> {
146 match self {
147 Self::Success { output, .. } => Some(output.into_data()),
148 Self::Revert { output, .. } => Some(output),
149 _ => None,
150 }
151 }
152
153 pub fn logs(&self) -> &[Log] {
155 match self {
156 Self::Success { logs, .. } => logs.as_slice(),
157 _ => &[],
158 }
159 }
160
161 pub fn into_logs(self) -> Vec<Log> {
163 match self {
164 Self::Success { logs, .. } => logs,
165 _ => Vec::new(),
166 }
167 }
168
169 pub fn gas_used(&self) -> u64 {
171 match *self {
172 Self::Success { gas_used, .. }
173 | Self::Revert { gas_used, .. }
174 | Self::Halt { gas_used, .. } => gas_used,
175 }
176 }
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, Hash)]
181#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
182pub enum Output {
183 Call(Bytes),
185 Create(Bytes, Option<Address>),
187}
188
189impl Output {
190 pub fn into_data(self) -> Bytes {
192 match self {
193 Output::Call(data) => data,
194 Output::Create(data, _) => data,
195 }
196 }
197
198 pub fn data(&self) -> &Bytes {
200 match self {
201 Output::Call(data) => data,
202 Output::Create(data, _) => data,
203 }
204 }
205
206 pub fn address(&self) -> Option<&Address> {
208 match self {
209 Output::Call(_) => None,
210 Output::Create(_, address) => address.as_ref(),
211 }
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
217#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
218pub enum EVMError<DBError, TransactionError = InvalidTransaction> {
219 Transaction(TransactionError),
221 Header(InvalidHeader),
223 Database(DBError),
225 Custom(String),
229}
230
231impl<DBError, TransactionValidationErrorT> From<ContextError<DBError>>
232 for EVMError<DBError, TransactionValidationErrorT>
233{
234 fn from(value: ContextError<DBError>) -> Self {
235 match value {
236 ContextError::Db(e) => Self::Database(e),
237 ContextError::Custom(e) => Self::Custom(e),
238 }
239 }
240}
241
242impl<DBError: DBErrorMarker, TX> From<DBError> for EVMError<DBError, TX> {
243 fn from(value: DBError) -> Self {
244 Self::Database(value)
245 }
246}
247
248pub trait FromStringError {
250 fn from_string(value: String) -> Self;
252}
253
254impl<DB, TX> FromStringError for EVMError<DB, TX> {
255 fn from_string(value: String) -> Self {
256 Self::Custom(value)
257 }
258}
259
260impl<DB, TXE: From<InvalidTransaction>> From<InvalidTransaction> for EVMError<DB, TXE> {
261 fn from(value: InvalidTransaction) -> Self {
262 Self::Transaction(TXE::from(value))
263 }
264}
265
266impl<DBError, TransactionValidationErrorT> EVMError<DBError, TransactionValidationErrorT> {
267 pub fn map_db_err<F, E>(self, op: F) -> EVMError<E, TransactionValidationErrorT>
269 where
270 F: FnOnce(DBError) -> E,
271 {
272 match self {
273 Self::Transaction(e) => EVMError::Transaction(e),
274 Self::Header(e) => EVMError::Header(e),
275 Self::Database(e) => EVMError::Database(op(e)),
276 Self::Custom(e) => EVMError::Custom(e),
277 }
278 }
279}
280
281impl<DBError, TransactionValidationErrorT> core::error::Error
282 for EVMError<DBError, TransactionValidationErrorT>
283where
284 DBError: core::error::Error + 'static,
285 TransactionValidationErrorT: core::error::Error + 'static,
286{
287 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
288 match self {
289 Self::Transaction(e) => Some(e),
290 Self::Header(e) => Some(e),
291 Self::Database(e) => Some(e),
292 Self::Custom(_) => None,
293 }
294 }
295}
296
297impl<DBError, TransactionValidationErrorT> fmt::Display
298 for EVMError<DBError, TransactionValidationErrorT>
299where
300 DBError: fmt::Display,
301 TransactionValidationErrorT: fmt::Display,
302{
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 match self {
305 Self::Transaction(e) => write!(f, "transaction validation error: {e}"),
306 Self::Header(e) => write!(f, "header validation error: {e}"),
307 Self::Database(e) => write!(f, "database error: {e}"),
308 Self::Custom(e) => f.write_str(e),
309 }
310 }
311}
312
313impl<DBError, TransactionValidationErrorT> From<InvalidHeader>
314 for EVMError<DBError, TransactionValidationErrorT>
315{
316 fn from(value: InvalidHeader) -> Self {
317 Self::Header(value)
318 }
319}
320
321#[derive(Debug, Clone, PartialEq, Eq, Hash)]
323#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
324pub enum InvalidTransaction {
325 PriorityFeeGreaterThanMaxFee,
331 GasPriceLessThanBasefee,
333 CallerGasLimitMoreThanBlock,
335 CallGasCostMoreThanGasLimit {
341 initial_gas: u64,
343 gas_limit: u64,
345 },
346 GasFloorMoreThanGasLimit {
351 gas_floor: u64,
353 gas_limit: u64,
355 },
356 RejectCallerWithCode,
358 LackOfFundForMaxFee {
360 fee: Box<U256>,
362 balance: Box<U256>,
364 },
365 OverflowPaymentInTransaction,
367 NonceOverflowInTransaction,
369 NonceTooHigh {
371 tx: u64,
373 state: u64,
375 },
376 NonceTooLow {
378 tx: u64,
380 state: u64,
382 },
383 CreateInitCodeSizeLimit,
385 InvalidChainId,
387 MissingChainId,
389 TxGasLimitGreaterThanCap {
391 gas_limit: u64,
393 cap: u64,
395 },
396 AccessListNotSupported,
398 MaxFeePerBlobGasNotSupported,
400 BlobVersionedHashesNotSupported,
402 BlobGasPriceGreaterThanMax {
404 block_blob_gas_price: u128,
406 tx_max_fee_per_blob_gas: u128,
408 },
409 EmptyBlobs,
411 BlobCreateTransaction,
415 TooManyBlobs {
417 max: usize,
419 have: usize,
421 },
422 BlobVersionNotSupported,
424 AuthorizationListNotSupported,
426 AuthorizationListInvalidFields,
428 EmptyAuthorizationList,
430 Eip2930NotSupported,
432 Eip1559NotSupported,
434 Eip4844NotSupported,
436 Eip7702NotSupported,
438 Eip7873NotSupported,
440 Eip7873MissingTarget,
442 Str(Cow<'static, str>),
444}
445
446impl TransactionError for InvalidTransaction {}
447
448impl core::error::Error for InvalidTransaction {}
449
450impl fmt::Display for InvalidTransaction {
451 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452 match self {
453 Self::PriorityFeeGreaterThanMaxFee => {
454 write!(f, "priority fee is greater than max fee")
455 }
456 Self::GasPriceLessThanBasefee => {
457 write!(f, "gas price is less than basefee")
458 }
459 Self::CallerGasLimitMoreThanBlock => {
460 write!(f, "caller gas limit exceeds the block gas limit")
461 }
462 Self::TxGasLimitGreaterThanCap { gas_limit, cap } => {
463 write!(
464 f,
465 "transaction gas limit ({gas_limit}) is greater than the cap ({cap})"
466 )
467 }
468 Self::CallGasCostMoreThanGasLimit {
469 initial_gas,
470 gas_limit,
471 } => {
472 write!(
473 f,
474 "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
475 )
476 }
477 Self::GasFloorMoreThanGasLimit {
478 gas_floor,
479 gas_limit,
480 } => {
481 write!(
482 f,
483 "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
484 )
485 }
486 Self::RejectCallerWithCode => {
487 write!(f, "reject transactions from senders with deployed code")
488 }
489 Self::LackOfFundForMaxFee { fee, balance } => {
490 write!(f, "lack of funds ({balance}) for max fee ({fee})")
491 }
492 Self::OverflowPaymentInTransaction => {
493 write!(f, "overflow payment in transaction")
494 }
495 Self::NonceOverflowInTransaction => {
496 write!(f, "nonce overflow in transaction")
497 }
498 Self::NonceTooHigh { tx, state } => {
499 write!(f, "nonce {tx} too high, expected {state}")
500 }
501 Self::NonceTooLow { tx, state } => {
502 write!(f, "nonce {tx} too low, expected {state}")
503 }
504 Self::CreateInitCodeSizeLimit => {
505 write!(f, "create initcode size limit")
506 }
507 Self::InvalidChainId => write!(f, "invalid chain ID"),
508 Self::MissingChainId => write!(f, "missing chain ID"),
509 Self::AccessListNotSupported => write!(f, "access list not supported"),
510 Self::MaxFeePerBlobGasNotSupported => {
511 write!(f, "max fee per blob gas not supported")
512 }
513 Self::BlobVersionedHashesNotSupported => {
514 write!(f, "blob versioned hashes not supported")
515 }
516 Self::BlobGasPriceGreaterThanMax {
517 block_blob_gas_price,
518 tx_max_fee_per_blob_gas,
519 } => {
520 write!(
521 f,
522 "blob gas price ({block_blob_gas_price}) is greater than max fee per blob gas ({tx_max_fee_per_blob_gas})"
523 )
524 }
525 Self::EmptyBlobs => write!(f, "empty blobs"),
526 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
527 Self::TooManyBlobs { max, have } => {
528 write!(f, "too many blobs, have {have}, max {max}")
529 }
530 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
531 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
532 Self::AuthorizationListInvalidFields => {
533 write!(f, "authorization list tx has invalid fields")
534 }
535 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
536 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
537 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
538 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
539 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
540 Self::Eip7873NotSupported => write!(f, "Eip7873 is not supported"),
541 Self::Eip7873MissingTarget => {
542 write!(f, "Eip7873 initcode transaction should have `to` address")
543 }
544 Self::Str(msg) => f.write_str(msg),
545 }
546 }
547}
548
549#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
551#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
552pub enum InvalidHeader {
553 PrevrandaoNotSet,
555 ExcessBlobGasNotSet,
557}
558
559impl core::error::Error for InvalidHeader {}
560
561impl fmt::Display for InvalidHeader {
562 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
563 match self {
564 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
565 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
566 }
567 }
568}
569
570#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
572#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
573pub enum SuccessReason {
574 Stop,
576 Return,
578 SelfDestruct,
580}
581
582#[derive(Debug, Clone, PartialEq, Eq, Hash)]
586#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
587pub enum HaltReason {
588 OutOfGas(OutOfGasError),
590 OpcodeNotFound,
592 InvalidFEOpcode,
594 InvalidJump,
596 NotActivated,
598 StackUnderflow,
600 StackOverflow,
602 OutOfOffset,
604 CreateCollision,
606 PrecompileError,
608 PrecompileErrorWithContext(String),
610 NonceOverflow,
612 CreateContractSizeLimit,
614 CreateContractStartingWithEF,
616 CreateInitCodeSizeLimit,
618
619 OverflowPayment,
622 StateChangeDuringStaticCall,
624 CallNotAllowedInsideStatic,
626 OutOfFunds,
628 CallTooDeep,
630}
631
632#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
634#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
635pub enum OutOfGasError {
636 Basic,
638 MemoryLimit,
640 Memory,
642 Precompile,
644 InvalidOperand,
647 ReentrancySentry,
649}
650
651#[derive(Debug, Clone, PartialEq, Eq)]
653#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
654pub struct TransactionIndexedError<Error> {
655 pub error: Error,
657 pub transaction_index: usize,
659}
660
661impl<Error> TransactionIndexedError<Error> {
662 #[must_use]
664 pub fn new(error: Error, transaction_index: usize) -> Self {
665 Self {
666 error,
667 transaction_index,
668 }
669 }
670
671 pub fn error(&self) -> &Error {
673 &self.error
674 }
675
676 #[must_use]
678 pub fn into_error(self) -> Error {
679 self.error
680 }
681}
682
683impl<Error: fmt::Display> fmt::Display for TransactionIndexedError<Error> {
684 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
685 write!(
686 f,
687 "transaction {} failed: {}",
688 self.transaction_index, self.error
689 )
690 }
691}
692
693impl<Error: core::error::Error + 'static> core::error::Error for TransactionIndexedError<Error> {
694 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
695 Some(&self.error)
696 }
697}
698
699impl From<&'static str> for InvalidTransaction {
700 fn from(s: &'static str) -> Self {
701 Self::Str(Cow::Borrowed(s))
702 }
703}
704
705impl From<String> for InvalidTransaction {
706 fn from(s: String) -> Self {
707 Self::Str(Cow::Owned(s))
708 }
709}