1use crate::{any::AnyError, db::DatabaseError};
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_codecs::DecompressError;
7use reth_primitives_traits::{transaction::signed::RecoveryError, GotExpected};
8use reth_prune_types::PruneSegmentError;
9use reth_static_file_types::StaticFileSegment;
10use revm_database_interface::{bal::EvmDatabaseError, DBErrorMarker};
11use revm_state::bal::BalError;
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("BAL error:{_0}")]
24 Bal(BalError),
25 #[error(transparent)]
27 Pruning(#[from] PruneSegmentError),
28 #[error(transparent)]
30 StaticFileWriter(#[from] StaticFileWriterError),
31 #[error("{_0}")]
33 Rlp(alloy_rlp::Error),
34 #[error("trie witness error: {_0}")]
36 TrieWitnessError(String),
37 #[error("failed to recover sender for transaction")]
39 SenderRecoveryError,
40 #[error("block hash {_0} does not exist in Headers table")]
42 BlockHashNotFound(BlockHash),
43 #[error("block meta not found for block #{_0}")]
45 BlockBodyIndicesNotFound(BlockNumber),
46 #[error(
49 "storage change set for address {address} and key {storage_key} at block #{block_number} does not exist"
50 )]
51 StorageChangesetNotFound {
52 block_number: BlockNumber,
54 address: Address,
56 storage_key: Box<B256>,
60 },
61 #[error("account change set for address {address} at block #{block_number} does not exist")]
63 AccountChangesetNotFound {
64 block_number: BlockNumber,
66 address: Address,
68 },
69 #[error("no header found for {_0:?}")]
71 HeaderNotFound(BlockHashOrNumber),
72 #[error("no transaction found for {_0:?}")]
74 TransactionNotFound(HashOrNumber),
75 #[error("no receipt found for {_0:?}")]
77 ReceiptNotFound(HashOrNumber),
78 #[error("best block does not exist")]
80 BestBlockNotFound,
81 #[error("finalized block does not exist")]
83 FinalizedBlockNotFound,
84 #[error("safe block does not exist")]
86 SafeBlockNotFound,
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("state at block #{requested} is not available, block has not been executed yet (latest executed: #{executed})")]
110 BlockNotExecuted {
111 requested: BlockNumber,
113 executed: BlockNumber,
115 },
116 #[error("block #{requested} is not available, history has expired (earliest available: #{earliest_available})")]
120 BlockExpired {
121 requested: BlockNumber,
123 earliest_available: BlockNumber,
125 },
126 #[error("this provider does not support this request")]
128 UnsupportedProvider,
129 #[cfg(feature = "std")]
131 #[error("not able to find {_0} static file at {_1:?}")]
132 MissingStaticFileSegmentPath(StaticFileSegment, std::path::PathBuf),
133 #[cfg(feature = "std")]
135 #[error("not able to find static file at {_0:?}")]
136 MissingStaticFilePath(std::path::PathBuf),
137 #[error("highest block is not found for {_0} static file")]
139 MissingHighestStaticFileBlock(StaticFileSegment),
140 #[error("not able to find {_0} static file for block number {_1}")]
142 MissingStaticFileBlock(StaticFileSegment, BlockNumber),
143 #[error("unable to find {_0} static file for transaction id {_1}")]
145 MissingStaticFileTx(StaticFileSegment, TxNumber),
146 #[error("unable to write block #{_1} to finalized static file {_0}")]
148 FinalizedStaticFile(StaticFileSegment, BlockNumber),
149 #[error("trying to append data to {_0} as block #{_1} but expected block #{_2}")]
151 UnexpectedStaticFileBlockNumber(StaticFileSegment, BlockNumber, BlockNumber),
152 #[error("trying to append row to {_0} at index #{_1} but expected index #{_2}")]
154 UnexpectedStaticFileTxNumber(StaticFileSegment, TxNumber, TxNumber),
155 #[error("changeset static file is corrupted, missing offsets for changesets in each block")]
157 CorruptedChangeSetStaticFile,
158 #[error("Unbounded start is unsupported in from_reverts")]
160 UnboundedStartUnsupported,
161 #[error("cannot get a writer on a read-only environment.")]
163 ReadOnlyStaticFileAccess,
164 #[error("failed to initialize consistent view: {_0}")]
166 ConsistentView(Box<ConsistentViewError>),
167 #[error("received invalid output from storage")]
169 InvalidStorageOutput,
170 #[error("missing trie updates for block {0}")]
172 MissingTrieUpdates(B256),
173 #[error("insufficient changesets to revert to block #{requested}. Available changeset range: {available:?}")]
175 InsufficientChangesets {
176 requested: BlockNumber,
178 available: core::ops::RangeInclusive<BlockNumber>,
180 },
181 #[error("consistency check failed for {data_source}. Db must be unwound to {unwind_to}")]
185 MustUnwind {
186 data_source: &'static str,
188 unwind_to: BlockNumber,
190 },
191 #[error(transparent)]
193 Other(#[from] AnyError),
194}
195
196impl ProviderError {
197 pub fn other<E>(error: E) -> Self
200 where
201 E: core::error::Error + Send + Sync + 'static,
202 {
203 Self::Other(AnyError::new(error))
204 }
205
206 pub fn as_other(&self) -> Option<&(dyn core::error::Error + Send + Sync + 'static)> {
208 match self {
209 Self::Other(err) => Some(err.as_error()),
210 _ => None,
211 }
212 }
213
214 pub fn downcast_other_ref<T: core::error::Error + 'static>(&self) -> Option<&T> {
218 let other = self.as_other()?;
219 other.downcast_ref()
220 }
221
222 pub fn is_other<T: core::error::Error + 'static>(&self) -> bool {
225 self.as_other().map(|err| err.is::<T>()).unwrap_or(false)
226 }
227}
228
229impl DBErrorMarker for ProviderError {}
230
231impl From<alloy_rlp::Error> for ProviderError {
232 fn from(error: alloy_rlp::Error) -> Self {
233 Self::Rlp(error)
234 }
235}
236
237impl From<RecoveryError> for ProviderError {
238 fn from(_: RecoveryError) -> Self {
239 Self::SenderRecoveryError
240 }
241}
242
243impl From<ProviderError> for EvmDatabaseError<ProviderError> {
244 fn from(error: ProviderError) -> Self {
245 Self::Database(error)
246 }
247}
248
249impl From<DecompressError> for ProviderError {
250 fn from(error: DecompressError) -> Self {
251 Self::Database(error.into())
252 }
253}
254
255#[derive(Clone, Debug, PartialEq, Eq, Display)]
257#[display("root mismatch at #{block_number} ({block_hash}): {root}")]
258pub struct RootMismatch {
259 pub root: GotExpected<B256>,
261 pub block_number: BlockNumber,
263 pub block_hash: BlockHash,
265}
266
267#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
269pub enum StaticFileWriterError {
270 #[error("cannot call sync_all or finalize when prune is queued, use commit() instead")]
272 FinalizeWithPruneQueued,
273 #[error("thread panicked: {_0}")]
275 ThreadPanic(&'static str),
276 #[error("{0}")]
278 Other(String),
279}
280
281impl StaticFileWriterError {
282 pub fn new(message: impl Into<String>) -> Self {
284 Self::Other(message.into())
285 }
286}
287#[derive(Clone, Debug, PartialEq, Eq, Display)]
289pub enum ConsistentViewError {
290 #[display("node is syncing. best block: {best_block:?}")]
292 Syncing {
293 best_block: GotExpected<BlockNumber>,
295 },
296 #[display("inconsistent database state: {tip:?}")]
298 Inconsistent {
299 tip: GotExpected<Option<B256>>,
301 },
302 #[display("database view no longer contains block: {block:?}")]
304 Reorged {
305 block: B256,
307 },
308}
309
310impl From<ConsistentViewError> for ProviderError {
311 fn from(error: ConsistentViewError) -> Self {
312 Self::ConsistentView(Box::new(error))
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 #[derive(thiserror::Error, Debug)]
321 #[error("E")]
322 struct E;
323
324 #[test]
325 fn other_err() {
326 let err = ProviderError::other(E);
327 assert!(err.is_other::<E>());
328 assert!(err.downcast_other_ref::<E>().is_some());
329 }
330}