Skip to main content

reth_engine_tree/tree/
error.rs

1//! Internal errors for the tree module.
2
3use crate::tree::payload_processor::bal::BalExecutionError;
4use alloy_consensus::BlockHeader;
5use reth_consensus::ConsensusError;
6use reth_errors::{BlockExecutionError, BlockValidationError, ProviderError};
7use reth_evm::execute::InternalBlockExecutionError;
8use reth_payload_primitives::NewPayloadError;
9use reth_primitives_traits::{Block, BlockBody, SealedBlock};
10
11/// This is an error that can come from advancing persistence.
12#[derive(Debug, thiserror::Error)]
13pub enum AdvancePersistenceError {
14    /// The persistence channel was closed unexpectedly
15    #[error("persistence channel closed")]
16    ChannelClosed,
17    /// A provider error
18    #[error(transparent)]
19    Provider(#[from] ProviderError),
20}
21
22#[derive(thiserror::Error)]
23#[error("Failed to insert block (hash={}, number={}, parent_hash={}): {}",
24    .block.hash(),
25    .block.number(),
26    .block.parent_hash(),
27    .kind)]
28struct InsertBlockErrorData<B: Block> {
29    block: SealedBlock<B>,
30    #[source]
31    kind: InsertBlockErrorKind,
32}
33
34impl<B: Block> std::fmt::Debug for InsertBlockErrorData<B> {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        f.debug_struct("InsertBlockError")
37            .field("error", &self.kind)
38            .field("hash", &self.block.hash())
39            .field("number", &self.block.number())
40            .field("parent_hash", &self.block.parent_hash())
41            .field("num_txs", &self.block.body().transactions().len())
42            .finish_non_exhaustive()
43    }
44}
45
46impl<B: Block> InsertBlockErrorData<B> {
47    const fn new(block: SealedBlock<B>, kind: InsertBlockErrorKind) -> Self {
48        Self { block, kind }
49    }
50
51    fn boxed(block: SealedBlock<B>, kind: InsertBlockErrorKind) -> Box<Self> {
52        Box::new(Self::new(block, kind))
53    }
54}
55
56/// Error thrown when inserting a block failed because the block is considered invalid.
57#[derive(thiserror::Error)]
58#[error(transparent)]
59pub struct InsertBlockError<B: Block> {
60    inner: Box<InsertBlockErrorData<B>>,
61}
62
63// === impl InsertBlockErrorTwo ===
64
65impl<B: Block> InsertBlockError<B> {
66    /// Create a new `InsertInvalidBlockErrorTwo`
67    pub fn new(block: SealedBlock<B>, kind: InsertBlockErrorKind) -> Self {
68        Self { inner: InsertBlockErrorData::boxed(block, kind) }
69    }
70
71    /// Create a new `InsertInvalidBlockError` from a consensus error
72    pub fn consensus_error(error: ConsensusError, block: SealedBlock<B>) -> Self {
73        Self::new(block, InsertBlockErrorKind::Consensus(error))
74    }
75
76    /// Consumes the error and returns the block that resulted in the error
77    #[inline]
78    pub fn into_block(self) -> SealedBlock<B> {
79        self.inner.block
80    }
81
82    /// Returns the error kind
83    #[inline]
84    pub const fn kind(&self) -> &InsertBlockErrorKind {
85        &self.inner.kind
86    }
87
88    /// Returns the block that resulted in the error
89    #[inline]
90    pub const fn block(&self) -> &SealedBlock<B> {
91        &self.inner.block
92    }
93
94    /// Consumes the type and returns the block and error kind.
95    #[inline]
96    pub fn split(self) -> (SealedBlock<B>, InsertBlockErrorKind) {
97        let inner = *self.inner;
98        (inner.block, inner.kind)
99    }
100}
101
102impl<B: Block> std::fmt::Debug for InsertBlockError<B> {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        std::fmt::Debug::fmt(&self.inner, f)
105    }
106}
107
108/// All error variants possible when inserting a block
109#[derive(Debug, thiserror::Error)]
110pub enum InsertBlockErrorKind {
111    /// Block violated consensus rules.
112    #[error(transparent)]
113    Consensus(#[from] ConsensusError),
114    /// Block execution failed.
115    #[error(transparent)]
116    Execution(#[from] BlockExecutionError),
117    /// Provider error.
118    #[error(transparent)]
119    Provider(#[from] ProviderError),
120    /// BAL-driven block execution rejected the block. Covers structural BAL errors and the
121    /// final-hash mismatch.
122    #[error(transparent)]
123    InvalidBlockAccessList(BalExecutionError),
124    /// Other errors.
125    #[error(transparent)]
126    Other(#[from] Box<dyn core::error::Error + Send + Sync + 'static>),
127}
128
129impl From<BalExecutionError> for InsertBlockErrorKind {
130    fn from(e: BalExecutionError) -> Self {
131        match e {
132            // Worker EVM errors flow through the standard execution-error path so existing
133            // metrics and routing apply.
134            BalExecutionError::Evm(inner) => Self::Execution(inner),
135            BalExecutionError::Provider(inner) => Self::Provider(inner),
136            other => Self::InvalidBlockAccessList(other),
137        }
138    }
139}
140
141impl InsertBlockErrorKind {
142    /// Returns an [`InsertBlockValidationError`] if the error is caused by an invalid block.
143    ///
144    /// Returns an [`InsertBlockFatalError`] if the error is caused by an error that is not
145    /// validation related or is otherwise fatal.
146    ///
147    /// This is intended to be used to determine if we should respond `INVALID` as a response when
148    /// processing a new block.
149    pub fn ensure_validation_error(
150        self,
151    ) -> Result<InsertBlockValidationError, InsertBlockFatalError> {
152        match self {
153            Self::Consensus(err) => Ok(InsertBlockValidationError::Consensus(err)),
154            // other execution errors that are considered internal errors
155            Self::Execution(err) => {
156                match err {
157                    BlockExecutionError::Validation(err) => {
158                        Ok(InsertBlockValidationError::Validation(err))
159                    }
160                    // these are internal errors, not caused by an invalid block
161                    BlockExecutionError::Internal(error) => {
162                        Err(InsertBlockFatalError::BlockExecutionError(error))
163                    }
164                }
165            }
166            Self::Provider(err) => Err(InsertBlockFatalError::Provider(err)),
167            Self::InvalidBlockAccessList(err) => {
168                Ok(InsertBlockValidationError::InvalidBlockAccessList(err))
169            }
170            Self::Other(err) => Err(InternalBlockExecutionError::Other(err).into()),
171        }
172    }
173}
174
175/// Error variants that are not caused by invalid blocks
176#[derive(Debug, thiserror::Error)]
177pub enum InsertBlockFatalError {
178    /// A provider error
179    #[error(transparent)]
180    Provider(#[from] ProviderError),
181    /// An internal / fatal block execution error
182    #[error(transparent)]
183    BlockExecutionError(#[from] InternalBlockExecutionError),
184}
185
186/// Error variants that are caused by invalid blocks
187#[derive(Debug, thiserror::Error)]
188pub enum InsertBlockValidationError {
189    /// Block violated consensus rules.
190    #[error(transparent)]
191    Consensus(#[from] ConsensusError),
192    /// Validation error, transparently wrapping [`BlockValidationError`]
193    #[error(transparent)]
194    Validation(#[from] BlockValidationError),
195    /// BAL-driven block execution rejected the block. Covers structural BAL errors and the
196    /// final-hash mismatch.
197    #[error(transparent)]
198    InvalidBlockAccessList(BalExecutionError),
199}
200
201/// Errors that may occur when inserting a payload.
202#[derive(Debug, thiserror::Error)]
203pub enum InsertPayloadError<B: Block> {
204    /// Block validation error
205    #[error(transparent)]
206    Block(#[from] InsertBlockError<B>),
207    /// Payload validation error
208    #[error(transparent)]
209    Payload(#[from] NewPayloadError),
210}