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}
374
375impl TransactionError for InvalidTransaction {}
376
377impl core::error::Error for InvalidTransaction {}
378
379impl fmt::Display for InvalidTransaction {
380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 match self {
382 Self::PriorityFeeGreaterThanMaxFee => {
383 write!(f, "priority fee is greater than max fee")
384 }
385 Self::GasPriceLessThanBasefee => {
386 write!(f, "gas price is less than basefee")
387 }
388 Self::CallerGasLimitMoreThanBlock => {
389 write!(f, "caller gas limit exceeds the block gas limit")
390 }
391 Self::CallGasCostMoreThanGasLimit {
392 initial_gas,
393 gas_limit,
394 } => {
395 write!(
396 f,
397 "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
398 )
399 }
400 Self::GasFloorMoreThanGasLimit {
401 gas_floor,
402 gas_limit,
403 } => {
404 write!(
405 f,
406 "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
407 )
408 }
409 Self::RejectCallerWithCode => {
410 write!(f, "reject transactions from senders with deployed code")
411 }
412 Self::LackOfFundForMaxFee { fee, balance } => {
413 write!(f, "lack of funds ({balance}) for max fee ({fee})")
414 }
415 Self::OverflowPaymentInTransaction => {
416 write!(f, "overflow payment in transaction")
417 }
418 Self::NonceOverflowInTransaction => {
419 write!(f, "nonce overflow in transaction")
420 }
421 Self::NonceTooHigh { tx, state } => {
422 write!(f, "nonce {tx} too high, expected {state}")
423 }
424 Self::NonceTooLow { tx, state } => {
425 write!(f, "nonce {tx} too low, expected {state}")
426 }
427 Self::CreateInitCodeSizeLimit => {
428 write!(f, "create initcode size limit")
429 }
430 Self::InvalidChainId => write!(f, "invalid chain ID"),
431 Self::AccessListNotSupported => write!(f, "access list not supported"),
432 Self::MaxFeePerBlobGasNotSupported => {
433 write!(f, "max fee per blob gas not supported")
434 }
435 Self::BlobVersionedHashesNotSupported => {
436 write!(f, "blob versioned hashes not supported")
437 }
438 Self::BlobGasPriceGreaterThanMax => {
439 write!(f, "blob gas price is greater than max fee per blob gas")
440 }
441 Self::EmptyBlobs => write!(f, "empty blobs"),
442 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
443 Self::TooManyBlobs { max, have } => {
444 write!(f, "too many blobs, have {have}, max {max}")
445 }
446 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
447 Self::EofCreateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"),
448 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
449 Self::AuthorizationListInvalidFields => {
450 write!(f, "authorization list tx has invalid fields")
451 }
452 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
453 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
454 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
455 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
456 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
457 }
458 }
459}
460
461#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
463#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
464pub enum InvalidHeader {
465 PrevrandaoNotSet,
467 ExcessBlobGasNotSet,
469}
470
471impl core::error::Error for InvalidHeader {}
472
473impl fmt::Display for InvalidHeader {
474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
475 match self {
476 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
477 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
478 }
479 }
480}
481
482#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
484#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
485pub enum SuccessReason {
486 Stop,
487 Return,
488 SelfDestruct,
489 EofReturnContract,
490}
491
492#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
496#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
497pub enum HaltReason {
498 OutOfGas(OutOfGasError),
499 OpcodeNotFound,
500 InvalidFEOpcode,
501 InvalidJump,
502 NotActivated,
503 StackUnderflow,
504 StackOverflow,
505 OutOfOffset,
506 CreateCollision,
507 PrecompileError,
508 NonceOverflow,
509 CreateContractSizeLimit,
511 CreateContractStartingWithEF,
513 CreateInitCodeSizeLimit,
515
516 OverflowPayment,
518 StateChangeDuringStaticCall,
519 CallNotAllowedInsideStatic,
520 OutOfFunds,
521 CallTooDeep,
522
523 EofAuxDataOverflow,
525 EofAuxDataTooSmall,
527 SubRoutineStackOverflow,
529 InvalidEXTCALLTarget,
531}
532
533#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
534#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
535pub enum OutOfGasError {
536 Basic,
538 MemoryLimit,
540 Memory,
542 Precompile,
544 InvalidOperand,
547 ReentrancySentry,
549}