Skip to main content

event_scanner/
error.rs

1use std::{mem::discriminant, sync::Arc};
2
3use alloy::transports::{RpcError, TransportErrorKind};
4use thiserror::Error;
5
6use crate::types::ScannerResult;
7
8use robust_provider::Error as RobustProviderError;
9
10/// Errors emitted by the scanner.
11///
12/// `ScannerError` values can be returned by builder `connect()` methods and are also yielded by
13/// subscription streams (as `Err(ScannerError)` items).
14///
15/// All errors except [`ScannerError::Lagged`] are terminal and will halt further stream processing.
16#[derive(Error, Debug, Clone)]
17pub enum ScannerError {
18    /// The underlying RPC transport returned an error.
19    #[error("RPC error: {0}")]
20    RpcError(Arc<RpcError<TransportErrorKind>>),
21
22    /// A requested block (by number, hash or tag) could not be retrieved.
23    #[error("Block not found")]
24    BlockNotFound,
25
26    /// A timeout elapsed while waiting for an RPC response.
27    #[error("Operation timed out")]
28    Timeout,
29
30    /// A configured block parameter exceeds the latest known block.
31    #[error("{0} {1} exceeds the latest block {2}")]
32    BlockExceedsLatest(&'static str, u64, u64),
33
34    /// The requested event count is invalid (must be greater than zero).
35    #[error("Event count must be greater than 0")]
36    InvalidEventCount,
37
38    /// The configured maximum block range is invalid (must be greater than zero).
39    #[error("Max block range must be greater than 0")]
40    InvalidMaxBlockRange,
41
42    /// The configured stream buffer capacity is invalid (must be greater than zero).
43    #[error("Stream buffer capacity must be greater than 0")]
44    InvalidBufferCapacity,
45
46    /// The configured maximum number of concurrent fetches is invalid (must be greater than
47    /// zero).
48    #[error("Max concurrent fetches must be greater than 0")]
49    InvalidMaxConcurrentFetches,
50
51    /// A block subscription ended (for example, the underlying WebSocket subscription closed).
52    #[error("Subscription closed")]
53    SubscriptionClosed,
54
55    /// A subscription consumer could not keep up and some internal messages were skipped.
56    ///
57    /// The contained value is the number of skipped messages reported by the underlying channel.
58    /// After emitting this error, the subscription stream may continue with newer items.
59    #[error("Subscription lagged")]
60    Lagged(u64),
61}
62
63impl From<RobustProviderError> for ScannerError {
64    fn from(error: RobustProviderError) -> ScannerError {
65        match error {
66            RobustProviderError::Timeout => ScannerError::Timeout,
67            RobustProviderError::RpcError(err) => ScannerError::RpcError(Arc::new(err)),
68            RobustProviderError::BlockNotFound => ScannerError::BlockNotFound,
69            RobustProviderError::Lagged(blocks) => ScannerError::Lagged(blocks),
70            RobustProviderError::Closed => ScannerError::SubscriptionClosed,
71        }
72    }
73}
74
75impl From<RpcError<TransportErrorKind>> for ScannerError {
76    fn from(error: RpcError<TransportErrorKind>) -> Self {
77        ScannerError::RpcError(Arc::new(error))
78    }
79}
80
81impl<T: Clone> PartialEq<ScannerError> for ScannerResult<T> {
82    fn eq(&self, other: &ScannerError) -> bool {
83        match self {
84            Ok(_) => false,
85            Err(err) => discriminant(err) == discriminant(other),
86        }
87    }
88}