@@ -24,7 +24,7 @@ pub(crate) fn checksum(bytes: impl AsRef<[u8]>) -> String {
2424/// Constructs a `ParameterError::ChecksumMismatch` error from an expected and a computed checksum.
2525/// Used to report integrity failures when a loaded or downloaded file does not match its metadata.
2626/// Generic over `T` so it can be returned from any `Result<T, ParameterError>`-returning function.
27- #[ cfg( feature = "filesystem" ) ]
27+ #[ cfg( any ( feature = "filesystem" , feature = "wasm" ) ) ]
2828#[ inline( always) ]
2929pub ( crate ) fn checksum_error < T > ( expected : String , candidate : String ) -> Result < T , crate :: errors:: ParameterError > {
3030 Err ( crate :: errors:: ParameterError :: ChecksumMismatch ( expected, candidate) )
@@ -85,7 +85,7 @@ pub(crate) fn load_bytes_local(
8585/// Used internally by `impl_remote!` to provide download and caching support.
8686macro_rules! impl_store_and_remote_fetch {
8787 ( ) => {
88- #[ cfg( all( feature= "filesystem" , not( feature = "wasm" ) ) ) ]
88+ #[ cfg( all( feature = "filesystem" , not( feature = "wasm" ) ) ) ]
8989 fn store_bytes( buffer: & [ u8 ] , file_path: & std:: path:: Path ) -> Result <( ) , $crate:: errors:: ParameterError > {
9090 use snarkvm_utilities:: Write ;
9191
@@ -109,35 +109,34 @@ macro_rules! impl_store_and_remote_fetch {
109109 Ok ( ( ) )
110110 }
111111
112- #[ cfg( all( feature= "filesystem" , not( feature = "wasm" ) , not( target_env = "sgx" ) ) ) ]
112+ #[ cfg( all( feature = "filesystem" , not( feature = "wasm" ) , not( target_env = "sgx" ) ) ) ]
113113 fn remote_fetch( buffer: & mut Vec <u8 >, url: & str ) -> Result <( ) , $crate:: errors:: ParameterError > {
114+ use std:: io:: Read ;
115+
114116 #[ cfg( not( feature = "no_std_out" ) ) ]
115117 {
116118 use colored:: * ;
117119 let output = format!( "{:>15} - Downloading \" {url}\" " , "Installation" ) ;
118120 println!( "{}" , output. dimmed( ) ) ;
119121 }
120122
121- let host = url. split( '/' ) . nth( 2 ) . unwrap_or_default( ) . to_string( ) ;
122- let retry_policy = reqwest:: retry:: for_host( host)
123- . max_retries_per_request( 3 )
124- . classify_fn( |req_rep| {
125- if req_rep. error( ) . is_some( ) {
126- return req_rep. retryable( ) ;
123+ // Retry up to 3 times on transient errors (5xx, 429, IO, timeout).
124+ let mut attempts = 3u32 ;
125+ loop {
126+ match ureq:: get( url) . config( ) . max_redirects( 10 ) . build( ) . call( ) {
127+ Ok ( mut response) => {
128+ response. body_mut( ) . as_reader( ) . read_to_end( buffer) ?;
129+ break ;
127130 }
128- match req_rep. status( ) {
129- Some ( status) if status. is_server_error( ) || status. as_u16( ) == 429 => req_rep. retryable( ) ,
130- _ => req_rep. success( ) ,
131+ Err ( ureq:: Error :: StatusCode ( code) ) if attempts > 0 && ( code >= 500 || code == 429 ) => {
132+ attempts -= 1 ;
131133 }
132- } ) ;
133-
134- let client = reqwest:: blocking:: Client :: builder( )
135- . redirect( reqwest:: redirect:: Policy :: limited( 10 ) ) // Limit to 10 redirects.
136- . retry( retry_policy)
137- . build( ) ?;
138-
139- let mut response = client. get( url) . send( ) ?. error_for_status( ) ?;
140- response. copy_to( buffer) ?;
134+ Err ( ureq:: Error :: Io ( _) | ureq:: Error :: Timeout ( _) ) if attempts > 0 => {
135+ attempts -= 1 ;
136+ }
137+ Err ( err) => return Err ( err. into( ) ) ,
138+ }
139+ }
141140
142141 #[ cfg( not( feature = "no_std_out" ) ) ]
143142 {
0 commit comments