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> = ExecResultAndState<ExecutionResult<H>>;
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 EmptyBlobs,
406 BlobCreateTransaction,
410 TooManyBlobs {
412 max: usize,
414 have: usize,
416 },
417 BlobVersionNotSupported,
419 AuthorizationListNotSupported,
421 AuthorizationListInvalidFields,
423 EmptyAuthorizationList,
425 Eip2930NotSupported,
427 Eip1559NotSupported,
429 Eip4844NotSupported,
431 Eip7702NotSupported,
433 Eip7873NotSupported,
435 Eip7873MissingTarget,
437}
438
439impl TransactionError for InvalidTransaction {}
440
441impl core::error::Error for InvalidTransaction {}
442
443impl fmt::Display for InvalidTransaction {
444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445 match self {
446 Self::PriorityFeeGreaterThanMaxFee => {
447 write!(f, "priority fee is greater than max fee")
448 }
449 Self::GasPriceLessThanBasefee => {
450 write!(f, "gas price is less than basefee")
451 }
452 Self::CallerGasLimitMoreThanBlock => {
453 write!(f, "caller gas limit exceeds the block gas limit")
454 }
455 Self::TxGasLimitGreaterThanCap { gas_limit, cap } => {
456 write!(
457 f,
458 "transaction gas limit ({gas_limit}) is greater than the cap ({cap})"
459 )
460 }
461 Self::CallGasCostMoreThanGasLimit {
462 initial_gas,
463 gas_limit,
464 } => {
465 write!(
466 f,
467 "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
468 )
469 }
470 Self::GasFloorMoreThanGasLimit {
471 gas_floor,
472 gas_limit,
473 } => {
474 write!(
475 f,
476 "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
477 )
478 }
479 Self::RejectCallerWithCode => {
480 write!(f, "reject transactions from senders with deployed code")
481 }
482 Self::LackOfFundForMaxFee { fee, balance } => {
483 write!(f, "lack of funds ({balance}) for max fee ({fee})")
484 }
485 Self::OverflowPaymentInTransaction => {
486 write!(f, "overflow payment in transaction")
487 }
488 Self::NonceOverflowInTransaction => {
489 write!(f, "nonce overflow in transaction")
490 }
491 Self::NonceTooHigh { tx, state } => {
492 write!(f, "nonce {tx} too high, expected {state}")
493 }
494 Self::NonceTooLow { tx, state } => {
495 write!(f, "nonce {tx} too low, expected {state}")
496 }
497 Self::CreateInitCodeSizeLimit => {
498 write!(f, "create initcode size limit")
499 }
500 Self::InvalidChainId => write!(f, "invalid chain ID"),
501 Self::MissingChainId => write!(f, "missing chain ID"),
502 Self::AccessListNotSupported => write!(f, "access list not supported"),
503 Self::MaxFeePerBlobGasNotSupported => {
504 write!(f, "max fee per blob gas not supported")
505 }
506 Self::BlobVersionedHashesNotSupported => {
507 write!(f, "blob versioned hashes not supported")
508 }
509 Self::BlobGasPriceGreaterThanMax => {
510 write!(f, "blob gas price is greater than max fee per blob gas")
511 }
512 Self::EmptyBlobs => write!(f, "empty blobs"),
513 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
514 Self::TooManyBlobs { max, have } => {
515 write!(f, "too many blobs, have {have}, max {max}")
516 }
517 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
518 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
519 Self::AuthorizationListInvalidFields => {
520 write!(f, "authorization list tx has invalid fields")
521 }
522 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
523 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
524 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
525 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
526 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
527 Self::Eip7873NotSupported => write!(f, "Eip7873 is not supported"),
528 Self::Eip7873MissingTarget => {
529 write!(f, "Eip7873 initcode transaction should have `to` address")
530 }
531 }
532 }
533}
534
535#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
537#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
538pub enum InvalidHeader {
539 PrevrandaoNotSet,
541 ExcessBlobGasNotSet,
543}
544
545impl core::error::Error for InvalidHeader {}
546
547impl fmt::Display for InvalidHeader {
548 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
549 match self {
550 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
551 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
552 }
553 }
554}
555
556#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
558#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
559pub enum SuccessReason {
560 Stop,
562 Return,
564 SelfDestruct,
566}
567
568#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
572#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
573pub enum HaltReason {
574 OutOfGas(OutOfGasError),
576 OpcodeNotFound,
578 InvalidFEOpcode,
580 InvalidJump,
582 NotActivated,
584 StackUnderflow,
586 StackOverflow,
588 OutOfOffset,
590 CreateCollision,
592 PrecompileError,
594 NonceOverflow,
596 CreateContractSizeLimit,
598 CreateContractStartingWithEF,
600 CreateInitCodeSizeLimit,
602
603 OverflowPayment,
606 StateChangeDuringStaticCall,
608 CallNotAllowedInsideStatic,
610 OutOfFunds,
612 CallTooDeep,
614}
615
616#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
618#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
619pub enum OutOfGasError {
620 Basic,
622 MemoryLimit,
624 Memory,
626 Precompile,
628 InvalidOperand,
631 ReentrancySentry,
633}