@@ -39,32 +39,38 @@ use alloy::{
3939use backon:: { ExponentialBuilder , Retryable } ;
4040use tracing:: { debug, error} ;
4141
42- pub const DEFAULT_TIMEOUT : Duration = Duration :: from_secs ( 30 ) ;
42+ // RPC retry and timeout settings
43+ /// Default timeout used by `SafeProvider`
44+ pub const DEFAULT_MAX_TIMEOUT : Duration = Duration :: from_secs ( 30 ) ;
45+ /// Default maximum number of retry attempts.
4346pub const DEFAULT_MAX_RETRIES : usize = 5 ;
47+ /// Default base delay between retries.
4448pub const DEFAULT_RETRY_INTERVAL : Duration = Duration :: from_secs ( 1 ) ;
4549
50+ /// Provider wrapper adding retries and timeouts.
4651#[ derive( Clone ) ]
4752pub struct SafeProvider < N : Network > {
4853 provider : RootProvider < N > ,
49- timeout : Duration ,
54+ max_timeout : Duration ,
5055 max_retries : usize ,
5156 retry_interval : Duration ,
5257}
5358
5459impl < N : Network > SafeProvider < N > {
60+ /// Create a new `SafeProvider` with default settings.
5561 #[ must_use]
5662 pub fn new ( provider : RootProvider < N > ) -> Self {
5763 Self {
5864 provider,
59- timeout : DEFAULT_TIMEOUT ,
65+ max_timeout : DEFAULT_MAX_TIMEOUT ,
6066 max_retries : DEFAULT_MAX_RETRIES ,
6167 retry_interval : DEFAULT_RETRY_INTERVAL ,
6268 }
6369 }
6470
6571 #[ must_use]
66- pub fn with_timeout ( mut self , timeout : Duration ) -> Self {
67- self . timeout = timeout;
72+ pub fn with_max_timeout ( mut self , timeout : Duration ) -> Self {
73+ self . max_timeout = timeout;
6874 self
6975 }
7076
@@ -85,7 +91,11 @@ impl<N: Network> SafeProvider<N> {
8591 & self . provider
8692 }
8793
88- #[ allow( clippy:: missing_errors_doc) ]
94+ /// Fetch a block by number with retry and timeout.
95+ ///
96+ /// # Errors
97+ /// Returns `RpcError<TransportErrorKind>` if the RPC call fails
98+ /// after exhausting retries or times out.
8999 pub async fn get_block_by_number (
90100 & self ,
91101 number : BlockNumberOrTag ,
@@ -100,7 +110,11 @@ impl<N: Network> SafeProvider<N> {
100110 result
101111 }
102112
103- #[ allow( clippy:: missing_errors_doc) ]
113+ /// Fetch the latest block number with retry and timeout.
114+ ///
115+ /// # Errors
116+ /// Returns `RpcError<TransportErrorKind>` if the RPC call fails
117+ /// after exhausting retries or times out.
104118 pub async fn get_block_number ( & self ) -> Result < u64 , RpcError < TransportErrorKind > > {
105119 debug ! ( "SafeProvider eth_getBlockNumber called" ) ;
106120 let provider = self . provider . clone ( ) ;
@@ -111,7 +125,11 @@ impl<N: Network> SafeProvider<N> {
111125 result
112126 }
113127
114- #[ allow( clippy:: missing_errors_doc) ]
128+ /// Fetch a block by hash with retry and timeout.
129+ ///
130+ /// # Errors
131+ /// Returns `RpcError<TransportErrorKind>` if the RPC call fails
132+ /// after exhausting retries or times out.
115133 pub async fn get_block_by_hash (
116134 & self ,
117135 hash : alloy:: primitives:: BlockHash ,
@@ -126,7 +144,11 @@ impl<N: Network> SafeProvider<N> {
126144 result
127145 }
128146
129- #[ allow( clippy:: missing_errors_doc) ]
147+ /// Fetch logs for the given filter with retry and timeout.
148+ ///
149+ /// # Errors
150+ /// Returns `RpcError<TransportErrorKind>` if the RPC call fails
151+ /// after exhausting retries or times out.
130152 pub async fn get_logs (
131153 & self ,
132154 filter : & Filter ,
@@ -140,7 +162,11 @@ impl<N: Network> SafeProvider<N> {
140162 result
141163 }
142164
143- #[ allow( clippy:: missing_errors_doc) ]
165+ /// Subscribe to new block headers with retry and timeout.
166+ ///
167+ /// # Errors
168+ /// Returns `RpcError<TransportErrorKind>` if the subscription
169+ /// cannot be established after retries or times out.
144170 pub async fn subscribe_blocks (
145171 & self ,
146172 ) -> Result < Subscription < N :: HeaderResponse > , RpcError < TransportErrorKind > > {
@@ -153,7 +179,11 @@ impl<N: Network> SafeProvider<N> {
153179 result
154180 }
155181
156- #[ allow( clippy:: missing_errors_doc) ]
182+ /// Execute `operation` with exponential backoff and a total timeout.
183+ ///
184+ /// # Errors
185+ /// Returns `RpcError<TransportErrorKind>` if all attempts fail or the
186+ /// total delay exceeds the configured timeout.
157187 pub ( crate ) async fn retry_with_timeout < T , F , Fut > (
158188 & self ,
159189 operation : F ,
@@ -164,7 +194,7 @@ impl<N: Network> SafeProvider<N> {
164194 {
165195 let retry_strategy = ExponentialBuilder :: default ( )
166196 . with_max_times ( self . max_retries )
167- . with_total_delay ( Some ( self . timeout ) )
197+ . with_total_delay ( Some ( self . max_timeout ) )
168198 . with_min_delay ( self . retry_interval ) ;
169199
170200 operation. retry ( retry_strategy) . sleep ( tokio:: time:: sleep) . await
@@ -184,7 +214,7 @@ mod tests {
184214 ) -> SafeProvider < Ethereum > {
185215 SafeProvider {
186216 provider : RootProvider :: < Ethereum > :: new_http ( "http://localhost:8545" . parse ( ) . unwrap ( ) ) ,
187- timeout,
217+ max_timeout : timeout,
188218 max_retries,
189219 retry_interval,
190220 }
0 commit comments