1use crate::{EvmError, InvalidTxError};
2use alloc::{
3 boxed::Box,
4 string::{String, ToString},
5};
6use alloy_primitives::B256;
7
8#[derive(Debug, thiserror::Error)]
10pub enum BlockValidationError {
11 #[error("EVM reported invalid transaction ({hash}): {error}")]
13 InvalidTx {
14 hash: B256,
16 error: Box<dyn InvalidTxError>,
18 },
19 #[error("incrementing balance in post execution failed")]
21 IncrementBalanceFailed,
22 #[error(
24 "transaction gas limit {transaction_gas_limit} is more than blocks available gas {block_available_gas}"
25 )]
26 TransactionGasLimitMoreThanAvailableBlockGas {
27 transaction_gas_limit: u64,
29 block_available_gas: u64,
31 },
32 #[error("EIP-4788 parent beacon block root missing for active Cancun block")]
34 MissingParentBeaconBlockRoot,
35 #[error(
37 "the parent beacon block root is not zero for Cancun genesis block: {parent_beacon_block_root}"
38 )]
39 CancunGenesisParentBeaconBlockRootNotZero {
40 parent_beacon_block_root: B256,
42 },
43 #[error("failed to apply beacon root contract call at {parent_beacon_block_root}: {message}")]
47 BeaconRootContractCall {
48 parent_beacon_block_root: Box<B256>,
50 message: String,
52 },
53 #[error("failed to apply blockhash contract call: {message}")]
57 BlockHashContractCall {
58 message: String,
60 },
61 #[error("failed to apply withdrawal requests contract call: {message}")]
65 WithdrawalRequestsContractCall {
66 message: String,
68 },
69 #[error("failed to apply consolidation requests contract call: {message}")]
73 ConsolidationRequestsContractCall {
74 message: String,
76 },
77 #[error("failed to decode deposit requests from receipts: {_0}")]
81 DepositRequestDecode(String),
82 #[error(transparent)]
84 Other(Box<dyn core::error::Error + Send + Sync + 'static>),
85}
86
87impl BlockValidationError {
88 pub fn other<E>(error: E) -> Self
90 where
91 E: core::error::Error + Send + Sync + 'static,
92 {
93 Self::Other(Box::new(error))
94 }
95
96 pub fn msg(msg: impl core::fmt::Display) -> Self {
98 Self::Other(msg.to_string().into())
99 }
100}
101
102#[derive(Debug, thiserror::Error)]
104pub enum BlockExecutionError {
105 #[error(transparent)]
107 Validation(#[from] BlockValidationError),
108 #[error(transparent)]
110 Internal(#[from] InternalBlockExecutionError),
111}
112
113impl BlockExecutionError {
114 pub fn other<E>(error: E) -> Self
117 where
118 E: core::error::Error + Send + Sync + 'static,
119 {
120 Self::Internal(InternalBlockExecutionError::other(error))
121 }
122
123 pub fn msg(msg: impl core::fmt::Display) -> Self {
126 Self::Internal(InternalBlockExecutionError::msg(msg))
127 }
128
129 pub const fn as_validation(&self) -> Option<&BlockValidationError> {
131 match self {
132 Self::Validation(err) => Some(err),
133 _ => None,
134 }
135 }
136
137 pub fn evm<E: EvmError>(error: E, hash: B256) -> Self {
142 match error.try_into_invalid_tx_err() {
143 Ok(err) => {
144 Self::Validation(BlockValidationError::InvalidTx { hash, error: Box::new(err) })
145 }
146 Err(err) => {
147 Self::Internal(InternalBlockExecutionError::EVM { hash, error: Box::new(err) })
148 }
149 }
150 }
151}
152
153#[derive(Debug, thiserror::Error)]
155pub enum InternalBlockExecutionError {
156 #[error("internal EVM error occurred when executing transaction {hash}: {error}")]
160 EVM {
161 hash: B256,
163 error: Box<dyn core::error::Error + Send + Sync>,
165 },
166 #[error(transparent)]
168 Other(Box<dyn core::error::Error + Send + Sync + 'static>),
169}
170
171impl InternalBlockExecutionError {
172 pub fn other<E>(error: E) -> Self
174 where
175 E: core::error::Error + Send + Sync + 'static,
176 {
177 Self::Other(Box::new(error))
178 }
179
180 pub fn msg(msg: impl core::fmt::Display) -> Self {
182 Self::Other(msg.to_string().into())
183 }
184
185 pub fn as_other(&self) -> Option<&(dyn core::error::Error + Send + Sync + 'static)> {
187 match self {
188 Self::Other(err) => Some(&**err),
189 _ => None,
190 }
191 }
192
193 pub fn downcast<T: core::error::Error + 'static>(self) -> Result<Box<T>, Self> {
195 match self {
196 Self::Other(err) => err.downcast().map_err(Self::Other),
197 err => Err(err),
198 }
199 }
200
201 pub fn downcast_other<T: core::error::Error + 'static>(&self) -> Option<&T> {
204 let other = self.as_other()?;
205 other.downcast_ref()
206 }
207
208 pub fn is_other<T: core::error::Error + 'static>(&self) -> bool {
211 self.as_other().map(|err| err.is::<T>()).unwrap_or(false)
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[derive(thiserror::Error, Debug)]
220 #[error("err")]
221 struct E;
222
223 #[test]
224 fn other_downcast() {
225 let err = InternalBlockExecutionError::other(E);
226 assert!(err.is_other::<E>());
227
228 assert!(err.downcast_other::<E>().is_some());
229 assert!(err.downcast::<E>().is_ok());
230 }
231}