1use crate::transaction::TransactionError;
2use core::fmt::{self, Debug};
3use database_interface::DBErrorMarker;
4use primitives::{eof::MAX_INITCODE_COUNT, Address, Bytes, Log, MAX_INITCODE_SIZE, 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 Eip7873EmptyInitcodeList,
377 Eip7873EmptyInitcode {
379 i: usize,
380 },
381 Eip7873TooManyInitcodes {
383 size: usize,
384 },
385 Eip7873InitcodeTooLarge {
387 i: usize,
388 size: usize,
389 },
390 Eip7873MissingTarget,
392}
393
394impl TransactionError for InvalidTransaction {}
395
396impl core::error::Error for InvalidTransaction {}
397
398impl fmt::Display for InvalidTransaction {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 match self {
401 Self::PriorityFeeGreaterThanMaxFee => {
402 write!(f, "priority fee is greater than max fee")
403 }
404 Self::GasPriceLessThanBasefee => {
405 write!(f, "gas price is less than basefee")
406 }
407 Self::CallerGasLimitMoreThanBlock => {
408 write!(f, "caller gas limit exceeds the block gas limit")
409 }
410 Self::CallGasCostMoreThanGasLimit {
411 initial_gas,
412 gas_limit,
413 } => {
414 write!(
415 f,
416 "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
417 )
418 }
419 Self::GasFloorMoreThanGasLimit {
420 gas_floor,
421 gas_limit,
422 } => {
423 write!(
424 f,
425 "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
426 )
427 }
428 Self::RejectCallerWithCode => {
429 write!(f, "reject transactions from senders with deployed code")
430 }
431 Self::LackOfFundForMaxFee { fee, balance } => {
432 write!(f, "lack of funds ({balance}) for max fee ({fee})")
433 }
434 Self::OverflowPaymentInTransaction => {
435 write!(f, "overflow payment in transaction")
436 }
437 Self::NonceOverflowInTransaction => {
438 write!(f, "nonce overflow in transaction")
439 }
440 Self::NonceTooHigh { tx, state } => {
441 write!(f, "nonce {tx} too high, expected {state}")
442 }
443 Self::NonceTooLow { tx, state } => {
444 write!(f, "nonce {tx} too low, expected {state}")
445 }
446 Self::CreateInitCodeSizeLimit => {
447 write!(f, "create initcode size limit")
448 }
449 Self::InvalidChainId => write!(f, "invalid chain ID"),
450 Self::AccessListNotSupported => write!(f, "access list not supported"),
451 Self::MaxFeePerBlobGasNotSupported => {
452 write!(f, "max fee per blob gas not supported")
453 }
454 Self::BlobVersionedHashesNotSupported => {
455 write!(f, "blob versioned hashes not supported")
456 }
457 Self::BlobGasPriceGreaterThanMax => {
458 write!(f, "blob gas price is greater than max fee per blob gas")
459 }
460 Self::EmptyBlobs => write!(f, "empty blobs"),
461 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
462 Self::TooManyBlobs { max, have } => {
463 write!(f, "too many blobs, have {have}, max {max}")
464 }
465 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
466 Self::EofCreateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"),
467 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
468 Self::AuthorizationListInvalidFields => {
469 write!(f, "authorization list tx has invalid fields")
470 }
471 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
472 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
473 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
474 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
475 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
476 Self::Eip7873NotSupported => write!(f, "Eip7873 is not supported"),
477 Self::Eip7873EmptyInitcodeList => {
478 write!(f, "Eip7873 initcode list should have at least one initcode")
479 }
480 Self::Eip7873EmptyInitcode { i } => {
481 write!(f, "Eip7873 initcode {i} can't be zero length")
482 }
483 Self::Eip7873TooManyInitcodes { size } => {
484 write!(
485 f,
486 "Eip7873 initcodes can't be more than {MAX_INITCODE_COUNT}, have {size}"
487 )
488 }
489 Self::Eip7873InitcodeTooLarge { i, size } => {
490 write!(
491 f,
492 "Eip7873 initcode {i} can't be more than {MAX_INITCODE_SIZE}, have {size}"
493 )
494 }
495 Self::Eip7873MissingTarget => {
496 write!(f, "Eip7873 initcode transaction should have `to` address")
497 }
498 }
499 }
500}
501
502#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
504#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
505pub enum InvalidHeader {
506 PrevrandaoNotSet,
508 ExcessBlobGasNotSet,
510}
511
512impl core::error::Error for InvalidHeader {}
513
514impl fmt::Display for InvalidHeader {
515 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
516 match self {
517 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
518 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
519 }
520 }
521}
522
523#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
525#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
526pub enum SuccessReason {
527 Stop,
528 Return,
529 SelfDestruct,
530 EofReturnContract,
531}
532
533#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
537#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
538pub enum HaltReason {
539 OutOfGas(OutOfGasError),
540 OpcodeNotFound,
541 InvalidFEOpcode,
542 InvalidJump,
543 NotActivated,
544 StackUnderflow,
545 StackOverflow,
546 OutOfOffset,
547 CreateCollision,
548 PrecompileError,
549 NonceOverflow,
550 CreateContractSizeLimit,
552 CreateContractStartingWithEF,
554 CreateInitCodeSizeLimit,
556
557 OverflowPayment,
559 StateChangeDuringStaticCall,
560 CallNotAllowedInsideStatic,
561 OutOfFunds,
562 CallTooDeep,
563
564 EofAuxDataOverflow,
566 EofAuxDataTooSmall,
568 SubRoutineStackOverflow,
570 InvalidEXTCALLTarget,
572}
573
574#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
575#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
576pub enum OutOfGasError {
577 Basic,
579 MemoryLimit,
581 Memory,
583 Precompile,
585 InvalidOperand,
588 ReentrancySentry,
590}