reth_storage_errors/
provider.rs

1use crate::{any::AnyError, db::DatabaseError, writer::UnifiedStorageWriterError};
2use alloc::{boxed::Box, string::String};
3use alloy_eips::{BlockHashOrNumber, HashOrNumber};
4use alloy_primitives::{Address, BlockHash, BlockNumber, TxNumber, B256};
5use derive_more::Display;
6use reth_enclave::EnclaveError;
7use reth_primitives_traits::{transaction::signed::RecoveryError, GotExpected};
8use reth_prune_types::PruneSegmentError;
9use reth_static_file_types::StaticFileSegment;
10use revm_database_interface::DBErrorMarker;
11
12/// Provider result type.
13pub type ProviderResult<Ok> = Result<Ok, ProviderError>;
14
15/// Bundled errors variants thrown by various providers.
16#[derive(Clone, Debug, thiserror::Error)]
17pub enum ProviderError {
18    /// Database error.
19    #[error(transparent)]
20    Database(#[from] DatabaseError),
21    /// Pruning error.
22    #[error(transparent)]
23    Pruning(#[from] PruneSegmentError),
24    /// RLP error.
25    #[error("{_0}")]
26    Rlp(alloy_rlp::Error),
27    /// Trie witness error.
28    #[error("trie witness error: {_0}")]
29    TrieWitnessError(String),
30    /// Error when recovering the sender for a transaction
31    #[error("failed to recover sender for transaction")]
32    SenderRecoveryError,
33    /// The header number was not found for the given block hash.
34    #[error("block hash {_0} does not exist in Headers table")]
35    BlockHashNotFound(BlockHash),
36    /// A block body is missing.
37    #[error("block meta not found for block #{_0}")]
38    BlockBodyIndicesNotFound(BlockNumber),
39    /// The transition ID was found for the given address and storage key, but the changeset was
40    /// not found.
41    #[error(
42        "storage change set for address {address} and key {storage_key} at block #{block_number} does not exist"
43    )]
44    StorageChangesetNotFound {
45        /// The block number found for the address and storage key.
46        block_number: BlockNumber,
47        /// The account address.
48        address: Address,
49        /// The storage key.
50        // NOTE: This is a Box only because otherwise this variant is 16 bytes larger than the
51        // second largest (which uses `BlockHashOrNumber`).
52        storage_key: Box<B256>,
53    },
54    /// The block number was found for the given address, but the changeset was not found.
55    #[error("account change set for address {address} at block #{block_number} does not exist")]
56    AccountChangesetNotFound {
57        /// Block number found for the address.
58        block_number: BlockNumber,
59        /// The account address.
60        address: Address,
61    },
62    /// The total difficulty for a block is missing.
63    #[error("total difficulty not found for block #{_0}")]
64    TotalDifficultyNotFound(BlockNumber),
65    /// When required header related data was not found but was required.
66    #[error("no header found for {_0:?}")]
67    HeaderNotFound(BlockHashOrNumber),
68    /// The specific transaction identified by hash or id is missing.
69    #[error("no transaction found for {_0:?}")]
70    TransactionNotFound(HashOrNumber),
71    /// The specific receipt for a transaction identified by hash or id is missing
72    #[error("no receipt found for {_0:?}")]
73    ReceiptNotFound(HashOrNumber),
74    /// Unable to find the best block.
75    #[error("best block does not exist")]
76    BestBlockNotFound,
77    /// Unable to find the finalized block.
78    #[error("finalized block does not exist")]
79    FinalizedBlockNotFound,
80    /// Unable to find the safe block.
81    #[error("safe block does not exist")]
82    SafeBlockNotFound,
83    /// Thrown when we failed to lookup a block for the pending state.
84    #[error("unknown block {_0}")]
85    UnknownBlockHash(B256),
86    /// Thrown when we were unable to find a state for a block hash.
87    #[error("no state found for block {_0}")]
88    StateForHashNotFound(B256),
89    /// Thrown when we were unable to find a state for a block number.
90    #[error("no state found for block number {_0}")]
91    StateForNumberNotFound(u64),
92    /// Unable to find the block number for a given transaction index.
93    #[error("unable to find the block number for a given transaction index")]
94    BlockNumberForTransactionIndexNotFound,
95    /// Root mismatch.
96    #[error("merkle trie {_0}")]
97    StateRootMismatch(Box<RootMismatch>),
98    /// Root mismatch during unwind
99    #[error("unwind merkle trie {_0}")]
100    UnwindStateRootMismatch(Box<RootMismatch>),
101    /// State is not available for the given block number because it is pruned.
102    #[error("state at block #{_0} is pruned")]
103    StateAtBlockPruned(BlockNumber),
104    /// Provider does not support this particular request.
105    #[error("this provider does not support this request")]
106    UnsupportedProvider,
107    /// Static File is not found at specified path.
108    #[cfg(feature = "std")]
109    #[error("not able to find {_0} static file at {_1:?}")]
110    MissingStaticFilePath(StaticFileSegment, std::path::PathBuf),
111    /// Static File is not found for requested block.
112    #[error("not able to find {_0} static file for block number {_1}")]
113    MissingStaticFileBlock(StaticFileSegment, BlockNumber),
114    /// Static File is not found for requested transaction.
115    #[error("unable to find {_0} static file for transaction id {_1}")]
116    MissingStaticFileTx(StaticFileSegment, TxNumber),
117    /// Static File is finalized and cannot be written to.
118    #[error("unable to write block #{_1} to finalized static file {_0}")]
119    FinalizedStaticFile(StaticFileSegment, BlockNumber),
120    /// Trying to insert data from an unexpected block number.
121    #[error("trying to append data to {_0} as block #{_1} but expected block #{_2}")]
122    UnexpectedStaticFileBlockNumber(StaticFileSegment, BlockNumber, BlockNumber),
123    /// Trying to insert data from an unexpected block number.
124    #[error("trying to append row to {_0} at index #{_1} but expected index #{_2}")]
125    UnexpectedStaticFileTxNumber(StaticFileSegment, TxNumber, TxNumber),
126    /// Static File Provider was initialized as read-only.
127    #[error("cannot get a writer on a read-only environment.")]
128    ReadOnlyStaticFileAccess,
129    /// Consistent view error.
130    #[error("failed to initialize consistent view: {_0}")]
131    ConsistentView(Box<ConsistentViewError>),
132    /// Storage writer error.
133    #[error(transparent)]
134    UnifiedStorageWriterError(#[from] UnifiedStorageWriterError),
135    /// Received invalid output from configured storage implementation.
136    #[error("received invalid output from storage")]
137    InvalidStorageOutput,
138    /// Enclave encryptography error.
139    #[error("enclave error: {_0}")]
140    EnclaveError(EnclaveError),
141    /// Any other error type wrapped into a cloneable [`AnyError`].
142    #[error(transparent)]
143    Other(#[from] AnyError),
144}
145
146impl From<EnclaveError> for ProviderError {
147    fn from(err: EnclaveError) -> Self {
148        Self::EnclaveError(err)
149    }
150}
151
152impl ProviderError {
153    /// Creates a new [`ProviderError::Other`] variant by wrapping the given error into an
154    /// [`AnyError`]
155    pub fn other<E>(error: E) -> Self
156    where
157        E: core::error::Error + Send + Sync + 'static,
158    {
159        Self::Other(AnyError::new(error))
160    }
161
162    /// Returns the arbitrary error if it is [`ProviderError::Other`]
163    pub fn as_other(&self) -> Option<&(dyn core::error::Error + Send + Sync + 'static)> {
164        match self {
165            Self::Other(err) => Some(err.as_error()),
166            _ => None,
167        }
168    }
169
170    /// Returns a reference to the [`ProviderError::Other`] value if this type is a
171    /// [`ProviderError::Other`] and the [`AnyError`] wraps an error of that type. Returns None
172    /// otherwise.
173    pub fn downcast_other_ref<T: core::error::Error + 'static>(&self) -> Option<&T> {
174        let other = self.as_other()?;
175        other.downcast_ref()
176    }
177
178    /// Returns true if the this type is a [`ProviderError::Other`] of that error
179    /// type. Returns false otherwise.
180    pub fn is_other<T: core::error::Error + 'static>(&self) -> bool {
181        self.as_other().map(|err| err.is::<T>()).unwrap_or(false)
182    }
183}
184
185impl DBErrorMarker for ProviderError {}
186
187impl From<alloy_rlp::Error> for ProviderError {
188    fn from(error: alloy_rlp::Error) -> Self {
189        Self::Rlp(error)
190    }
191}
192
193impl From<RecoveryError> for ProviderError {
194    fn from(_: RecoveryError) -> Self {
195        Self::SenderRecoveryError
196    }
197}
198
199/// A root mismatch error at a given block height.
200#[derive(Clone, Debug, PartialEq, Eq, Display)]
201#[display("root mismatch at #{block_number} ({block_hash}): {root}")]
202pub struct RootMismatch {
203    /// The target block root diff.
204    pub root: GotExpected<B256>,
205    /// The target block number.
206    pub block_number: BlockNumber,
207    /// The target block hash.
208    pub block_hash: BlockHash,
209}
210
211/// A Static File Write Error.
212#[derive(Debug, thiserror::Error)]
213#[error("{message}")]
214pub struct StaticFileWriterError {
215    /// The error message.
216    pub message: String,
217}
218
219impl StaticFileWriterError {
220    /// Creates a new [`StaticFileWriterError`] with the given message.
221    pub fn new(message: impl Into<String>) -> Self {
222        Self { message: message.into() }
223    }
224}
225/// Consistent database view error.
226#[derive(Clone, Debug, PartialEq, Eq, Display)]
227pub enum ConsistentViewError {
228    /// Error thrown on attempt to initialize provider while node is still syncing.
229    #[display("node is syncing. best block: {best_block:?}")]
230    Syncing {
231        /// Best block diff.
232        best_block: GotExpected<BlockNumber>,
233    },
234    /// Error thrown on inconsistent database view.
235    #[display("inconsistent database state: {tip:?}")]
236    Inconsistent {
237        /// The tip diff.
238        tip: GotExpected<Option<B256>>,
239    },
240    /// Error thrown when the database does not contain a block from the previous database view.
241    #[display("database view no longer contains block: {block:?}")]
242    Reorged {
243        /// The previous block
244        block: B256,
245    },
246}
247
248impl From<ConsistentViewError> for ProviderError {
249    fn from(error: ConsistentViewError) -> Self {
250        Self::ConsistentView(Box::new(error))
251    }
252}
253
254#[cfg(test)]
255mod tests {
256    use super::*;
257
258    #[derive(thiserror::Error, Debug)]
259    #[error("E")]
260    struct E;
261
262    #[test]
263    fn other_err() {
264        let err = ProviderError::other(E);
265        assert!(err.is_other::<E>());
266        assert!(err.downcast_other_ref::<E>().is_some());
267    }
268}