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("storage change set for address {address} and key {storage_key} at block #{block_number} does not exist")]
43 StorageChangesetNotFound {
44 block_number: BlockNumber,
46 address: Address,
48 storage_key: Box<B256>,
52 },
53 #[error("account change set for address {address} at block #{block_number} does not exist")]
55 AccountChangesetNotFound {
56 block_number: BlockNumber,
58 address: Address,
60 },
61 #[error("total difficulty not found for block #{_0}")]
63 TotalDifficultyNotFound(BlockNumber),
64 #[error("no header found for {_0:?}")]
66 HeaderNotFound(BlockHashOrNumber),
67 #[error("no transaction found for {_0:?}")]
69 TransactionNotFound(HashOrNumber),
70 #[error("no receipt found for {_0:?}")]
72 ReceiptNotFound(HashOrNumber),
73 #[error("best block does not exist")]
75 BestBlockNotFound,
76 #[error("finalized block does not exist")]
78 FinalizedBlockNotFound,
79 #[error("safe block does not exist")]
81 SafeBlockNotFound,
82 #[error("cache service task stopped")]
84 CacheServiceUnavailable,
85 #[error("unknown block {_0}")]
87 UnknownBlockHash(B256),
88 #[error("no state found for block {_0}")]
90 StateForHashNotFound(B256),
91 #[error("no state found for block number {_0}")]
93 StateForNumberNotFound(u64),
94 #[error("unable to find the block number for a given transaction index")]
96 BlockNumberForTransactionIndexNotFound,
97 #[error("merkle trie {_0}")]
99 StateRootMismatch(Box<RootMismatch>),
100 #[error("unwind merkle trie {_0}")]
102 UnwindStateRootMismatch(Box<RootMismatch>),
103 #[error("state at block #{_0} is pruned")]
105 StateAtBlockPruned(BlockNumber),
106 #[error("this provider does not support this request")]
108 UnsupportedProvider,
109 #[cfg(feature = "std")]
111 #[error("not able to find {_0} static file at {_1:?}")]
112 MissingStaticFilePath(StaticFileSegment, std::path::PathBuf),
113 #[error("not able to find {_0} static file for block number {_1}")]
115 MissingStaticFileBlock(StaticFileSegment, BlockNumber),
116 #[error("unable to find {_0} static file for transaction id {_1}")]
118 MissingStaticFileTx(StaticFileSegment, TxNumber),
119 #[error("unable to write block #{_1} to finalized static file {_0}")]
121 FinalizedStaticFile(StaticFileSegment, BlockNumber),
122 #[error("trying to append data to {_0} as block #{_1} but expected block #{_2}")]
124 UnexpectedStaticFileBlockNumber(StaticFileSegment, BlockNumber, BlockNumber),
125 #[error("trying to append row to {_0} at index #{_1} but expected index #{_2}")]
127 UnexpectedStaticFileTxNumber(StaticFileSegment, TxNumber, TxNumber),
128 #[error("cannot get a writer on a read-only environment.")]
130 ReadOnlyStaticFileAccess,
131 #[error("failed to initialize consistent view: {_0}")]
133 ConsistentView(Box<ConsistentViewError>),
134 #[error(transparent)]
136 StorageLockError(#[from] StorageLockError),
137 #[error(transparent)]
139 UnifiedStorageWriterError(#[from] UnifiedStorageWriterError),
140 #[error("received invalid output from storage")]
142 InvalidStorageOutput,
143 #[error(transparent)]
145 Other(#[from] AnyError),
146}
147
148impl ProviderError {
149 pub fn other<E>(error: E) -> Self
152 where
153 E: core::error::Error + Send + Sync + 'static,
154 {
155 Self::Other(AnyError::new(error))
156 }
157
158 pub fn as_other(&self) -> Option<&(dyn core::error::Error + Send + Sync + 'static)> {
160 match self {
161 Self::Other(err) => Some(err.as_error()),
162 _ => None,
163 }
164 }
165
166 pub fn downcast_other_ref<T: core::error::Error + 'static>(&self) -> Option<&T> {
170 let other = self.as_other()?;
171 other.downcast_ref()
172 }
173
174 pub fn is_other<T: core::error::Error + 'static>(&self) -> bool {
177 self.as_other().map(|err| err.is::<T>()).unwrap_or(false)
178 }
179}
180
181impl DBErrorMarker for ProviderError {}
182
183impl From<alloy_rlp::Error> for ProviderError {
184 fn from(error: alloy_rlp::Error) -> Self {
185 Self::Rlp(error)
186 }
187}
188
189impl From<RecoveryError> for ProviderError {
190 fn from(_: RecoveryError) -> Self {
191 Self::SenderRecoveryError
192 }
193}
194
195#[derive(Clone, Debug, PartialEq, Eq, Display)]
197#[display("root mismatch at #{block_number} ({block_hash}): {root}")]
198pub struct RootMismatch {
199 pub root: GotExpected<B256>,
201 pub block_number: BlockNumber,
203 pub block_hash: BlockHash,
205}
206
207#[derive(Debug, thiserror::Error)]
209#[error("{message}")]
210pub struct StaticFileWriterError {
211 pub message: String,
213}
214
215impl StaticFileWriterError {
216 #[allow(dead_code)]
218 pub fn new(message: impl Into<String>) -> Self {
219 Self { message: message.into() }
220 }
221}
222
223#[derive(Clone, Debug, PartialEq, Eq, Display)]
225pub enum ConsistentViewError {
226 #[display("node is syncing. best block: {best_block:?}")]
228 Syncing {
229 best_block: GotExpected<BlockNumber>,
231 },
232 #[display("inconsistent database state: {tip:?}")]
234 Inconsistent {
235 tip: GotExpected<Option<B256>>,
237 },
238 #[display("database view no longer contains block: {block:?}")]
240 Reorged {
241 block: B256,
243 },
244}
245
246impl From<ConsistentViewError> for ProviderError {
247 fn from(error: ConsistentViewError) -> Self {
248 Self::ConsistentView(Box::new(error))
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 #[derive(thiserror::Error, Debug)]
257 #[error("E")]
258 struct E;
259
260 #[test]
261 fn other_err() {
262 let err = ProviderError::other(E);
263 assert!(err.is_other::<E>());
264 assert!(err.downcast_other_ref::<E>().is_some());
265 }
266}