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::{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}
443
444impl TransactionError for InvalidTransaction {}
445
446impl core::error::Error for InvalidTransaction {}
447
448impl fmt::Display for InvalidTransaction {
449 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450 match self {
451 Self::PriorityFeeGreaterThanMaxFee => {
452 write!(f, "priority fee is greater than max fee")
453 }
454 Self::GasPriceLessThanBasefee => {
455 write!(f, "gas price is less than basefee")
456 }
457 Self::CallerGasLimitMoreThanBlock => {
458 write!(f, "caller gas limit exceeds the block gas limit")
459 }
460 Self::TxGasLimitGreaterThanCap { gas_limit, cap } => {
461 write!(
462 f,
463 "transaction gas limit ({gas_limit}) is greater than the cap ({cap})"
464 )
465 }
466 Self::CallGasCostMoreThanGasLimit {
467 initial_gas,
468 gas_limit,
469 } => {
470 write!(
471 f,
472 "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
473 )
474 }
475 Self::GasFloorMoreThanGasLimit {
476 gas_floor,
477 gas_limit,
478 } => {
479 write!(
480 f,
481 "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
482 )
483 }
484 Self::RejectCallerWithCode => {
485 write!(f, "reject transactions from senders with deployed code")
486 }
487 Self::LackOfFundForMaxFee { fee, balance } => {
488 write!(f, "lack of funds ({balance}) for max fee ({fee})")
489 }
490 Self::OverflowPaymentInTransaction => {
491 write!(f, "overflow payment in transaction")
492 }
493 Self::NonceOverflowInTransaction => {
494 write!(f, "nonce overflow in transaction")
495 }
496 Self::NonceTooHigh { tx, state } => {
497 write!(f, "nonce {tx} too high, expected {state}")
498 }
499 Self::NonceTooLow { tx, state } => {
500 write!(f, "nonce {tx} too low, expected {state}")
501 }
502 Self::CreateInitCodeSizeLimit => {
503 write!(f, "create initcode size limit")
504 }
505 Self::InvalidChainId => write!(f, "invalid chain ID"),
506 Self::MissingChainId => write!(f, "missing chain ID"),
507 Self::AccessListNotSupported => write!(f, "access list not supported"),
508 Self::MaxFeePerBlobGasNotSupported => {
509 write!(f, "max fee per blob gas not supported")
510 }
511 Self::BlobVersionedHashesNotSupported => {
512 write!(f, "blob versioned hashes not supported")
513 }
514 Self::BlobGasPriceGreaterThanMax {
515 block_blob_gas_price,
516 tx_max_fee_per_blob_gas,
517 } => {
518 write!(
519 f,
520 "blob gas price ({block_blob_gas_price}) is greater than max fee per blob gas ({tx_max_fee_per_blob_gas})"
521 )
522 }
523 Self::EmptyBlobs => write!(f, "empty blobs"),
524 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
525 Self::TooManyBlobs { max, have } => {
526 write!(f, "too many blobs, have {have}, max {max}")
527 }
528 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
529 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
530 Self::AuthorizationListInvalidFields => {
531 write!(f, "authorization list tx has invalid fields")
532 }
533 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
534 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
535 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
536 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
537 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
538 Self::Eip7873NotSupported => write!(f, "Eip7873 is not supported"),
539 Self::Eip7873MissingTarget => {
540 write!(f, "Eip7873 initcode transaction should have `to` address")
541 }
542 }
543 }
544}
545
546#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
548#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
549pub enum InvalidHeader {
550 PrevrandaoNotSet,
552 ExcessBlobGasNotSet,
554}
555
556impl core::error::Error for InvalidHeader {}
557
558impl fmt::Display for InvalidHeader {
559 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
560 match self {
561 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
562 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
563 }
564 }
565}
566
567#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
569#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
570pub enum SuccessReason {
571 Stop,
573 Return,
575 SelfDestruct,
577}
578
579#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
583#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
584pub enum HaltReason {
585 OutOfGas(OutOfGasError),
587 OpcodeNotFound,
589 InvalidFEOpcode,
591 InvalidJump,
593 NotActivated,
595 StackUnderflow,
597 StackOverflow,
599 OutOfOffset,
601 CreateCollision,
603 PrecompileError,
605 NonceOverflow,
607 CreateContractSizeLimit,
609 CreateContractStartingWithEF,
611 CreateInitCodeSizeLimit,
613
614 OverflowPayment,
617 StateChangeDuringStaticCall,
619 CallNotAllowedInsideStatic,
621 OutOfFunds,
623 CallTooDeep,
625}
626
627#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
629#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
630pub enum OutOfGasError {
631 Basic,
633 MemoryLimit,
635 Memory,
637 Precompile,
639 InvalidOperand,
642 ReentrancySentry,
644}