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 AccessListNotSupported,
376 MaxFeePerBlobGasNotSupported,
378 BlobVersionedHashesNotSupported,
380 BlobGasPriceGreaterThanMax,
382 EmptyBlobs,
384 BlobCreateTransaction,
388 TooManyBlobs {
390 max: usize,
392 have: usize,
394 },
395 BlobVersionNotSupported,
397 EofCreateShouldHaveToAddress,
399 AuthorizationListNotSupported,
401 AuthorizationListInvalidFields,
403 EmptyAuthorizationList,
405 Eip2930NotSupported,
407 Eip1559NotSupported,
409 Eip4844NotSupported,
411 Eip7702NotSupported,
413 Eip7873NotSupported,
415 Eip7873MissingTarget,
433}
434
435impl TransactionError for InvalidTransaction {}
436
437impl core::error::Error for InvalidTransaction {}
438
439impl fmt::Display for InvalidTransaction {
440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441 match self {
442 Self::PriorityFeeGreaterThanMaxFee => {
443 write!(f, "priority fee is greater than max fee")
444 }
445 Self::GasPriceLessThanBasefee => {
446 write!(f, "gas price is less than basefee")
447 }
448 Self::CallerGasLimitMoreThanBlock => {
449 write!(f, "caller gas limit exceeds the block gas limit")
450 }
451 Self::CallGasCostMoreThanGasLimit {
452 initial_gas,
453 gas_limit,
454 } => {
455 write!(
456 f,
457 "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
458 )
459 }
460 Self::GasFloorMoreThanGasLimit {
461 gas_floor,
462 gas_limit,
463 } => {
464 write!(
465 f,
466 "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
467 )
468 }
469 Self::RejectCallerWithCode => {
470 write!(f, "reject transactions from senders with deployed code")
471 }
472 Self::LackOfFundForMaxFee { fee, balance } => {
473 write!(f, "lack of funds ({balance}) for max fee ({fee})")
474 }
475 Self::OverflowPaymentInTransaction => {
476 write!(f, "overflow payment in transaction")
477 }
478 Self::NonceOverflowInTransaction => {
479 write!(f, "nonce overflow in transaction")
480 }
481 Self::NonceTooHigh { tx, state } => {
482 write!(f, "nonce {tx} too high, expected {state}")
483 }
484 Self::NonceTooLow { tx, state } => {
485 write!(f, "nonce {tx} too low, expected {state}")
486 }
487 Self::CreateInitCodeSizeLimit => {
488 write!(f, "create initcode size limit")
489 }
490 Self::InvalidChainId => write!(f, "invalid chain ID"),
491 Self::MissingChainId => write!(f, "missing chain ID"),
492 Self::AccessListNotSupported => write!(f, "access list not supported"),
493 Self::MaxFeePerBlobGasNotSupported => {
494 write!(f, "max fee per blob gas not supported")
495 }
496 Self::BlobVersionedHashesNotSupported => {
497 write!(f, "blob versioned hashes not supported")
498 }
499 Self::BlobGasPriceGreaterThanMax => {
500 write!(f, "blob gas price is greater than max fee per blob gas")
501 }
502 Self::EmptyBlobs => write!(f, "empty blobs"),
503 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
504 Self::TooManyBlobs { max, have } => {
505 write!(f, "too many blobs, have {have}, max {max}")
506 }
507 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
508 Self::EofCreateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"),
509 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
510 Self::AuthorizationListInvalidFields => {
511 write!(f, "authorization list tx has invalid fields")
512 }
513 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
514 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
515 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
516 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
517 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
518 Self::Eip7873NotSupported => write!(f, "Eip7873 is not supported"),
519 Self::Eip7873MissingTarget => {
539 write!(f, "Eip7873 initcode transaction should have `to` address")
540 }
541 }
542 }
543}
544
545#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
547#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
548pub enum InvalidHeader {
549 PrevrandaoNotSet,
551 ExcessBlobGasNotSet,
553}
554
555impl core::error::Error for InvalidHeader {}
556
557impl fmt::Display for InvalidHeader {
558 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
559 match self {
560 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
561 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
562 }
563 }
564}
565
566#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
568#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
569pub enum SuccessReason {
570 Stop,
572 Return,
574 SelfDestruct,
576 EofReturnContract,
578}
579
580#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
584#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
585pub enum HaltReason {
586 OutOfGas(OutOfGasError),
588 OpcodeNotFound,
590 InvalidFEOpcode,
592 InvalidJump,
594 NotActivated,
596 StackUnderflow,
598 StackOverflow,
600 OutOfOffset,
602 CreateCollision,
604 PrecompileError,
606 NonceOverflow,
608 CreateContractSizeLimit,
610 CreateContractStartingWithEF,
612 CreateInitCodeSizeLimit,
614
615 OverflowPayment,
618 StateChangeDuringStaticCall,
620 CallNotAllowedInsideStatic,
622 OutOfFunds,
624 CallTooDeep,
626
627 EofAuxDataOverflow,
629 EofAuxDataTooSmall,
631 SubRoutineStackOverflow,
633 InvalidEXTCALLTarget,
635}
636
637#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
639#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
640pub enum OutOfGasError {
641 Basic,
643 MemoryLimit,
645 Memory,
647 Precompile,
649 InvalidOperand,
652 ReentrancySentry,
654}