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 Precompile(String),
205}
206
207impl<DBError: DBErrorMarker, TX> From<DBError> for EVMError<DBError, TX> {
208 fn from(value: DBError) -> Self {
209 Self::Database(value)
210 }
211}
212
213pub trait FromStringError {
214 fn from_string(value: String) -> Self;
215}
216
217impl<DB, TX> FromStringError for EVMError<DB, TX> {
218 fn from_string(value: String) -> Self {
219 Self::Custom(value)
220 }
221}
222
223impl<DB, TXE: From<InvalidTransaction>> From<InvalidTransaction> for EVMError<DB, TXE> {
224 fn from(value: InvalidTransaction) -> Self {
225 Self::Transaction(TXE::from(value))
226 }
227}
228
229impl<DBError, TransactionValidationErrorT> EVMError<DBError, TransactionValidationErrorT> {
230 pub fn map_db_err<F, E>(self, op: F) -> EVMError<E, TransactionValidationErrorT>
232 where
233 F: FnOnce(DBError) -> E,
234 {
235 match self {
236 Self::Transaction(e) => EVMError::Transaction(e),
237 Self::Header(e) => EVMError::Header(e),
238 Self::Database(e) => EVMError::Database(op(e)),
239 Self::Precompile(e) => EVMError::Precompile(e),
240 Self::Custom(e) => EVMError::Custom(e),
241 }
242 }
243}
244
245impl<DBError, TransactionValidationErrorT> core::error::Error
246 for EVMError<DBError, TransactionValidationErrorT>
247where
248 DBError: core::error::Error + 'static,
249 TransactionValidationErrorT: core::error::Error + 'static,
250{
251 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
252 match self {
253 Self::Transaction(e) => Some(e),
254 Self::Header(e) => Some(e),
255 Self::Database(e) => Some(e),
256 Self::Precompile(_) | Self::Custom(_) => None,
257 }
258 }
259}
260
261impl<DBError, TransactionValidationErrorT> fmt::Display
262 for EVMError<DBError, TransactionValidationErrorT>
263where
264 DBError: fmt::Display,
265 TransactionValidationErrorT: fmt::Display,
266{
267 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268 match self {
269 Self::Transaction(e) => write!(f, "transaction validation error: {e}"),
270 Self::Header(e) => write!(f, "header validation error: {e}"),
271 Self::Database(e) => write!(f, "database error: {e}"),
272 Self::Precompile(e) | Self::Custom(e) => f.write_str(e),
273 }
274 }
275}
276
277impl<DBError, TransactionValidationErrorT> From<InvalidHeader>
278 for EVMError<DBError, TransactionValidationErrorT>
279{
280 fn from(value: InvalidHeader) -> Self {
281 Self::Header(value)
282 }
283}
284
285#[derive(Debug, Clone, PartialEq, Eq, Hash)]
287#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
288pub enum InvalidTransaction {
289 PriorityFeeGreaterThanMaxFee,
295 GasPriceLessThanBasefee,
297 CallerGasLimitMoreThanBlock,
299 CallGasCostMoreThanGasLimit,
305 GasFloorMoreThanGasLimit,
310 RejectCallerWithCode,
312 LackOfFundForMaxFee {
314 fee: Box<U256>,
315 balance: Box<U256>,
316 },
317 OverflowPaymentInTransaction,
319 NonceOverflowInTransaction,
321 NonceTooHigh {
322 tx: u64,
323 state: u64,
324 },
325 NonceTooLow {
326 tx: u64,
327 state: u64,
328 },
329 CreateInitCodeSizeLimit,
331 InvalidChainId,
333 AccessListNotSupported,
335 MaxFeePerBlobGasNotSupported,
337 BlobVersionedHashesNotSupported,
339 BlobGasPriceGreaterThanMax,
341 EmptyBlobs,
343 BlobCreateTransaction,
347 TooManyBlobs {
349 max: usize,
350 have: usize,
351 },
352 BlobVersionNotSupported,
354 EofCrateShouldHaveToAddress,
356 AuthorizationListNotSupported,
358 AuthorizationListInvalidFields,
360 EmptyAuthorizationList,
362 Eip2930NotSupported,
364 Eip1559NotSupported,
366 Eip4844NotSupported,
368 Eip7702NotSupported,
370}
371
372impl TransactionError for InvalidTransaction {}
373
374impl core::error::Error for InvalidTransaction {}
375
376impl fmt::Display for InvalidTransaction {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 match self {
379 Self::PriorityFeeGreaterThanMaxFee => {
380 write!(f, "priority fee is greater than max fee")
381 }
382 Self::GasPriceLessThanBasefee => {
383 write!(f, "gas price is less than basefee")
384 }
385 Self::CallerGasLimitMoreThanBlock => {
386 write!(f, "caller gas limit exceeds the block gas limit")
387 }
388 Self::CallGasCostMoreThanGasLimit => {
389 write!(f, "call gas cost exceeds the gas limit")
390 }
391 Self::GasFloorMoreThanGasLimit => {
392 write!(f, "gas floor exceeds the gas limit")
393 }
394 Self::RejectCallerWithCode => {
395 write!(f, "reject transactions from senders with deployed code")
396 }
397 Self::LackOfFundForMaxFee { fee, balance } => {
398 write!(f, "lack of funds ({balance}) for max fee ({fee})")
399 }
400 Self::OverflowPaymentInTransaction => {
401 write!(f, "overflow payment in transaction")
402 }
403 Self::NonceOverflowInTransaction => {
404 write!(f, "nonce overflow in transaction")
405 }
406 Self::NonceTooHigh { tx, state } => {
407 write!(f, "nonce {tx} too high, expected {state}")
408 }
409 Self::NonceTooLow { tx, state } => {
410 write!(f, "nonce {tx} too low, expected {state}")
411 }
412 Self::CreateInitCodeSizeLimit => {
413 write!(f, "create initcode size limit")
414 }
415 Self::InvalidChainId => write!(f, "invalid chain ID"),
416 Self::AccessListNotSupported => write!(f, "access list not supported"),
417 Self::MaxFeePerBlobGasNotSupported => {
418 write!(f, "max fee per blob gas not supported")
419 }
420 Self::BlobVersionedHashesNotSupported => {
421 write!(f, "blob versioned hashes not supported")
422 }
423 Self::BlobGasPriceGreaterThanMax => {
424 write!(f, "blob gas price is greater than max fee per blob gas")
425 }
426 Self::EmptyBlobs => write!(f, "empty blobs"),
427 Self::BlobCreateTransaction => write!(f, "blob create transaction"),
428 Self::TooManyBlobs { max, have } => {
429 write!(f, "too many blobs, have {have}, max {max}")
430 }
431 Self::BlobVersionNotSupported => write!(f, "blob version not supported"),
432 Self::EofCrateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"),
433 Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"),
434 Self::AuthorizationListInvalidFields => {
435 write!(f, "authorization list tx has invalid fields")
436 }
437 Self::EmptyAuthorizationList => write!(f, "empty authorization list"),
438 Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"),
439 Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"),
440 Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"),
441 Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"),
442 }
443 }
444}
445
446#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
448#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
449pub enum InvalidHeader {
450 PrevrandaoNotSet,
452 ExcessBlobGasNotSet,
454}
455
456impl core::error::Error for InvalidHeader {}
457
458impl fmt::Display for InvalidHeader {
459 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460 match self {
461 Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"),
462 Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"),
463 }
464 }
465}
466
467#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
469#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
470pub enum SuccessReason {
471 Stop,
472 Return,
473 SelfDestruct,
474 EofReturnContract,
475}
476
477#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
481#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
482pub enum HaltReason {
483 OutOfGas(OutOfGasError),
484 OpcodeNotFound,
485 InvalidFEOpcode,
486 InvalidJump,
487 NotActivated,
488 StackUnderflow,
489 StackOverflow,
490 OutOfOffset,
491 CreateCollision,
492 PrecompileError,
493 NonceOverflow,
494 CreateContractSizeLimit,
496 CreateContractStartingWithEF,
498 CreateInitCodeSizeLimit,
500
501 OverflowPayment,
503 StateChangeDuringStaticCall,
504 CallNotAllowedInsideStatic,
505 OutOfFunds,
506 CallTooDeep,
507
508 EofAuxDataOverflow,
510 EofAuxDataTooSmall,
512 SubRoutineStackOverflow,
514 InvalidEXTCALLTarget,
516}
517
518#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
519#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
520pub enum OutOfGasError {
521 Basic,
523 MemoryLimit,
525 Memory,
527 Precompile,
529 InvalidOperand,
532 ReentrancySentry,
534}