1use crate::{
2 any::AnyError, db::DatabaseError, lockfile::StorageLockError, writer::UnifiedStorageWriterError,
3};
4use alloc::{boxed::Box, string::String};
5use alloy_eips::{BlockHashOrNumber, HashOrNumber};
6use alloy_primitives::{Address, BlockHash, BlockNumber, TxNumber, B256};
7use derive_more::Display;
8use reth_primitives_traits::{transaction::signed::RecoveryError, GotExpected};
9use reth_prune_types::PruneSegmentError;
10use reth_static_file_types::StaticFileSegment;
11use revm_database_interface::DBErrorMarker;
12
13pub type ProviderResult<Ok> = Result<Ok, ProviderError>;
15
16#[derive(Clone, Debug, thiserror::Error)]
18pub enum ProviderError {
19 #[error(transparent)]
21 Database(#[from] DatabaseError),
22 #[error(transparent)]
24 Pruning(#[from] PruneSegmentError),
25 #[error("{_0}")]
27 Rlp(alloy_rlp::Error),
28 #[error("trie witness error: {_0}")]
30 TrieWitnessError(String),
31 #[error("failed to recover sender for transaction")]
33 SenderRecoveryError,
34 #[error("block hash {_0} does not exist in Headers table")]
36 BlockHashNotFound(BlockHash),
37 #[error("block meta not found for block #{_0}")]
39 BlockBodyIndicesNotFound(BlockNumber),
40 #[error(
43 "storage change set for address {address} and key {storage_key} at block #{block_number} does not exist"
44 )]
45 StorageChangesetNotFound {
46 block_number: BlockNumber,
48 address: Address,
50 storage_key: Box<B256>,
54 },
55 #[error("account change set for address {address} at block #{block_number} does not exist")]
57 AccountChangesetNotFound {
58 block_number: BlockNumber,
60 address: Address,
62 },
63 #[error("total difficulty not found for block #{_0}")]
65 TotalDifficultyNotFound(BlockNumber),
66 #[error("no header found for {_0:?}")]
68 HeaderNotFound(BlockHashOrNumber),
69 #[error("no transaction found for {_0:?}")]
71 TransactionNotFound(HashOrNumber),
72 #[error("no receipt found for {_0:?}")]
74 ReceiptNotFound(HashOrNumber),
75 #[error("best block does not exist")]
77 BestBlockNotFound,
78 #[error("finalized block does not exist")]
80 FinalizedBlockNotFound,
81 #[error("safe block does not exist")]
83 SafeBlockNotFound,
84 #[error("cache service task stopped")]
86 CacheServiceUnavailable,
87 #[error("unknown block {_0}")]
89 UnknownBlockHash(B256),
90 #[error("no state found for block {_0}")]
92 StateForHashNotFound(B256),
93 #[error("no state found for block number {_0}")]
95 StateForNumberNotFound(u64),
96 #[error("unable to find the block number for a given transaction index")]
98 BlockNumberForTransactionIndexNotFound,
99 #[error("merkle trie {_0}")]
101 StateRootMismatch(Box<RootMismatch>),
102 #[error("unwind merkle trie {_0}")]
104 UnwindStateRootMismatch(Box<RootMismatch>),
105 #[error("state at block #{_0} is pruned")]
107 StateAtBlockPruned(BlockNumber),
108 #[error("this provider does not support this request")]
110 UnsupportedProvider,
111 #[cfg(feature = "std")]
113 #[error("not able to find {_0} static file at {_1:?}")]
114 MissingStaticFilePath(StaticFileSegment, std::path::PathBuf),
115 #[error("not able to find {_0} static file for block number {_1}")]
117 MissingStaticFileBlock(StaticFileSegment, BlockNumber),
118 #[error("unable to find {_0} static file for transaction id {_1}")]
120 MissingStaticFileTx(StaticFileSegment, TxNumber),
121 #[error("unable to write block #{_1} to finalized static file {_0}")]
123 FinalizedStaticFile(StaticFileSegment, BlockNumber),
124 #[error("trying to append data to {_0} as block #{_1} but expected block #{_2}")]
126 UnexpectedStaticFileBlockNumber(StaticFileSegment, BlockNumber, BlockNumber),
127 #[error("trying to append row to {_0} at index #{_1} but expected index #{_2}")]
129 UnexpectedStaticFileTxNumber(StaticFileSegment, TxNumber, TxNumber),
130 #[error("cannot get a writer on a read-only environment.")]
132 ReadOnlyStaticFileAccess,
133 #[error("failed to initialize consistent view: {_0}")]
135 ConsistentView(Box<ConsistentViewError>),
136 #[error(transparent)]
138 StorageLockError(#[from] StorageLockError),
139 #[error(transparent)]
141 UnifiedStorageWriterError(#[from] UnifiedStorageWriterError),
142 #[error("received invalid output from storage")]
144 InvalidStorageOutput,
145 #[error(transparent)]
147 Other(#[from] AnyError),
148}
149
150impl ProviderError {
151 pub fn other<E>(error: E) -> Self
154 where
155 E: core::error::Error + Send + Sync + 'static,
156 {
157 Self::Other(AnyError::new(error))
158 }
159
160 pub fn as_other(&self) -> Option<&(dyn core::error::Error + Send + Sync + 'static)> {
162 match self {
163 Self::Other(err) => Some(err.as_error()),
164 _ => None,
165 }
166 }
167
168 pub fn downcast_other_ref<T: core::error::Error + 'static>(&self) -> Option<&T> {
172 let other = self.as_other()?;
173 other.downcast_ref()
174 }
175
176 pub fn is_other<T: core::error::Error + 'static>(&self) -> bool {
179 self.as_other().map(|err| err.is::<T>()).unwrap_or(false)
180 }
181}
182
183impl DBErrorMarker for ProviderError {}
184
185impl From<alloy_rlp::Error> for ProviderError {
186 fn from(error: alloy_rlp::Error) -> Self {
187 Self::Rlp(error)
188 }
189}
190
191impl From<RecoveryError> for ProviderError {
192 fn from(_: RecoveryError) -> Self {
193 Self::SenderRecoveryError
194 }
195}
196
197#[derive(Clone, Debug, PartialEq, Eq, Display)]
199#[display("root mismatch at #{block_number} ({block_hash}): {root}")]
200pub struct RootMismatch {
201 pub root: GotExpected<B256>,
203 pub block_number: BlockNumber,
205 pub block_hash: BlockHash,
207}
208
209#[derive(Debug, thiserror::Error)]
211#[error("{message}")]
212pub struct StaticFileWriterError {
213 pub message: String,
215}
216
217impl StaticFileWriterError {
218 pub fn new(message: impl Into<String>) -> Self {
220 Self { message: message.into() }
221 }
222}
223
224#[derive(Clone, Debug, PartialEq, Eq, Display)]
226pub enum ConsistentViewError {
227 #[display("node is syncing. best block: {best_block:?}")]
229 Syncing {
230 best_block: GotExpected<BlockNumber>,
232 },
233 #[display("inconsistent database state: {tip:?}")]
235 Inconsistent {
236 tip: GotExpected<Option<B256>>,
238 },
239 #[display("database view no longer contains block: {block:?}")]
241 Reorged {
242 block: B256,
244 },
245}
246
247impl From<ConsistentViewError> for ProviderError {
248 fn from(error: ConsistentViewError) -> Self {
249 Self::ConsistentView(Box::new(error))
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[derive(thiserror::Error, Debug)]
258 #[error("E")]
259 struct E;
260
261 #[test]
262 fn other_err() {
263 let err = ProviderError::other(E);
264 assert!(err.is_other::<E>());
265 assert!(err.downcast_other_ref::<E>().is_some());
266 }
267}