reth_engine_tree/tree/
error.rs

1//! Internal errors for the tree module.
2
3use alloy_consensus::BlockHeader;
4use alloy_primitives::B256;
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};
10use tokio::sync::oneshot::error::TryRecvError;
11
12/// This is an error that can come from advancing persistence. Either this can be a
13/// [`TryRecvError`], or this can be a [`ProviderError`]
14#[derive(Debug, thiserror::Error)]
15pub enum AdvancePersistenceError {
16    /// An error that can be from failing to receive a value from persistence
17    #[error(transparent)]
18    RecvError(#[from] TryRecvError),
19    /// A provider error
20    #[error(transparent)]
21    Provider(#[from] ProviderError),
22    /// Missing ancestor.
23    ///
24    /// This error occurs when we need to compute the state root for a block with missing trie
25    /// updates, but the ancestor block is not available. State root computation requires the state
26    /// from the parent block as a starting point.
27    ///
28    /// A block may be missing the trie updates when it's a fork chain block building on top of the
29    /// historical database state. Since we don't store the historical trie state, we cannot
30    /// generate the trie updates for it until the moment when database is unwound to the canonical
31    /// chain.
32    ///
33    /// Also see [`reth_chain_state::ExecutedTrieUpdates::Missing`].
34    #[error("Missing ancestor with hash {0}")]
35    MissingAncestor(B256),
36}
37
38#[derive(thiserror::Error)]
39#[error("Failed to insert block (hash={}, number={}, parent_hash={}): {}",
40    .block.hash(),
41    .block.number(),
42    .block.parent_hash(),
43    .kind)]
44struct InsertBlockErrorData<B: Block> {
45    block: SealedBlock<B>,
46    #[source]
47    kind: InsertBlockErrorKind,
48}
49
50impl<B: Block> std::fmt::Debug for InsertBlockErrorData<B> {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        f.debug_struct("InsertBlockError")
53            .field("error", &self.kind)
54            .field("hash", &self.block.hash())
55            .field("number", &self.block.number())
56            .field("parent_hash", &self.block.parent_hash())
57            .field("num_txs", &self.block.body().transactions().len())
58            .finish_non_exhaustive()
59    }
60}
61
62impl<B: Block> InsertBlockErrorData<B> {
63    const fn new(block: SealedBlock<B>, kind: InsertBlockErrorKind) -> Self {
64        Self { block, kind }
65    }
66
67    fn boxed(block: SealedBlock<B>, kind: InsertBlockErrorKind) -> Box<Self> {
68        Box::new(Self::new(block, kind))
69    }
70}
71
72/// Error thrown when inserting a block failed because the block is considered invalid.
73#[derive(thiserror::Error)]
74#[error(transparent)]
75pub struct InsertBlockError<B: Block> {
76    inner: Box<InsertBlockErrorData<B>>,
77}
78
79// === impl InsertBlockErrorTwo ===
80
81impl<B: Block> InsertBlockError<B> {
82    /// Create a new `InsertInvalidBlockErrorTwo`
83    pub fn new(block: SealedBlock<B>, kind: InsertBlockErrorKind) -> Self {
84        Self { inner: InsertBlockErrorData::boxed(block, kind) }
85    }
86
87    /// Create a new `InsertInvalidBlockError` from a consensus error
88    pub fn consensus_error(error: ConsensusError, block: SealedBlock<B>) -> Self {
89        Self::new(block, InsertBlockErrorKind::Consensus(error))
90    }
91
92    /// Consumes the error and returns the block that resulted in the error
93    #[inline]
94    pub fn into_block(self) -> SealedBlock<B> {
95        self.inner.block
96    }
97
98    /// Returns the error kind
99    #[inline]
100    pub const fn kind(&self) -> &InsertBlockErrorKind {
101        &self.inner.kind
102    }
103
104    /// Returns the block that resulted in the error
105    #[inline]
106    pub const fn block(&self) -> &SealedBlock<B> {
107        &self.inner.block
108    }
109
110    /// Consumes the type and returns the block and error kind.
111    #[inline]
112    pub fn split(self) -> (SealedBlock<B>, InsertBlockErrorKind) {
113        let inner = *self.inner;
114        (inner.block, inner.kind)
115    }
116}
117
118impl<B: Block> std::fmt::Debug for InsertBlockError<B> {
119    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120        std::fmt::Debug::fmt(&self.inner, f)
121    }
122}
123
124/// All error variants possible when inserting a block
125#[derive(Debug, thiserror::Error)]
126pub enum InsertBlockErrorKind {
127    /// Block violated consensus rules.
128    #[error(transparent)]
129    Consensus(#[from] ConsensusError),
130    /// Block execution failed.
131    #[error(transparent)]
132    Execution(#[from] BlockExecutionError),
133    /// Provider error.
134    #[error(transparent)]
135    Provider(#[from] ProviderError),
136    /// Other errors.
137    #[error(transparent)]
138    Other(#[from] Box<dyn core::error::Error + Send + Sync + 'static>),
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::Other(err) => Err(InternalBlockExecutionError::Other(err).into()),
168        }
169    }
170}
171
172/// Error variants that are not caused by invalid blocks
173#[derive(Debug, thiserror::Error)]
174pub enum InsertBlockFatalError {
175    /// A provider error
176    #[error(transparent)]
177    Provider(#[from] ProviderError),
178    /// An internal / fatal block execution error
179    #[error(transparent)]
180    BlockExecutionError(#[from] InternalBlockExecutionError),
181}
182
183/// Error variants that are caused by invalid blocks
184#[derive(Debug, thiserror::Error)]
185pub enum InsertBlockValidationError {
186    /// Block violated consensus rules.
187    #[error(transparent)]
188    Consensus(#[from] ConsensusError),
189    /// Validation error, transparently wrapping [`BlockValidationError`]
190    #[error(transparent)]
191    Validation(#[from] BlockValidationError),
192}
193
194/// Errors that may occur when inserting a payload.
195#[derive(Debug, thiserror::Error)]
196pub enum InsertPayloadError<B: Block> {
197    /// Block validation error
198    #[error(transparent)]
199    Block(#[from] InsertBlockError<B>),
200    /// Payload validation error
201    #[error(transparent)]
202    Payload(#[from] NewPayloadError),
203}