1414use  std:: collections:: HashMap ; 
1515use  std:: convert:: TryFrom ; 
1616use  std:: str:: FromStr ; 
17+ use  std:: thread; 
18+ use  std:: time:: Duration ; 
1719
1820#[ allow( unused_imports) ]  
1921use  log:: { debug,  error,  info,  trace} ; 
2022
21- use  minreq:: { Proxy ,  Request } ; 
23+ use  minreq:: { Proxy ,  Request ,   Response } ; 
2224
2325use  bitcoin:: consensus:: { deserialize,  serialize,  Decodable } ; 
2426use  bitcoin:: hashes:: { sha256,  Hash } ; 
@@ -27,7 +29,10 @@ use bitcoin::{
2729    block:: Header  as  BlockHeader ,  Block ,  BlockHash ,  MerkleBlock ,  Script ,  Transaction ,  Txid , 
2830} ; 
2931
30- use  crate :: { BlockStatus ,  BlockSummary ,  Builder ,  Error ,  MerkleProof ,  OutputStatus ,  Tx ,  TxStatus } ; 
32+ use  crate :: { 
33+     BlockStatus ,  BlockSummary ,  Builder ,  Error ,  MerkleProof ,  OutputStatus ,  Tx ,  TxStatus , 
34+     RETRYABLE_ERROR_CODES , 
35+ } ; 
3136
3237#[ derive( Debug ,  Clone ) ]  
3338pub  struct  BlockingClient  { 
@@ -39,6 +44,10 @@ pub struct BlockingClient {
3944pub  timeout :  Option < u64 > , 
4045    /// HTTP headers to set on every request made to Esplora server 
4146pub  headers :  HashMap < String ,  String > , 
47+     /// Backoff 
48+ pub  backoff :  Duration , 
49+     /// Max retries 
50+ pub  max_retries :  u32 , 
4251} 
4352
4453impl  BlockingClient  { 
@@ -49,6 +58,8 @@ impl BlockingClient {
4958            proxy :  builder. proxy , 
5059            timeout :  builder. timeout , 
5160            headers :  builder. headers , 
61+             backoff :  builder. backoff , 
62+             max_retries :  builder. max_retries , 
5263        } 
5364    } 
5465
@@ -80,20 +91,20 @@ impl BlockingClient {
8091    } 
8192
8293    fn  get_opt_response < T :  Decodable > ( & self ,  path :  & str )  -> Result < Option < T > ,  Error >  { 
83-         match  self . get_request ( path) ? . send ( )  { 
94+         match  self . get_with_retry ( path)  { 
8495            Ok ( resp)  if  is_status_not_found ( resp. status_code )  => Ok ( None ) , 
8596            Ok ( resp)  if  !is_status_ok ( resp. status_code )  => { 
8697                let  status = u16:: try_from ( resp. status_code ) . map_err ( Error :: StatusCode ) ?; 
8798                let  message = resp. as_str ( ) . unwrap_or_default ( ) . to_string ( ) ; 
8899                Err ( Error :: HttpResponse  {  status,  message } ) 
89100            } 
90101            Ok ( resp)  => Ok ( Some ( deserialize :: < T > ( resp. as_bytes ( ) ) ?) ) , 
91-             Err ( e)  => Err ( Error :: Minreq ( e ) ) , 
102+             Err ( e)  => Err ( e ) , 
92103        } 
93104    } 
94105
95106    fn  get_opt_response_txid ( & self ,  path :  & str )  -> Result < Option < Txid > ,  Error >  { 
96-         match  self . get_request ( path) ? . send ( )  { 
107+         match  self . get_with_retry ( path)  { 
97108            Ok ( resp)  if  is_status_not_found ( resp. status_code )  => Ok ( None ) , 
98109            Ok ( resp)  if  !is_status_ok ( resp. status_code )  => { 
99110                let  status = u16:: try_from ( resp. status_code ) . map_err ( Error :: StatusCode ) ?; 
@@ -103,12 +114,12 @@ impl BlockingClient {
103114            Ok ( resp)  => Ok ( Some ( 
104115                Txid :: from_str ( resp. as_str ( ) . map_err ( Error :: Minreq ) ?) . map_err ( Error :: HexToArray ) ?, 
105116            ) ) , 
106-             Err ( e)  => Err ( Error :: Minreq ( e ) ) , 
117+             Err ( e)  => Err ( e ) , 
107118        } 
108119    } 
109120
110121    fn  get_opt_response_hex < T :  Decodable > ( & self ,  path :  & str )  -> Result < Option < T > ,  Error >  { 
111-         match  self . get_request ( path) ? . send ( )  { 
122+         match  self . get_with_retry ( path)  { 
112123            Ok ( resp)  if  is_status_not_found ( resp. status_code )  => Ok ( None ) , 
113124            Ok ( resp)  if  !is_status_ok ( resp. status_code )  => { 
114125                let  status = u16:: try_from ( resp. status_code ) . map_err ( Error :: StatusCode ) ?; 
@@ -122,12 +133,12 @@ impl BlockingClient {
122133                    . map_err ( Error :: BitcoinEncoding ) 
123134                    . map ( |r| Some ( r) ) 
124135            } 
125-             Err ( e)  => Err ( Error :: Minreq ( e ) ) , 
136+             Err ( e)  => Err ( e ) , 
126137        } 
127138    } 
128139
129140    fn  get_response_hex < T :  Decodable > ( & self ,  path :  & str )  -> Result < T ,  Error >  { 
130-         match  self . get_request ( path) ? . send ( )  { 
141+         match  self . get_with_retry ( path)  { 
131142            Ok ( resp)  if  !is_status_ok ( resp. status_code )  => { 
132143                let  status = u16:: try_from ( resp. status_code ) . map_err ( Error :: StatusCode ) ?; 
133144                let  message = resp. as_str ( ) . unwrap_or_default ( ) . to_string ( ) ; 
@@ -138,51 +149,51 @@ impl BlockingClient {
138149                let  hex_vec = Vec :: from_hex ( hex_str) . unwrap ( ) ; 
139150                deserialize :: < T > ( & hex_vec) . map_err ( Error :: BitcoinEncoding ) 
140151            } 
141-             Err ( e)  => Err ( Error :: Minreq ( e ) ) , 
152+             Err ( e)  => Err ( e ) , 
142153        } 
143154    } 
144155
145156    fn  get_response_json < ' a ,  T :  serde:: de:: DeserializeOwned > ( 
146157        & ' a  self , 
147158        path :  & ' a  str , 
148159    )  -> Result < T ,  Error >  { 
149-         let  response = self . get_request ( path) ? . send ( ) ; 
160+         let  response = self . get_with_retry ( path) ; 
150161        match  response { 
151162            Ok ( resp)  if  !is_status_ok ( resp. status_code )  => { 
152163                let  status = u16:: try_from ( resp. status_code ) . map_err ( Error :: StatusCode ) ?; 
153164                let  message = resp. as_str ( ) . unwrap_or_default ( ) . to_string ( ) ; 
154165                Err ( Error :: HttpResponse  {  status,  message } ) 
155166            } 
156167            Ok ( resp)  => Ok ( resp. json :: < T > ( ) . map_err ( Error :: Minreq ) ?) , 
157-             Err ( e)  => Err ( Error :: Minreq ( e ) ) , 
168+             Err ( e)  => Err ( e ) , 
158169        } 
159170    } 
160171
161172    fn  get_opt_response_json < T :  serde:: de:: DeserializeOwned > ( 
162173        & self , 
163174        path :  & str , 
164175    )  -> Result < Option < T > ,  Error >  { 
165-         match  self . get_request ( path) ? . send ( )  { 
176+         match  self . get_with_retry ( path)  { 
166177            Ok ( resp)  if  is_status_not_found ( resp. status_code )  => Ok ( None ) , 
167178            Ok ( resp)  if  !is_status_ok ( resp. status_code )  => { 
168179                let  status = u16:: try_from ( resp. status_code ) . map_err ( Error :: StatusCode ) ?; 
169180                let  message = resp. as_str ( ) . unwrap_or_default ( ) . to_string ( ) ; 
170181                Err ( Error :: HttpResponse  {  status,  message } ) 
171182            } 
172183            Ok ( resp)  => Ok ( Some ( resp. json :: < T > ( ) ?) ) , 
173-             Err ( e)  => Err ( Error :: Minreq ( e ) ) , 
184+             Err ( e)  => Err ( e ) , 
174185        } 
175186    } 
176187
177188    fn  get_response_str ( & self ,  path :  & str )  -> Result < String ,  Error >  { 
178-         match  self . get_request ( path) ? . send ( )  { 
189+         match  self . get_with_retry ( path)  { 
179190            Ok ( resp)  if  !is_status_ok ( resp. status_code )  => { 
180191                let  status = u16:: try_from ( resp. status_code ) . map_err ( Error :: StatusCode ) ?; 
181192                let  message = resp. as_str ( ) . unwrap_or_default ( ) . to_string ( ) ; 
182193                Err ( Error :: HttpResponse  {  status,  message } ) 
183194            } 
184195            Ok ( resp)  => Ok ( resp. as_str ( ) ?. to_string ( ) ) , 
185-             Err ( e)  => Err ( Error :: Minreq ( e ) ) , 
196+             Err ( e)  => Err ( e ) , 
186197        } 
187198    } 
188199
@@ -339,6 +350,28 @@ impl BlockingClient {
339350        } ; 
340351        self . get_response_json ( & path) 
341352    } 
353+ 
354+     /// Sends a GET request to the given `url`, retrying failed attempts 
355+ /// for retryable error codes until max retries hit. 
356+ pub  fn  get_with_retry ( & self ,  url :  & str )  -> Result < Response ,  Error >  { 
357+         let  mut  attempts = 0 ; 
358+         let  mut  delay = self . backoff ; 
359+ 
360+         loop  { 
361+             match  self . get_request ( url) ?. send ( )  { 
362+                 Ok ( resp) 
363+                     if  attempts < self . max_retries 
364+                         && RETRYABLE_ERROR_CODES . contains ( & ( resp. status_code  as  u16 ) )  =>
365+                 { 
366+                     thread:: sleep ( delay) ; 
367+                     attempts += 1 ; 
368+                     delay *= 2 ; 
369+                 } 
370+                 Ok ( resp)  => return  Ok ( resp) , 
371+                 Err ( e)  => return  Err ( Error :: Minreq ( e) ) , 
372+             } 
373+         } 
374+     } 
342375} 
343376
344377fn  is_status_ok ( status :  i32 )  -> bool  { 
0 commit comments