1use bytes::Bytes;
2use derive_more::derive::Display;
3use ethrex_common::{
4 Address, H256, U256,
5 types::{FakeExponentialError, Log},
6};
7use serde::{Deserialize, Serialize};
8use thiserror;
9
10#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize, Display)]
11pub enum VMError {
12 Internal(#[from] InternalError),
14 TxValidation(#[from] TxValidationError),
16 ExceptionalHalt(#[from] ExceptionalHalt),
18 RevertOpcode,
20}
21
22impl VMError {
23 pub fn should_propagate(&self) -> bool {
26 matches!(self, VMError::Internal(_))
27 }
28
29 pub fn is_revert_opcode(&self) -> bool {
31 matches!(self, VMError::RevertOpcode)
32 }
33}
34
35impl From<DatabaseError> for VMError {
36 fn from(err: DatabaseError) -> Self {
37 VMError::Internal(InternalError::Database(err))
38 }
39}
40
41impl From<PrecompileError> for VMError {
42 fn from(err: PrecompileError) -> Self {
43 VMError::ExceptionalHalt(ExceptionalHalt::Precompile(err))
44 }
45}
46
47impl From<std::array::TryFromSliceError> for VMError {
50 fn from(_: std::array::TryFromSliceError) -> Self {
51 VMError::Internal(InternalError::TypeConversion)
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
56pub enum ExceptionalHalt {
57 #[error("Stack Underflow")]
58 StackUnderflow,
59 #[error("Stack Overflow")]
60 StackOverflow,
61 #[error("Invalid Jump")]
62 InvalidJump,
63 #[error("Opcode Not Allowed In Static Context")]
64 OpcodeNotAllowedInStaticContext,
65 #[error("Invalid Contract Prefix")]
66 InvalidContractPrefix,
67 #[error("Very Large Number")]
68 VeryLargeNumber,
69 #[error("Invalid Opcode")]
70 InvalidOpcode,
71 #[error("Address Already Occupied")]
72 AddressAlreadyOccupied,
73 #[error("Contract Output Too Big")]
74 ContractOutputTooBig,
75 #[error("Offset out of bounds")]
76 OutOfBounds,
77 #[error("Out Of Gas")]
78 OutOfGas,
79 #[error("Precompile execution error: {0}")]
80 Precompile(#[from] PrecompileError),
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
86pub enum TxValidationError {
87 #[error("Sender account {0} shouldn't be a contract")]
88 SenderNotEOA(Address),
89 #[error("Insufficient account funds")]
90 InsufficientAccountFunds,
91 #[error("Nonce is max")]
92 NonceIsMax,
93 #[error("Nonce mismatch: expected {expected}, got {actual}")]
94 NonceMismatch { expected: u64, actual: u64 },
95 #[error("Initcode size exceeded, max size: {max_size}, actual size: {actual_size}")]
96 InitcodeSizeExceeded { max_size: usize, actual_size: usize },
97 #[error("Priority fee {priority_fee} is greater than max fee per gas {max_fee_per_gas}")]
98 PriorityGreaterThanMaxFeePerGas {
99 priority_fee: U256,
100 max_fee_per_gas: U256,
101 },
102 #[error("Transaction gas limit lower than the minimum gas cost to execute the transaction")]
103 IntrinsicGasTooLow,
104 #[error("Transaction gas limit lower than the gas cost floor for calldata tokens")]
105 IntrinsicGasBelowFloorGasCost,
106 #[error(
107 "Gas allowance exceeded. Block gas limit: {block_gas_limit}, transaction gas limit: {tx_gas_limit}"
108 )]
109 GasAllowanceExceeded {
110 block_gas_limit: u64,
111 tx_gas_limit: u64,
112 },
113 #[error("Insufficient max fee per gas")]
114 InsufficientMaxFeePerGas,
115 #[error(
116 "Insufficient max fee per blob gas. Expected at least {base_fee_per_blob_gas}, got: {tx_max_fee_per_blob_gas}"
117 )]
118 InsufficientMaxFeePerBlobGas {
119 base_fee_per_blob_gas: U256,
120 tx_max_fee_per_blob_gas: U256,
121 },
122 #[error("Type 3 transactions are not supported before the Cancun fork")]
123 Type3TxPreFork,
124 #[error("Type 3 transaction without blobs")]
125 Type3TxZeroBlobs,
126 #[error("Invalid blob versioned hash")]
127 Type3TxInvalidBlobVersionedHash,
128 #[error(
129 "Blob count exceeded. Max blob count: {max_blob_count}, actual blob count: {actual_blob_count}"
130 )]
131 Type3TxBlobCountExceeded {
132 max_blob_count: usize,
133 actual_blob_count: usize,
134 },
135 #[error("Contract creation in blob transaction")]
136 Type3TxContractCreation,
137 #[error("Type 4 transactions are not supported before the Prague fork")]
138 Type4TxPreFork,
139 #[error("Empty authorization list in type 4 transaction")]
140 Type4TxAuthorizationListIsEmpty,
141 #[error("Contract creation in type 4 transaction")]
142 Type4TxContractCreation,
143 #[error("Gas limit price product overflow")]
144 GasLimitPriceProductOverflow,
145 #[error(
146 "Transaction gas limit exceeds maximum. Transaction hash: {tx_hash}, transaction gas limit: {tx_gas_limit}"
147 )]
148 TxMaxGasLimitExceeded { tx_hash: H256, tx_gas_limit: u64 },
149}
150
151#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
152pub enum InternalError {
153 #[error("Arithmetic operation overflowed")]
154 Overflow,
155 #[error("Arithmetic operation underflowed")]
156 Underflow,
157 #[error("Cannot divide by zero")]
158 DivisionByZero,
159 #[error("Tried to convert one type to another")]
160 TypeConversion,
161 #[error("CallFrame not found")]
162 CallFrame,
163 #[error("Tried to slice non-existing data")]
164 Slicing,
165 #[error("Account not found when it should've been in the cache.")]
166 AccountNotFound,
167 #[error("Invalid precompile address. Tried to execute a precompile that does not exist.")]
168 InvalidPrecompileAddress,
169 #[error("Invalid Fork")]
170 InvalidFork,
171 #[error("Account should had been delegated")]
172 AccountNotDelegated,
173 #[error("No recipient found for privileged transaction")]
174 RecipientNotFoundForPrivilegedTransaction,
175 #[error("Memory Size Sverflow")]
176 MemorySizeOverflow,
177 #[error("Custom error: {0}")]
178 Custom(String),
179 #[error("Database access error: {0}")]
181 Database(#[from] DatabaseError),
182 #[error("{0}")]
183 FakeExponentialError(#[from] FakeExponentialError),
184}
185
186impl InternalError {
187 pub fn msg(msg: &'static str) -> Self {
188 Self::Custom(msg.to_owned())
189 }
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
193pub enum PrecompileError {
194 #[error("Error while parsing the calldata")]
195 ParsingInputError,
196 #[error("There is not enough gas to execute precompiled contract")]
197 NotEnoughGas,
198 #[error("Invalid point")]
199 InvalidPoint,
200 #[error("The point is not in the subgroup")]
201 PointNotInSubgroup,
202 #[error("The G1 point is not in the curve")]
203 BLS12381G1PointNotInCurve,
204 #[error("The G2 point is not in the curve")]
205 BLS12381G2PointNotInCurve,
206 #[error("Mod-exp base length is too large")]
207 ModExpBaseTooLarge,
208 #[error("Mod-exp exponent length is too large")]
209 ModExpExpTooLarge,
210 #[error("Mod-exp modulus length is too large")]
211 ModExpModulusTooLarge,
212 #[error("Coordinate Exceeds Field Modulus")]
213 CoordinateExceedsFieldModulus,
214}
215
216#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
217pub enum DatabaseError {
218 #[error("{0}")]
219 Custom(String),
220}
221
222#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
223pub enum OpcodeResult {
224 Continue,
225 Halt,
226}
227
228#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
229pub enum TxResult {
230 Success,
231 Revert(VMError),
232}
233
234#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
235pub struct ExecutionReport {
236 pub result: TxResult,
237 pub gas_used: u64,
241 pub gas_spent: u64,
246 pub gas_refunded: u64,
247 pub state_gas_used: u64,
250 pub output: Bytes,
251 pub logs: Vec<Log>,
252}
253
254impl ExecutionReport {
255 pub fn is_success(&self) -> bool {
256 matches!(self.result, TxResult::Success)
257 }
258}
259
260#[derive(Debug, Clone, PartialEq, Eq)]
261pub struct ContextResult {
262 pub result: TxResult,
263 pub gas_used: u64,
265 pub gas_spent: u64,
267 pub output: Bytes,
268}
269
270impl ContextResult {
271 pub fn is_success(&self) -> bool {
272 matches!(self.result, TxResult::Success)
273 }
274
275 pub fn is_collision(&self) -> bool {
277 matches!(
278 self.result,
279 TxResult::Revert(VMError::ExceptionalHalt(
280 ExceptionalHalt::AddressAlreadyOccupied
281 ))
282 )
283 }
284
285 pub fn is_revert_opcode(&self) -> bool {
289 matches!(self.result, TxResult::Revert(VMError::RevertOpcode))
290 }
291}