1use crate::transaction::TransactionError;
2use core::fmt::{self, Debug};
3use database_interface::DBErrorMarker;
4use primitives::{Address, Bytes, Log, U256};
5use state::EvmState;
6use std::{boxed::Box, string::String, vec::Vec};
7
8pub trait HaltReasonTr: Clone + Debug + PartialEq + Eq + From<HaltReason> {}
9
10impl<T> HaltReasonTr for T where T: Clone + Debug + PartialEq + Eq + From<HaltReason> {}
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct ResultAndState<HaltReasonTy = HaltReason> {
15 pub result: ExecutionResult<HaltReasonTy>,
17 pub state: EvmState,
19}
20
21impl<HaltReasonTy> ResultAndState<HaltReasonTy> {
22 pub fn map_haltreason<F, OHR>(self, op: F) -> ResultAndState<OHR>
24 where
25 F: FnOnce(HaltReasonTy) -> OHR,
26 {
27 ResultAndState {
28 result: self.result.map_haltreason(op),
29 state: self.state,
30 }
31 }
32}
33
34#[derive(Clone, Debug, PartialEq, Eq, Hash)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub enum ExecutionResult<HaltReasonTy = HaltReason> {
38 Success {
40 reason: SuccessReason,
41 gas_used: u64,
42 gas_refunded: u64,
43 logs: Vec<Log>,
44 output: Output,
45 },
46 Revert { gas_used: u64, output: Bytes },
48 Halt {
50 reason: HaltReasonTy,
51 gas_used: u64,
53 },
54}
55
56impl<HaltReasonTy> ExecutionResult<HaltReasonTy> {
57 pub fn is_success(&self) -> bool {
63 matches!(self, Self::Success { .. })
64 }
65
66 pub fn map_haltreason<F, OHR>(self, op: F) -> ExecutionResult<OHR>
68 where
69 F: FnOnce(HaltReasonTy) -> OHR,
70 {
71 match self {
72 Self::Success {
73 reason,
74 gas_used,
75 gas_refunded,
76 logs,
77 output,
78 } => ExecutionResult::Success {
79 reason,
80 gas_used,
81 gas_refunded,
82 logs,
83 output,
84 },
85 Self::Revert { gas_used, output } => ExecutionResult::Revert { gas_used, output },
86 Self::Halt { reason, gas_used } => ExecutionResult::Halt {
87 reason: op(reason),
88 gas_used,
89 },
90 }
91 }
92
93 pub fn created_address(&self) -> Option<Address> {
96 match self {
97 Self::Success { output, .. } => output.address().cloned(),
98 _ => None,
99 }
100 }
101
102 pub fn is_halt(&self) -> bool {
104 matches!(self, Self::Halt { .. })
105 }
106
107 pub fn output(&self) -> Option<&Bytes> {
111 match self {
112 Self::Success { output, .. } => Some(output.data()),
113 Self::Revert { output, .. } => Some(output),
114 _ => None,
115 }
116 }
117
118 pub fn into_output(self) -> Option<Bytes> {
122 match self {
123 Self::Success { output, .. } => Some(output.into_data()),
124 Self::Revert { output, .. } => Some(output),
125 _ => None,
126 }
127 }
128
129 pub fn logs(&self) -> &[Log] {
131 match self {
132 Self::Success { logs, .. } => logs.as_slice(),
133 _ => &[],
134 }
135 }
136
137 pub fn into_logs(self) -> Vec<Log> {
139 match self {
140 Self::Success { logs, .. } => logs,
141 _ => Vec::new(),
142 }
143 }
144
145 pub fn gas_used(&self) -> u64 {
147 match *self {
148 Self::Success { gas_used, .. }
149 | Self::Revert { gas_used, .. }
150 | Self::Halt { gas_used, .. } => gas_used,
151 }
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq, Hash)]
157#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
158pub enum Output {
159 Call(Bytes),
160 Create(Bytes, Option<Address>),
161}
162
163impl Output {
164 pub fn into_data(self) -> Bytes {
166 match self {
167 Output::Call(data) => data,
168 Output::Create(data, _) => data,
169 }
170 }
171
172 pub fn data(&self) -> &Bytes {
174 match self {
175 Output::Call(data) => data,
176 Output::Create(data, _) => data,
177 }
178 }
179
180 pub fn address(&self) -> Option<&Address> {
182 match self {
183 Output::Call(_) => None,
184 Output::Create(_, address) => address.as_ref(),
185 }
186 }
187}
188
189#[derive(Debug, Clone, PartialEq, Eq)]
191#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
192pub enum EVMError<DBError, TransactionError = InvalidTransaction> {
193 Transaction(TransactionError),
195 Header(InvalidHeader),
197 Database(DBError),
199 Custom(String),
203}
204
205impl<DBError: DBErrorMarker, TX> From<DBError> for EVMError<DBError, TX> {
206 fn from(value: DBError) -> Self {
207 Self::Database(value)
208 }
209}
210
211pub trait FromStringError {
212 fn from_string(value: String) -> Self;
213}
214
215impl<DB, TX> FromStringError for EVMError<DB, TX> {
216 fn from_string(value: String) -> Self {
217 Self::Custom(value)
218 }
219}
220
221impl<DB, TXE: From<InvalidTransaction>> From<InvalidTransaction> for EVMError<DB, TXE> {
222 fn from(value: InvalidTransaction) -> Self {
223 Self::Transaction(TXE::from(value))
224 }
225}
226
227impl<DBError, TransactionValidationErrorT> EVMError<DBError, TransactionValidationErrorT> {
228 pub fn map_db_err<F, E>(self, op: F) -> EVMError<E, TransactionValidationErrorT>
230 where
231 F: FnOnce(DBError) -> E,
232 {
233 match self {
234 Self::Transaction(e) => EVMError::Transaction(e),
235 Self::Header(e) => EVMError::Header(e),
236 Self::Database(e) => EVMError::Database(op(e)),
237 Self::Custom(e) => EVMError::Custom(e),
238 }
239 }
240}
241
242impl<DBError, TransactionValidationErrorT> core::error::Error
243 for EVMError<DBError, TransactionValidationErrorT>
244where
245 DBError: core::error::Error + 'static,
246 TransactionValidationErrorT: core::error::Error + 'static,
247{
248 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
249 match self {
250 Self::Transaction(e) => Some(e),
251 Self::Header(e) => Some(e),
252 Self::Database(e) => Some(e),
253 Self::Custom(_) => None,
254 }
255 }
256}
257
258impl<DBError, TransactionValidationErrorT> fmt::Display
259 for EVMError<DBError, TransactionValidationErrorT>
260where
261 DBError: fmt::Display,
262 TransactionValidationErrorT: fmt::Display,
263{
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 match self {
266 Self::Transaction(e) => write!(f, "transaction validation error: {e}"),
267 Self::Header(e) => write!(f, "header validation error: {e}"),
268 Self::Database(e) => write!(f, "database error: {e}"),
269 Self::Custom(e) => f.write_str(e),
270 }
271 }
272}
273
274impl<DBError, TransactionValidationErrorT> From<InvalidHeader>
275 for EVMError<DBError, TransactionValidationErrorT>
276{
277 fn from(value: InvalidHeader) -> Self {
278 Self::Header(value)
279 }
280}
281
282#[derive(Debug, Clone, PartialEq, Eq, Hash)]
284#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
285pub enum InvalidTransaction {
286 PriorityFeeGreaterThanMaxFee,
292 GasPriceLessThanBasefee,
294 CallerGasLimitMoreThanBlock,
296 CallGasCostMoreThanGasLimit {
302 initial_gas: u64,
303 gas_limit: u64,
304 },
305 GasFloorMoreThanGasLimit {
310 gas_floor: u64,
311 gas_limit: u64,
312 },
313 RejectCallerWithCode,
315 LackOfFundForMaxFee {
317 fee: Box<U256>,
318 balance: Box<U256>,
319 },
320 OverflowPaymentInTransaction,
322 NonceOverflowInTransaction,
324 NonceTooHigh {
325 tx: u64,
326 state: u64,
327 },
328 NonceTooLow {
329 tx: u64,
330 state: u64,
331 },
332 CreateInitCodeSizeLimit,
334 InvalidChainId,
336 AccessListNotSupported,
338 MaxFeePerBlobGasNotSupported,
340 BlobVersionedHashesNotSupported,
342 BlobGasPriceGreaterThanMax,
344 EmptyBlobs,
346 BlobCreateTransaction,
350 TooManyBlobs {
352 max: usize,
353 have: usize,
354 },
355 BlobVersionNotSupported,
357 EofCreateShouldHaveToAddress,
359 AuthorizationListNotSupported,
361 AuthorizationListInvalidFields,
363 EmptyAuthorizationList,
365 Eip2930NotSupported,
367 Eip1559NotSupported,
369 Eip4844NotSupported,
371 Eip7702NotSupported,
373 Eip7873NotSupported,
375 Eip7873MissingTarget,
393}
394
395impl TransactionError for InvalidTransaction {}
396
397impl core::error::Error for InvalidTransaction {}
398
399impl fmt::Display for InvalidTransaction {
400 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401 match self {
402 Self::PriorityFeeGreaterThanMaxFee => {
403 write!(f, "priority fee is greater than max fee")
404 }
405 Self::GasPriceLessThanBasefee => {
406 write!(f, "gas price is less than basefee")
407 }
408 Self::CallerGasLimitMoreThanBlock => {
409 write!(f, "caller gas limit exceeds the block gas limit")
410 }
411 Self::CallGasCostMoreThanGasLimit {
412 initial_gas,
413 gas_limit,
414 } => {
415 write!(
416 f,
417 "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
418 )
419 }
420 Self::GasFloorMoreThanGasLimit {
421 gas_floor,
422 gas_limit,
423 } => {
424 write!(
425 f,
426 "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
427 )
428 }
429 Self::RejectCallerWithCode => {
430 write!(f, "reject transactions from senders with deployed code")
431 }
432 Self::LackOfFundForMaxFee { fee, balance } => {
433 write!(f, "lack of funds ({balance}) for max fee ({fee})")
434 }
435 Self::OverflowPaymentInTransaction => {
436 write!(f, "overflow payment in transaction")
437 }
438 Self::NonceOverflowInTransaction => {
439 write!(f, "nonce overflow in transaction")
440 }
441 Self::NonceTooHigh { tx, state } => {
442 write!(f, "nonce {tx} too high, expected {state}")
443 }
444 Self::NonceTooLow { tx, state } => {
445 write!(f, "nonce {tx} too low, expected {state}")
446 }
447 Self::CreateInitCodeSizeLimit => {
448 write!(f, "create initcode size limit")
449 }
450 Self::InvalidChainId => write!(f, "invalid chain ID"),
451 Self::AccessListNotSupported => write!(f, "access list not supported"),
452 Self::MaxFeePerBlobGasNotSupported => {
453 write!(f, "max fee per blob gas not supported")
454 }
455 Self::BlobVersionedHashesNotSupported => {
456 write!(f, "blob versioned hashes not supported")
457 }
458 Self::BlobGasPriceGreaterThanMax => {
459 write!(f, "blob gas price is greater than max fee per blob gas")
460 }
461 Self::EmptyBlobs => write!(f, "empty blobs"),
462 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
463 Self::TooManyBlobs { max, have } => {
464 write!(f, "too many blobs, have {have}, max {max}")
465 }
466 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
467 Self::EofCreateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"),
468 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
469 Self::AuthorizationListInvalidFields => {
470 write!(f, "authorization list tx has invalid fields")
471 }
472 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
473 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
474 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
475 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
476 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
477 Self::Eip7873NotSupported => write!(f, "Eip7873 is not supported"),
478 Self::Eip7873MissingTarget => {
498 write!(f, "Eip7873 initcode transaction should have `to` address")
499 }
500 }
501 }
502}
503
504#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
506#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
507pub enum InvalidHeader {
508 PrevrandaoNotSet,
510 ExcessBlobGasNotSet,
512}
513
514impl core::error::Error for InvalidHeader {}
515
516impl fmt::Display for InvalidHeader {
517 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
518 match self {
519 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
520 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
521 }
522 }
523}
524
525#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
527#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
528pub enum SuccessReason {
529 Stop,
530 Return,
531 SelfDestruct,
532 EofReturnContract,
533}
534
535#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
539#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
540pub enum HaltReason {
541 OutOfGas(OutOfGasError),
542 OpcodeNotFound,
543 InvalidFEOpcode,
544 InvalidJump,
545 NotActivated,
546 StackUnderflow,
547 StackOverflow,
548 OutOfOffset,
549 CreateCollision,
550 PrecompileError,
551 NonceOverflow,
552 CreateContractSizeLimit,
554 CreateContractStartingWithEF,
556 CreateInitCodeSizeLimit,
558
559 OverflowPayment,
561 StateChangeDuringStaticCall,
562 CallNotAllowedInsideStatic,
563 OutOfFunds,
564 CallTooDeep,
565
566 EofAuxDataOverflow,
568 EofAuxDataTooSmall,
570 SubRoutineStackOverflow,
572 InvalidEXTCALLTarget,
574}
575
576#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
577#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
578pub enum OutOfGasError {
579 Basic,
581 MemoryLimit,
583 Memory,
585 Precompile,
587 InvalidOperand,
590 ReentrancySentry,
592}