From a33a70a166e3e391c2209019f164eff5f539574f Mon Sep 17 00:00:00 2001 From: psg-19 Date: Thu, 29 May 2025 17:16:47 +0530 Subject: [PATCH 01/18] Replacing reqwest with async-minreq --- Cargo.toml | 2 + src/async.rs | 204 +++++++++++++++++++++++++++++++-------------------- src/lib.rs | 26 ++++++- 3 files changed, 149 insertions(+), 83 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f1e85b9..c4c506c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,8 @@ hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } reqwest = { version = "0.12", features = ["json"], default-features = false, optional = true } +async_minreq = { git = "https://github.com/BEULAHEVANJALIN/async-minreq.git" } +serde_json = "1.0.140" # default async runtime tokio = { version = "1", features = ["time"], optional = true } diff --git a/src/async.rs b/src/async.rs index b72988b..7d7ef1e 100644 --- a/src/async.rs +++ b/src/async.rs @@ -14,6 +14,8 @@ use std::collections::HashMap; use std::marker::PhantomData; use std::str::FromStr; +use std::time::Duration;//-----------------------added---------------- +use std::convert::TryInto;//-------------------added----------------- use bitcoin::consensus::{deserialize, serialize, Decodable, Encodable}; use bitcoin::hashes::{sha256, Hash}; @@ -26,71 +28,96 @@ use bitcoin::{ #[allow(unused_imports)] use log::{debug, error, info, trace}; -use reqwest::{header, Client, Response}; - +// use reqwest::{header, Client, Response}; +use async_minreq::{Method, Request}; //-----------------------added------------------- use crate::api::AddressStats; use crate::{ BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES, }; +// #[derive(Debug, Clone)] +// pub struct AsyncClient { +// /// The URL of the Esplora Server. +// url: String, +// /// The inner [`reqwest::Client`] to make HTTP requests. +// client: Client, +// /// Number of times to retry a request +// max_retries: usize, + +// /// Marker for the type of sleeper used +// marker: PhantomData, +// } + #[derive(Debug, Clone)] pub struct AsyncClient { - /// The URL of the Esplora Server. + /// The base URL of the Esplora server. url: String, - /// The inner [`reqwest::Client`] to make HTTP requests. - client: Client, - /// Number of times to retry a request + /// Number of times to retry a request. max_retries: usize, - - /// Marker for the type of sleeper used + /// Default headers (applied to every request). + headers: HashMap, + /// Marker for the sleeper. marker: PhantomData, } impl AsyncClient { /// Build an async client from a builder pub fn from_builder(builder: Builder) -> Result { - let mut client_builder = Client::builder(); - - #[cfg(not(target_arch = "wasm32"))] - if let Some(proxy) = &builder.proxy { - client_builder = client_builder.proxy(reqwest::Proxy::all(proxy)?); - } - #[cfg(not(target_arch = "wasm32"))] - if let Some(timeout) = builder.timeout { - client_builder = client_builder.timeout(core::time::Duration::from_secs(timeout)); - } - - if !builder.headers.is_empty() { - let mut headers = header::HeaderMap::new(); - for (k, v) in builder.headers { - let header_name = header::HeaderName::from_lowercase(k.to_lowercase().as_bytes()) - .map_err(|_| Error::InvalidHttpHeaderName(k))?; - let header_value = header::HeaderValue::from_str(&v) - .map_err(|_| Error::InvalidHttpHeaderValue(v))?; - headers.insert(header_name, header_value); - } - client_builder = client_builder.default_headers(headers); - } - - Ok(AsyncClient { + //----------------------------------------not needed since no client struct in async minreq------------------------------------ + // let mut client_builder = Client::builder(); + + // #[cfg(not(target_arch = "wasm32"))] + // if let Some(proxy) = &builder.proxy { + // client_builder = client_builder.proxy(reqwest::Proxy::all(proxy)?); + // } + + // #[cfg(not(target_arch = "wasm32"))] + // if let Some(timeout) = builder.timeout { + // client_builder = client_builder.timeout(core::time::Duration::from_secs(timeout)); + // } + + // if !builder.headers.is_empty() { + // let mut headers = header::HeaderMap::new(); + // for (k, v) in builder.headers { + // let header_name = header::HeaderName::from_lowercase(k.to_lowercase().as_bytes()) + // .map_err(|_| Error::InvalidHttpHeaderName(k))?; + // let header_value = header::HeaderValue::from_str(&v) + // .map_err(|_| Error::InvalidHttpHeaderValue(v))?; + // headers.insert(header_name, header_value); + // } + // client_builder = client_builder.default_headers(headers); + // } + + // Ok(AsyncClient { + // url: builder.base_url, + // client: client_builder.build()?, + // max_retries: builder.max_retries, + // marker: PhantomData, + // }) + +//-------------------------------------------------------------------------------------- + Ok(AsyncClient { url: builder.base_url, - client: client_builder.build()?, max_retries: builder.max_retries, + headers: builder.headers, marker: PhantomData, }) - } - pub fn from_client(url: String, client: Client) -> Self { - AsyncClient { - url, - client, - max_retries: crate::DEFAULT_MAX_RETRIES, - marker: PhantomData, - } + } + //----------------------------------------not needed since no client struct in async minreq------------------------------------ + // pub fn from_client(url: String, client: Client) -> Self { + // AsyncClient { + // url, + // client, + // max_retries: crate::DEFAULT_MAX_RETRIES, + // marker: PhantomData, + // } + // } +//----------------------------------------------------------------------------------------------- /// Make an HTTP GET request to given URL, deserializing to any `T` that /// implement [`bitcoin::consensus::Decodable`]. /// @@ -106,14 +133,14 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if !response.status().is_success() { + if !(response.status_code==200) { return Err(Error::HttpResponse { - status: response.status().as_u16(), - message: response.text().await?, + status: response.status_code as u16, + message: response.as_str().unwrap().to_string(), }); } - Ok(deserialize::(&response.bytes().await?)?) + Ok(deserialize::(&response.as_bytes())?) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -146,14 +173,14 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if !response.status().is_success() { + if !(response.status_code==200) { return Err(Error::HttpResponse { - status: response.status().as_u16(), - message: response.text().await?, + status: response.status_code as u16, + message: response.as_str().unwrap().to_string(), }); } - response.json::().await.map_err(Error::Reqwest) + serde_json::from_str(&response.as_str().unwrap().to_string()).map_err(Error::Json) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -188,14 +215,14 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if !response.status().is_success() { + if !(response.status_code==200) { return Err(Error::HttpResponse { - status: response.status().as_u16(), - message: response.text().await?, + status: response.status_code as u16, + message:response.as_str().unwrap().to_string(), }); } - let hex_str = response.text().await?; + let hex_str =response.as_str().unwrap().to_string(); Ok(deserialize(&Vec::from_hex(&hex_str)?)?) } @@ -225,14 +252,14 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if !response.status().is_success() { + if !(response.status_code==200) { return Err(Error::HttpResponse { - status: response.status().as_u16(), - message: response.text().await?, + status: response.status_code as u16, + message:response.as_str().unwrap().to_string(), }); } - - Ok(response.text().await?) +// let x=response.as_str().unwrap().to_string(); + Ok(response.as_str().unwrap().to_string()) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -263,15 +290,12 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let body = serialize::(&body).to_lower_hex_string(); - let response = self.client.post(url).body(body).send().await?; - - if !response.status().is_success() { - return Err(Error::HttpResponse { - status: response.status().as_u16(), - message: response.text().await?, - }); + let mut request = Request::new(Method::Post, &url).with_body(body); + for (key, value) in &self.headers { + request = request.with_header(key, value); } - + + let _ = request.send().await.map_err(Error::AsyncMinreq)?; Ok(()) } @@ -284,7 +308,7 @@ impl AsyncClient { pub async fn get_tx_no_opt(&self, txid: &Txid) -> Result { match self.get_tx(txid).await { Ok(Some(tx)) => Ok(tx), - Ok(None) => Err(Error::TransactionNotFound(*txid)), + Ok(None) => Err(Error::TransactionNotFound(*txid)), //look into Err(e) => Err(e), } } @@ -455,32 +479,52 @@ impl AsyncClient { } /// Get the underlying [`Client`]. - pub fn client(&self) -> &Client { - &self.client - } + // pub fn client(&self) -> &Client { + // &self.client + // } /// Sends a GET request to the given `url`, retrying failed attempts /// for retryable error codes until max retries hit. - async fn get_with_retry(&self, url: &str) -> Result { + async fn get_with_retry(&self, url: &str) -> Result { let mut delay = BASE_BACKOFF_MILLIS; let mut attempts = 0; loop { - match self.client.get(url).send().await? { - resp if attempts < self.max_retries && is_status_retryable(resp.status()) => { - S::sleep(delay).await; - attempts += 1; - delay *= 2; + let mut request = Request::new(Method::Get, url); + // Apply headers from the builder. + for (key, value) in &self.headers { + request = request.with_header(key, value); + } + // request. + + let res = request.send().await.map_err(Error::AsyncMinreq); + + match res { + Ok(body) => { + + + return Ok(body); + + }, + Err(e) => { + // Here you might inspect the error (if possible) to decide whether to retry. + // For simplicity, we retry on any error until max_retries is reached. + if attempts < self.max_retries { + S::sleep(delay).await; + attempts += 1; + delay *= 2; + continue; + } + return Err(e); } - resp => return Ok(resp), } } } } -fn is_status_retryable(status: reqwest::StatusCode) -> bool { - RETRYABLE_ERROR_CODES.contains(&status.as_u16()) -} +// fn is_status_retryable(status: reqwest::StatusCode) -> bool { +// RETRYABLE_ERROR_CODES.contains(&status.as_u16()) +// } pub trait Sleeper: 'static { type Sleep: std::future::Future; diff --git a/src/lib.rs b/src/lib.rs index 5c48318..bf4df57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,8 +201,14 @@ pub enum Error { #[cfg(feature = "blocking")] Minreq(::minreq::Error), /// Error during reqwest HTTP request - #[cfg(feature = "async")] - Reqwest(::reqwest::Error), + //-----------------------------------------------changed------------------------------ + // #[cfg(feature = "async")] + // Reqwest(::reqwest::Error), + #[cfg(feature = "async")] + AsyncMinreq(async_minreq::Error), + Json(serde_json::Error), + + /// HTTP response error HttpResponse { status: u16, message: String }, /// Invalid number returned @@ -251,8 +257,22 @@ macro_rules! impl_error { impl std::error::Error for Error {} #[cfg(feature = "blocking")] impl_error!(::minreq::Error, Minreq, Error); + +//---------------------------------------------changed------------------------------ #[cfg(feature = "async")] -impl_error!(::reqwest::Error, Reqwest, Error); +// impl_error!(::reqwest::Error, Reqwest, Error); +impl std::convert::From for Error { + fn from(err: async_minreq::Error) -> Self { + Error::AsyncMinreq(err) + } +} + +impl std::convert::From for Error { + fn from(err: serde_json::Error) -> Self { + Error::Json(err) + } +} +// impl_error!(::reqwest::Error, Reqwest, Error); impl_error!(std::num::ParseIntError, Parsing, Error); impl_error!(bitcoin::consensus::encode::Error, BitcoinEncoding, Error); impl_error!(bitcoin::hex::HexToArrayError, HexToArray, Error); From 2997b1693c8967e147cf493ddc94097e2a53bf43 Mon Sep 17 00:00:00 2001 From: psg-19 Date: Thu, 29 May 2025 20:22:31 +0530 Subject: [PATCH 02/18] fix:from_client function --- src/async.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/async.rs b/src/async.rs index 7d7ef1e..614f9ac 100644 --- a/src/async.rs +++ b/src/async.rs @@ -108,16 +108,14 @@ impl AsyncClient { } - //----------------------------------------not needed since no client struct in async minreq------------------------------------ - // pub fn from_client(url: String, client: Client) -> Self { - // AsyncClient { - // url, - // client, - // max_retries: crate::DEFAULT_MAX_RETRIES, - // marker: PhantomData, - // } - // } -//----------------------------------------------------------------------------------------------- + pub fn from_client(url: String, client: Client) -> Self { + AsyncClient { + url, + headers, + max_retries: crate::DEFAULT_MAX_RETRIES, + marker: PhantomData, + } + } /// Make an HTTP GET request to given URL, deserializing to any `T` that /// implement [`bitcoin::consensus::Decodable`]. /// @@ -507,8 +505,7 @@ impl AsyncClient { }, Err(e) => { - // Here you might inspect the error (if possible) to decide whether to retry. - // For simplicity, we retry on any error until max_retries is reached. + if attempts < self.max_retries { S::sleep(delay).await; attempts += 1; From a4b945a4633acfaba3fd718c9d9fcd07fd0cba4c Mon Sep 17 00:00:00 2001 From: psg-19 Date: Tue, 3 Jun 2025 15:17:53 +0530 Subject: [PATCH 03/18] fix: is_status_retryable() function and post_request_hex() function causing failure to some tests. --- Cargo.toml | 11 +++--- src/async.rs | 100 +++++++++++++-------------------------------------- src/lib.rs | 28 +++------------ 3 files changed, 35 insertions(+), 104 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c4c506c..43981bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,6 @@ bitcoin = { version = "0.32", features = ["serde", "std"], default-features = fa hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } -reqwest = { version = "0.12", features = ["json"], default-features = false, optional = true } async_minreq = { git = "https://github.com/BEULAHEVANJALIN/async-minreq.git" } serde_json = "1.0.140" @@ -44,8 +43,8 @@ blocking-https-native = ["blocking", "minreq/https-native"] blocking-https-bundled = ["blocking", "minreq/https-bundled"] tokio = ["dep:tokio"] -async = ["reqwest", "reqwest/socks", "tokio?/time"] -async-https = ["async", "reqwest/default-tls"] -async-https-native = ["async", "reqwest/native-tls"] -async-https-rustls = ["async", "reqwest/rustls-tls"] -async-https-rustls-manual-roots = ["async", "reqwest/rustls-tls-manual-roots"] +async = [ "tokio?/time"] +async-https = ["async"] +async-https-native = ["async"] +async-https-rustls = ["async"] +async-https-rustls-manual-roots = ["async"] \ No newline at end of file diff --git a/src/async.rs b/src/async.rs index 614f9ac..237e607 100644 --- a/src/async.rs +++ b/src/async.rs @@ -14,9 +14,6 @@ use std::collections::HashMap; use std::marker::PhantomData; use std::str::FromStr; -use std::time::Duration;//-----------------------added---------------- -use std::convert::TryInto;//-------------------added----------------- - use bitcoin::consensus::{deserialize, serialize, Decodable, Encodable}; use bitcoin::hashes::{sha256, Hash}; use bitcoin::hex::{DisplayHex, FromHex}; @@ -64,58 +61,22 @@ pub struct AsyncClient { impl AsyncClient { /// Build an async client from a builder pub fn from_builder(builder: Builder) -> Result { - - //----------------------------------------not needed since no client struct in async minreq------------------------------------ - // let mut client_builder = Client::builder(); - - // #[cfg(not(target_arch = "wasm32"))] - // if let Some(proxy) = &builder.proxy { - // client_builder = client_builder.proxy(reqwest::Proxy::all(proxy)?); - // } - - // #[cfg(not(target_arch = "wasm32"))] - // if let Some(timeout) = builder.timeout { - // client_builder = client_builder.timeout(core::time::Duration::from_secs(timeout)); - // } - - // if !builder.headers.is_empty() { - // let mut headers = header::HeaderMap::new(); - // for (k, v) in builder.headers { - // let header_name = header::HeaderName::from_lowercase(k.to_lowercase().as_bytes()) - // .map_err(|_| Error::InvalidHttpHeaderName(k))?; - // let header_value = header::HeaderValue::from_str(&v) - // .map_err(|_| Error::InvalidHttpHeaderValue(v))?; - // headers.insert(header_name, header_value); - // } - // client_builder = client_builder.default_headers(headers); - // } - - // Ok(AsyncClient { - // url: builder.base_url, - // client: client_builder.build()?, - // max_retries: builder.max_retries, - // marker: PhantomData, - // }) - -//-------------------------------------------------------------------------------------- Ok(AsyncClient { url: builder.base_url, max_retries: builder.max_retries, headers: builder.headers, marker: PhantomData, }) - - } - pub fn from_client(url: String, client: Client) -> Self { + pub fn from_client(url: String, headers: HashMap,) -> Self { AsyncClient { url, headers, max_retries: crate::DEFAULT_MAX_RETRIES, marker: PhantomData, } - } + } /// Make an HTTP GET request to given URL, deserializing to any `T` that /// implement [`bitcoin::consensus::Decodable`]. /// @@ -131,13 +92,12 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if !(response.status_code==200) { + if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, message: response.as_str().unwrap().to_string(), }); } - Ok(deserialize::(&response.as_bytes())?) } @@ -171,13 +131,12 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if !(response.status_code==200) { + if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, message: response.as_str().unwrap().to_string(), }); } - serde_json::from_str(&response.as_str().unwrap().to_string()).map_err(Error::Json) } @@ -213,13 +172,12 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if !(response.status_code==200) { + if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, message:response.as_str().unwrap().to_string(), }); } - let hex_str =response.as_str().unwrap().to_string(); Ok(deserialize(&Vec::from_hex(&hex_str)?)?) } @@ -250,13 +208,12 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if !(response.status_code==200) { + if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, message:response.as_str().unwrap().to_string(), }); } -// let x=response.as_str().unwrap().to_string(); Ok(response.as_str().unwrap().to_string()) } @@ -293,7 +250,13 @@ impl AsyncClient { request = request.with_header(key, value); } - let _ = request.send().await.map_err(Error::AsyncMinreq)?; + let response = request.send().await.map_err(Error::AsyncMinreq)?; + if response.status_code>299{ + return Err(Error::HttpResponse { + status: response.status_code as u16, + message: response.as_str().unwrap().to_string(), + }); + } Ok(()) } @@ -489,39 +452,26 @@ impl AsyncClient { loop { let mut request = Request::new(Method::Get, url); - // Apply headers from the builder. + // Applying headers from the builder. for (key, value) in &self.headers { request = request.with_header(key, value); } - // request. - - let res = request.send().await.map_err(Error::AsyncMinreq); - - match res { - Ok(body) => { - - - return Ok(body); - - }, - Err(e) => { - - if attempts < self.max_retries { - S::sleep(delay).await; - attempts += 1; - delay *= 2; - continue; - } - return Err(e); + + match request.send().await? { + resp if attempts < self.max_retries && is_status_retryable(resp.status_code) => { + S::sleep(delay).await; + attempts += 1; + delay *= 2; } + resp => return Ok(resp), } } } } -// fn is_status_retryable(status: reqwest::StatusCode) -> bool { -// RETRYABLE_ERROR_CODES.contains(&status.as_u16()) -// } +fn is_status_retryable(status: i32) -> bool { + RETRYABLE_ERROR_CODES.contains(&(status as u16)) +} pub trait Sleeper: 'static { type Sleep: std::future::Future; @@ -538,4 +488,4 @@ impl Sleeper for DefaultSleeper { fn sleep(dur: std::time::Duration) -> Self::Sleep { tokio::time::sleep(dur) } -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index bf4df57..88c327d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -200,15 +200,11 @@ pub enum Error { /// Error during `minreq` HTTP request #[cfg(feature = "blocking")] Minreq(::minreq::Error), - /// Error during reqwest HTTP request - //-----------------------------------------------changed------------------------------ - // #[cfg(feature = "async")] - // Reqwest(::reqwest::Error), + /// Error during async_minreq HTTP request #[cfg(feature = "async")] AsyncMinreq(async_minreq::Error), + /// JSON Error Json(serde_json::Error), - - /// HTTP response error HttpResponse { status: u16, message: String }, /// Invalid number returned @@ -253,26 +249,12 @@ macro_rules! impl_error { } }; } - impl std::error::Error for Error {} #[cfg(feature = "blocking")] impl_error!(::minreq::Error, Minreq, Error); - -//---------------------------------------------changed------------------------------ #[cfg(feature = "async")] -// impl_error!(::reqwest::Error, Reqwest, Error); -impl std::convert::From for Error { - fn from(err: async_minreq::Error) -> Self { - Error::AsyncMinreq(err) - } -} - -impl std::convert::From for Error { - fn from(err: serde_json::Error) -> Self { - Error::Json(err) - } -} -// impl_error!(::reqwest::Error, Reqwest, Error); +impl_error!(::async_minreq::Error, AsyncMinreq, Error); +impl_error!(::serde_json::Error, Json, Error); impl_error!(std::num::ParseIntError, Parsing, Error); impl_error!(bitcoin::consensus::encode::Error, BitcoinEncoding, Error); impl_error!(bitcoin::hex::HexToArrayError, HexToArray, Error); @@ -1105,4 +1087,4 @@ mod test { assert_eq!(address_txs_blocking, address_txs_async); assert_eq!(address_txs_async[0].txid, txid); } -} +} \ No newline at end of file From 82070eaba2101d1243008ca3458b658b25904fe8 Mon Sep 17 00:00:00 2001 From: psg-19 Date: Tue, 3 Jun 2025 15:21:10 +0530 Subject: [PATCH 04/18] removed unwanted comments. --- Cargo.toml | 2 +- src/async.rs | 21 +-------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 43981bc..db44c7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ blocking-https-native = ["blocking", "minreq/https-native"] blocking-https-bundled = ["blocking", "minreq/https-bundled"] tokio = ["dep:tokio"] -async = [ "tokio?/time"] +async = ["tokio?/time"] async-https = ["async"] async-https-native = ["async"] async-https-rustls = ["async"] diff --git a/src/async.rs b/src/async.rs index 237e607..ef852e0 100644 --- a/src/async.rs +++ b/src/async.rs @@ -25,27 +25,13 @@ use bitcoin::{ #[allow(unused_imports)] use log::{debug, error, info, trace}; -// use reqwest::{header, Client, Response}; -use async_minreq::{Method, Request}; //-----------------------added------------------- +use async_minreq::{Method, Request}; use crate::api::AddressStats; use crate::{ BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES, }; -// #[derive(Debug, Clone)] -// pub struct AsyncClient { -// /// The URL of the Esplora Server. -// url: String, -// /// The inner [`reqwest::Client`] to make HTTP requests. -// client: Client, -// /// Number of times to retry a request -// max_retries: usize, - -// /// Marker for the type of sleeper used -// marker: PhantomData, -// } - #[derive(Debug, Clone)] pub struct AsyncClient { /// The base URL of the Esplora server. @@ -439,11 +425,6 @@ impl AsyncClient { &self.url } - /// Get the underlying [`Client`]. - // pub fn client(&self) -> &Client { - // &self.client - // } - /// Sends a GET request to the given `url`, retrying failed attempts /// for retryable error codes until max retries hit. async fn get_with_retry(&self, url: &str) -> Result { From 37f626359b6ddd999ab2b300046b4cfc3adb1b1d Mon Sep 17 00:00:00 2001 From: psg-19 Date: Thu, 5 Jun 2025 13:59:49 +0530 Subject: [PATCH 05/18] fix: removed all .unwrap() --- src/async.rs | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/async.rs b/src/async.rs index ef852e0..d086660 100644 --- a/src/async.rs +++ b/src/async.rs @@ -77,13 +77,18 @@ impl AsyncClient { async fn get_response(&self, path: &str) -> Result { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - +// let x=response.as_str().map(|s| s.to_owned()).map_err(Error::InvalidResponse).unwrap_or_else(|s| s.to_stirng()); + if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message: response.as_str().unwrap().to_string(), + message:match response.as_str(){ + Ok(resp)=> resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + } }); } + // String::try_from(value) Ok(deserialize::(&response.as_bytes())?) } @@ -120,10 +125,16 @@ impl AsyncClient { if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message: response.as_str().unwrap().to_string(), + message: match response.as_str(){ + Ok(resp)=> resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }, }); } - serde_json::from_str(&response.as_str().unwrap().to_string()).map_err(Error::Json) + serde_json::from_str(match response.as_str(){ + Ok(resp)=> resp, + Err(_) => return Err(Error::InvalidResponse), + }).map_err(Error::Json) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -161,10 +172,16 @@ impl AsyncClient { if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message:response.as_str().unwrap().to_string(), + message:match response.as_str(){ + Ok(resp)=> resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + } }); } - let hex_str =response.as_str().unwrap().to_string(); + let hex_str =match response.as_str(){ + Ok(resp)=> resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }; Ok(deserialize(&Vec::from_hex(&hex_str)?)?) } @@ -197,10 +214,16 @@ impl AsyncClient { if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message:response.as_str().unwrap().to_string(), + message:match response.as_str(){ + Ok(resp)=> resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + } }); } - Ok(response.as_str().unwrap().to_string()) + Ok(match response.as_str(){ + Ok(resp)=> resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -240,7 +263,10 @@ impl AsyncClient { if response.status_code>299{ return Err(Error::HttpResponse { status: response.status_code as u16, - message: response.as_str().unwrap().to_string(), + message: match response.as_str(){ + Ok(resp)=> resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + } }); } Ok(()) From 60dcc98b0fa75bd9e4ec0b972efe85ad9a3ec5fc Mon Sep 17 00:00:00 2001 From: psg-19 Date: Thu, 5 Jun 2025 22:55:52 +0530 Subject: [PATCH 06/18] removed code added for debugging. --- src/async.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/async.rs b/src/async.rs index d086660..346dbcd 100644 --- a/src/async.rs +++ b/src/async.rs @@ -34,7 +34,7 @@ use crate::{ #[derive(Debug, Clone)] pub struct AsyncClient { - /// The base URL of the Esplora server. + /// The URL of the Esplora Server. url: String, /// Number of times to retry a request. max_retries: usize, @@ -77,8 +77,7 @@ impl AsyncClient { async fn get_response(&self, path: &str) -> Result { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; -// let x=response.as_str().map(|s| s.to_owned()).map_err(Error::InvalidResponse).unwrap_or_else(|s| s.to_stirng()); - + if response.status_code>299 { return Err(Error::HttpResponse { status: response.status_code as u16, @@ -88,7 +87,7 @@ impl AsyncClient { } }); } - // String::try_from(value) + Ok(deserialize::(&response.as_bytes())?) } @@ -459,7 +458,6 @@ impl AsyncClient { loop { let mut request = Request::new(Method::Get, url); - // Applying headers from the builder. for (key, value) in &self.headers { request = request.with_header(key, value); } From ee96f7abf45ab2676b4c72c940cf41a5a036b9d1 Mon Sep 17 00:00:00 2001 From: psg-19 Date: Thu, 5 Jun 2025 23:45:37 +0530 Subject: [PATCH 07/18] fix: formatting issue fixed. --- src/async.rs | 100 +++++++++++++++++++++++++-------------------------- src/lib.rs | 4 +-- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/async.rs b/src/async.rs index 346dbcd..75e1b24 100644 --- a/src/async.rs +++ b/src/async.rs @@ -11,9 +11,6 @@ //! Esplora by way of `reqwest` HTTP client. -use std::collections::HashMap; -use std::marker::PhantomData; -use std::str::FromStr; use bitcoin::consensus::{deserialize, serialize, Decodable, Encodable}; use bitcoin::hashes::{sha256, Hash}; use bitcoin::hex::{DisplayHex, FromHex}; @@ -21,16 +18,18 @@ use bitcoin::Address; use bitcoin::{ block::Header as BlockHeader, Block, BlockHash, MerkleBlock, Script, Transaction, Txid, }; +use std::collections::HashMap; +use std::marker::PhantomData; +use std::str::FromStr; -#[allow(unused_imports)] -use log::{debug, error, info, trace}; - -use async_minreq::{Method, Request}; use crate::api::AddressStats; use crate::{ BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus, BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES, }; +use async_minreq::{Method, Request}; +#[allow(unused_imports)] +use log::{debug, error, info, trace}; #[derive(Debug, Clone)] pub struct AsyncClient { @@ -47,7 +46,7 @@ pub struct AsyncClient { impl AsyncClient { /// Build an async client from a builder pub fn from_builder(builder: Builder) -> Result { - Ok(AsyncClient { + Ok(AsyncClient { url: builder.base_url, max_retries: builder.max_retries, headers: builder.headers, @@ -55,7 +54,7 @@ impl AsyncClient { }) } - pub fn from_client(url: String, headers: HashMap,) -> Self { + pub fn from_client(url: String, headers: HashMap) -> Self { AsyncClient { url, headers, @@ -78,17 +77,17 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if response.status_code>299 { + if response.status_code > 299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message:match response.as_str(){ - Ok(resp)=> resp.to_string(), - Err(_) => return Err(Error::InvalidResponse), - } + message: match response.as_str() { + Ok(resp) => resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }, }); } - Ok(deserialize::(&response.as_bytes())?) + Ok(deserialize::(response.as_bytes())?) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -121,19 +120,20 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if response.status_code>299 { + if response.status_code > 299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message: match response.as_str(){ - Ok(resp)=> resp.to_string(), - Err(_) => return Err(Error::InvalidResponse), - }, + message: match response.as_str() { + Ok(resp) => resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }, }); } - serde_json::from_str(match response.as_str(){ - Ok(resp)=> resp, - Err(_) => return Err(Error::InvalidResponse), - }).map_err(Error::Json) + serde_json::from_str(match response.as_str() { + Ok(resp) => resp, + Err(_) => return Err(Error::InvalidResponse), + }) + .map_err(Error::Json) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -168,19 +168,19 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if response.status_code>299 { + if response.status_code > 299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message:match response.as_str(){ - Ok(resp)=> resp.to_string(), - Err(_) => return Err(Error::InvalidResponse), - } + message: match response.as_str() { + Ok(resp) => resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }, }); } - let hex_str =match response.as_str(){ - Ok(resp)=> resp.to_string(), - Err(_) => return Err(Error::InvalidResponse), - }; + let hex_str = match response.as_str() { + Ok(resp) => resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }; Ok(deserialize(&Vec::from_hex(&hex_str)?)?) } @@ -210,19 +210,19 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if response.status_code>299 { + if response.status_code > 299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message:match response.as_str(){ - Ok(resp)=> resp.to_string(), - Err(_) => return Err(Error::InvalidResponse), - } + message: match response.as_str() { + Ok(resp) => resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }, }); } - Ok(match response.as_str(){ - Ok(resp)=> resp.to_string(), - Err(_) => return Err(Error::InvalidResponse), - }) + Ok(match response.as_str() { + Ok(resp) => resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -257,15 +257,15 @@ impl AsyncClient { for (key, value) in &self.headers { request = request.with_header(key, value); } - + let response = request.send().await.map_err(Error::AsyncMinreq)?; - if response.status_code>299{ + if response.status_code > 299 { return Err(Error::HttpResponse { status: response.status_code as u16, - message: match response.as_str(){ - Ok(resp)=> resp.to_string(), - Err(_) => return Err(Error::InvalidResponse), - } + message: match response.as_str() { + Ok(resp) => resp.to_string(), + Err(_) => return Err(Error::InvalidResponse), + }, }); } Ok(()) @@ -457,7 +457,7 @@ impl AsyncClient { let mut attempts = 0; loop { - let mut request = Request::new(Method::Get, url); + let mut request = Request::new(Method::Get, url); for (key, value) in &self.headers { request = request.with_header(key, value); } @@ -493,4 +493,4 @@ impl Sleeper for DefaultSleeper { fn sleep(dur: std::time::Duration) -> Self::Sleep { tokio::time::sleep(dur) } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 88c327d..02aa50e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,7 +201,7 @@ pub enum Error { #[cfg(feature = "blocking")] Minreq(::minreq::Error), /// Error during async_minreq HTTP request - #[cfg(feature = "async")] + #[cfg(feature = "async")] AsyncMinreq(async_minreq::Error), /// JSON Error Json(serde_json::Error), @@ -1087,4 +1087,4 @@ mod test { assert_eq!(address_txs_blocking, address_txs_async); assert_eq!(address_txs_async[0].txid, txid); } -} \ No newline at end of file +} From 2df003b3115c7e640c5c2b68fc121c2c5f06d86f Mon Sep 17 00:00:00 2001 From: psg-19 Date: Fri, 6 Jun 2025 19:12:34 +0530 Subject: [PATCH 08/18] removed reqwest from workflows. --- .github/workflows/cont_integration.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index 77d9454..dd266ab 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -54,7 +54,6 @@ jobs: - name: Pin dependencies for MSRV if: matrix.rust.version == '1.63.0' run: | - cargo update -p reqwest --precise "0.12.4" cargo update -p minreq --precise "2.13.2" cargo update -p zstd-sys --precise "2.0.8+zstd.1.5.5" cargo update -p time --precise "0.3.20" From fda978f5708bbf1eb469017fcebfde78a809f4dd Mon Sep 17 00:00:00 2001 From: psg-19 Date: Fri, 6 Jun 2025 19:31:03 +0530 Subject: [PATCH 09/18] removed url crate from ci, since it acted as dependency for reqwest. --- .github/workflows/cont_integration.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index dd266ab..4aa1dfa 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -58,7 +58,6 @@ jobs: cargo update -p zstd-sys --precise "2.0.8+zstd.1.5.5" cargo update -p time --precise "0.3.20" cargo update -p home --precise "0.5.5" - cargo update -p url --precise "2.5.0" cargo update -p tokio --precise "1.38.1" cargo update -p security-framework-sys --precise "2.11.1" cargo update -p native-tls --precise "0.2.13" From 345fc9a7b274ab89ae58093a02d4fcc1ba6cb75c Mon Sep 17 00:00:00 2001 From: psg-19 Date: Sun, 8 Jun 2025 12:21:11 +0530 Subject: [PATCH 10/18] Testing CI --- .github/workflows/cont_integration.yml | 5 ++--- Cargo.toml | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index 4aa1dfa..bf0d44c 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -17,7 +17,7 @@ jobs: matrix: rust: - version: stable # STABLE - - version: 1.63.0 # MSRV + - version: 1.71.0 # MSRV features: - default - blocking @@ -52,13 +52,12 @@ jobs: - name: Update toolchain run: rustup update - name: Pin dependencies for MSRV - if: matrix.rust.version == '1.63.0' + if: matrix.rust.version == '1.71.0' run: | cargo update -p minreq --precise "2.13.2" cargo update -p zstd-sys --precise "2.0.8+zstd.1.5.5" cargo update -p time --precise "0.3.20" cargo update -p home --precise "0.5.5" - cargo update -p tokio --precise "1.38.1" cargo update -p security-framework-sys --precise "2.11.1" cargo update -p native-tls --precise "0.2.13" cargo update -p ring --precise "0.17.12" diff --git a/Cargo.toml b/Cargo.toml index db44c7f..33c6ea2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ bitcoin = { version = "0.32", features = ["serde", "std"], default-features = fa hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } -async_minreq = { git = "https://github.com/BEULAHEVANJALIN/async-minreq.git" } +async_minreq = { git = "https://github.com/psg-19/async-minreq.git", default-features = false, optional = true } serde_json = "1.0.140" # default async runtime @@ -43,8 +43,8 @@ blocking-https-native = ["blocking", "minreq/https-native"] blocking-https-bundled = ["blocking", "minreq/https-bundled"] tokio = ["dep:tokio"] -async = ["tokio?/time"] +async = ["async_minreq", "tokio?/time"] async-https = ["async"] -async-https-native = ["async"] -async-https-rustls = ["async"] +async-https-native = ["async", "async_minreq/native-tls"] +async-https-rustls = ["async", "async_minreq/rustls"] async-https-rustls-manual-roots = ["async"] \ No newline at end of file From dc22fce733b4f3c76f9ec3b6b93cbe02f586a7c4 Mon Sep 17 00:00:00 2001 From: psg-19 Date: Sun, 8 Jun 2025 12:38:21 +0530 Subject: [PATCH 11/18] Testing without native-tls and rustls features on MSRV 1.71. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 33c6ea2..de6269d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,6 @@ blocking-https-bundled = ["blocking", "minreq/https-bundled"] tokio = ["dep:tokio"] async = ["async_minreq", "tokio?/time"] async-https = ["async"] -async-https-native = ["async", "async_minreq/native-tls"] -async-https-rustls = ["async", "async_minreq/rustls"] +async-https-native = ["async"] +async-https-rustls = ["async"] async-https-rustls-manual-roots = ["async"] \ No newline at end of file From 43a8603522aa1f0363fc54767d7578ab390cda4d Mon Sep 17 00:00:00 2001 From: psg-19 Date: Sun, 8 Jun 2025 20:17:04 +0530 Subject: [PATCH 12/18] fix: MSRV to 1.71 --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index de6269d..e6b7026 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://docs.rs/esplora-client/" description = "Bitcoin Esplora API client library. Supports plaintext, TLS and Onion servers. Blocking or async" keywords = ["bitcoin", "esplora"] readme = "README.md" -rust-version = "1.63.0" +rust-version = "1.70.0" [lib] name = "esplora_client" @@ -23,7 +23,7 @@ hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } async_minreq = { git = "https://github.com/psg-19/async-minreq.git", default-features = false, optional = true } -serde_json = "1.0.140" +serde_json = "1.0.100" # default async runtime tokio = { version = "1", features = ["time"], optional = true } @@ -43,7 +43,7 @@ blocking-https-native = ["blocking", "minreq/https-native"] blocking-https-bundled = ["blocking", "minreq/https-bundled"] tokio = ["dep:tokio"] -async = ["async_minreq", "tokio?/time"] +async = ["async_minreq","tokio?/time"] async-https = ["async"] async-https-native = ["async"] async-https-rustls = ["async"] From 159a5225f15440573fddcbec4c50fb5806c7d34c Mon Sep 17 00:00:00 2001 From: psg-19 Date: Sat, 14 Jun 2025 17:48:26 +0530 Subject: [PATCH 13/18] fix: added async-https-native and async-https-rustls. --- .clippy.toml | 2 +- Cargo.toml | 13 ++++++------- src/async.rs | 24 ++++++++++-------------- src/lib.rs | 6 +++--- 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/.clippy.toml b/.clippy.toml index 69478ce..e0ec8dd 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv="1.63.0" +msrv="1.71.0" diff --git a/Cargo.toml b/Cargo.toml index e6b7026..007c889 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://docs.rs/esplora-client/" description = "Bitcoin Esplora API client library. Supports plaintext, TLS and Onion servers. Blocking or async" keywords = ["bitcoin", "esplora"] readme = "README.md" -rust-version = "1.70.0" +rust-version = "1.71.0" [lib] name = "esplora_client" @@ -22,8 +22,7 @@ bitcoin = { version = "0.32", features = ["serde", "std"], default-features = fa hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } -async_minreq = { git = "https://github.com/psg-19/async-minreq.git", default-features = false, optional = true } -serde_json = "1.0.100" +async_minreq = { git = "https://github.com/psg-19/async-minreq.git", default-features = false, features = [], optional = true } # default async runtime tokio = { version = "1", features = ["time"], optional = true } @@ -43,8 +42,8 @@ blocking-https-native = ["blocking", "minreq/https-native"] blocking-https-bundled = ["blocking", "minreq/https-bundled"] tokio = ["dep:tokio"] -async = ["async_minreq","tokio?/time"] +async = ["async_minreq", "async_minreq/json-using-serde", "tokio?/time"] async-https = ["async"] -async-https-native = ["async"] -async-https-rustls = ["async"] -async-https-rustls-manual-roots = ["async"] \ No newline at end of file +async-https-native = ["async", "async_minreq/https-rustls-probe", "async_minreq/webpki-roots", "async_minreq/json-using-serde", "async_minreq/https-native"] +async-https-rustls = ["async", "async_minreq/json-using-serde", "async_minreq/https-rustls-probe", "async_minreq/https-rustls"] +async-https-rustls-manual-roots = ["async"] diff --git a/src/async.rs b/src/async.rs index 133ad88..19f2eb8 100644 --- a/src/async.rs +++ b/src/async.rs @@ -25,9 +25,9 @@ use std::str::FromStr; use crate::api::AddressStats; use crate::{ BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus, - BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES, + BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES, VALID_HTTP_CODE }; -use async_minreq::{Method, Request}; +use async_minreq::{Method, Request, Response}; #[allow(unused_imports)] use log::{debug, error, info, trace}; @@ -77,7 +77,7 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if response.status_code > 299 { + if response.status_code > VALID_HTTP_CODE { return Err(Error::HttpResponse { status: response.status_code as u16, message: match response.as_str() { @@ -120,7 +120,7 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if response.status_code > 299 { + if response.status_code > VALID_HTTP_CODE { return Err(Error::HttpResponse { status: response.status_code as u16, message: match response.as_str() { @@ -129,11 +129,7 @@ impl AsyncClient { }, }); } - serde_json::from_str(match response.as_str() { - Ok(resp) => resp, - Err(_) => return Err(Error::InvalidResponse), - }) - .map_err(Error::Json) + response.json().map_err(Error::AsyncMinreq) } /// Make an HTTP GET request to given URL, deserializing to `Option`. @@ -168,7 +164,7 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if response.status_code > 299 { + if response.status_code > VALID_HTTP_CODE { return Err(Error::HttpResponse { status: response.status_code as u16, message: match response.as_str() { @@ -210,7 +206,7 @@ impl AsyncClient { let url = format!("{}{}", self.url, path); let response = self.get_with_retry(&url).await?; - if response.status_code > 299 { + if response.status_code > VALID_HTTP_CODE { return Err(Error::HttpResponse { status: response.status_code as u16, message: match response.as_str() { @@ -259,7 +255,7 @@ impl AsyncClient { } let response = request.send().await.map_err(Error::AsyncMinreq)?; - if response.status_code > 299 { + if response.status_code > VALID_HTTP_CODE { return Err(Error::HttpResponse { status: response.status_code as u16, message: match response.as_str() { @@ -280,7 +276,7 @@ impl AsyncClient { pub async fn get_tx_no_opt(&self, txid: &Txid) -> Result { match self.get_tx(txid).await { Ok(Some(tx)) => Ok(tx), - Ok(None) => Err(Error::TransactionNotFound(*txid)), //look into + Ok(None) => Err(Error::TransactionNotFound(*txid)), Err(e) => Err(e), } } @@ -452,7 +448,7 @@ impl AsyncClient { /// Sends a GET request to the given `url`, retrying failed attempts /// for retryable error codes until max retries hit. - async fn get_with_retry(&self, url: &str) -> Result { + async fn get_with_retry(&self, url: &str) -> Result { let mut delay = BASE_BACKOFF_MILLIS; let mut attempts = 0; diff --git a/src/lib.rs b/src/lib.rs index 4803629..d6103b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,6 +102,9 @@ const BASE_BACKOFF_MILLIS: Duration = Duration::from_millis(256); /// Default max retries. const DEFAULT_MAX_RETRIES: usize = 6; +/// Valid HTTP code +const VALID_HTTP_CODE: i32 = 299; + /// Get a fee value in sats/vbytes from the estimates /// that matches the confirmation target set as parameter. /// @@ -206,8 +209,6 @@ pub enum Error { /// Error during async_minreq HTTP request #[cfg(feature = "async")] AsyncMinreq(async_minreq::Error), - /// JSON Error - Json(serde_json::Error), /// HTTP response error HttpResponse { status: u16, message: String }, /// Invalid number returned @@ -257,7 +258,6 @@ impl std::error::Error for Error {} impl_error!(::minreq::Error, Minreq, Error); #[cfg(feature = "async")] impl_error!(::async_minreq::Error, AsyncMinreq, Error); -impl_error!(::serde_json::Error, Json, Error); impl_error!(std::num::ParseIntError, Parsing, Error); impl_error!(bitcoin::consensus::encode::Error, BitcoinEncoding, Error); impl_error!(bitcoin::hex::HexToArrayError, HexToArray, Error); From e87541caa3ee999a7f1d029be187f5ee5994cb9c Mon Sep 17 00:00:00 2001 From: psg-19 Date: Wed, 18 Jun 2025 17:31:29 +0530 Subject: [PATCH 14/18] added features. --- .github/workflows/cont_integration.yml | 2 +- Cargo.toml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index 7c5abf0..ede35b6 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -58,7 +58,7 @@ jobs: cargo update -p zstd-sys --precise "2.0.8+zstd.1.5.5" cargo update -p time --precise "0.3.20" cargo update -p home --precise "0.5.5" - cargo update -p security-framework-sys --precise "2.11.1" + cargo update -p security-framework-sys --precise "2.14.0" cargo update -p native-tls --precise "0.2.13" cargo update -p ring --precise "0.17.12" cargo update -p flate2 --precise "1.0.35" diff --git a/Cargo.toml b/Cargo.toml index 007c889..ee7c51e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ bitcoin = { version = "0.32", features = ["serde", "std"], default-features = fa hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } -async_minreq = { git = "https://github.com/psg-19/async-minreq.git", default-features = false, features = [], optional = true } +async_minreq = { git = "https://github.com/psg-19/async-minreq", default-features = false, features = ["json-using-serde"], optional = true } # default async runtime tokio = { version = "1", features = ["time"], optional = true } @@ -42,8 +42,8 @@ blocking-https-native = ["blocking", "minreq/https-native"] blocking-https-bundled = ["blocking", "minreq/https-bundled"] tokio = ["dep:tokio"] -async = ["async_minreq", "async_minreq/json-using-serde", "tokio?/time"] -async-https = ["async"] -async-https-native = ["async", "async_minreq/https-rustls-probe", "async_minreq/webpki-roots", "async_minreq/json-using-serde", "async_minreq/https-native"] -async-https-rustls = ["async", "async_minreq/json-using-serde", "async_minreq/https-rustls-probe", "async_minreq/https-rustls"] +async = ["async_minreq", "tokio?/time"] +async-https = ["async", "async_minreq/https"] +async-https-native = ["async", "async_minreq/https-native"] +async-https-rustls = ["async", "async_minreq/https-rustls"] async-https-rustls-manual-roots = ["async"] From dff596965da1f74a45fdebf65d2b8864cf2c39fc Mon Sep 17 00:00:00 2001 From: psg-19 Date: Wed, 9 Jul 2025 13:48:47 +0530 Subject: [PATCH 15/18] added all async-minreq features and docs update --- Cargo.toml | 4 ++-- src/async.rs | 4 ++-- src/lib.rs | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ee7c51e..ab2d390 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ bitcoin = { version = "0.32", features = ["serde", "std"], default-features = fa hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } -async_minreq = { git = "https://github.com/psg-19/async-minreq", default-features = false, features = ["json-using-serde"], optional = true } +async_minreq = { path = "../../test_fix_am/async-minreq", default-features = false, features = ["json-using-serde"], optional = true } # default async runtime tokio = { version = "1", features = ["time"], optional = true } @@ -42,7 +42,7 @@ blocking-https-native = ["blocking", "minreq/https-native"] blocking-https-bundled = ["blocking", "minreq/https-bundled"] tokio = ["dep:tokio"] -async = ["async_minreq", "tokio?/time"] +async = ["async_minreq", "async_minreq/proxy", "tokio?/time"] async-https = ["async", "async_minreq/https"] async-https-native = ["async", "async_minreq/https-native"] async-https-rustls = ["async", "async_minreq/https-rustls"] diff --git a/src/async.rs b/src/async.rs index 19f2eb8..662ed04 100644 --- a/src/async.rs +++ b/src/async.rs @@ -9,7 +9,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -//! Esplora by way of `reqwest` HTTP client. +//! Esplora by way of `asyn_minreq` HTTP client. use bitcoin::consensus::{deserialize, serialize, Decodable, Encodable}; use bitcoin::hashes::{sha256, Hash}; @@ -25,7 +25,7 @@ use std::str::FromStr; use crate::api::AddressStats; use crate::{ BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus, - BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES, VALID_HTTP_CODE + BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES, VALID_HTTP_CODE, }; use async_minreq::{Method, Request, Response}; #[allow(unused_imports)] diff --git a/src/lib.rs b/src/lib.rs index d6103b0..c9d2934 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ //! async Esplora client to query Esplora's backend. //! //! The library provides the possibility to build a blocking -//! client using [`minreq`] and an async client using [`reqwest`]. +//! client using [`minreq`] and an async client using [`async_minreq`]. //! The library supports communicating to Esplora via a proxy //! and also using TLS (SSL) for secure communication. //! @@ -53,14 +53,14 @@ //! capabilities using the platform's native TLS backend (likely OpenSSL). //! * `blocking-https-bundled` enables [`minreq`], the blocking client with proxy and TLS (SSL) //! capabilities using a bundled OpenSSL library backend. -//! * `async` enables [`reqwest`], the async client with proxy capabilities. -//! * `async-https` enables [`reqwest`], the async client with support for proxying and TLS (SSL) -//! using the default [`reqwest`] TLS backend. -//! * `async-https-native` enables [`reqwest`], the async client with support for proxying and TLS +//! * `async` enables [`async_minreq`], the async client with proxy capabilities. +//! * `async-https` enables [`async_minreq`], the async client with support for proxying and TLS (SSL) +//! using the default [`async_minreq`] TLS backend. +//! * `async-https-native` enables [`async_minreq`], the async client with support for proxying and TLS //! (SSL) using the platform's native TLS backend (likely OpenSSL). -//! * `async-https-rustls` enables [`reqwest`], the async client with support for proxying and TLS +//! * `async-https-rustls` enables [`async_minreq`], the async client with support for proxying and TLS //! (SSL) using the `rustls` TLS backend. -//! * `async-https-rustls-manual-roots` enables [`reqwest`], the async client with support for +//! * `async-https-rustls-manual-roots` enables [`async_minreq`], the async client with support for //! proxying and TLS (SSL) using the `rustls` TLS backend without using its the default root //! certificates. //! From 86f59c519f54548d686595dd6a8cedb33abf08c8 Mon Sep 17 00:00:00 2001 From: psg-19 Date: Wed, 9 Jul 2025 13:50:56 +0530 Subject: [PATCH 16/18] fix: fixed the async-minreq crate link --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ab2d390..c221561 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ bitcoin = { version = "0.32", features = ["serde", "std"], default-features = fa hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } -async_minreq = { path = "../../test_fix_am/async-minreq", default-features = false, features = ["json-using-serde"], optional = true } +async_minreq = { path = "https://github.com/BEULAHEVANJALIN/async-minreq", default-features = false, features = ["json-using-serde"], optional = true } # default async runtime tokio = { version = "1", features = ["time"], optional = true } From 5ba3dc906939989b8c4fc0f931d82ea24df1c280 Mon Sep 17 00:00:00 2001 From: psg-19 Date: Wed, 9 Jul 2025 14:05:18 +0530 Subject: [PATCH 17/18] fixed github path --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c221561..1b6a47e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ bitcoin = { version = "0.32", features = ["serde", "std"], default-features = fa hex = { version = "0.2", package = "hex-conservative" } log = "^0.4" minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true } -async_minreq = { path = "https://github.com/BEULAHEVANJALIN/async-minreq", default-features = false, features = ["json-using-serde"], optional = true } +async_minreq = { git = "https://github.com/BEULAHEVANJALIN/async-minreq", default-features = false, features = ["json-using-serde"], optional = true } # default async runtime tokio = { version = "1", features = ["time"], optional = true } From aaf4d9ca99f533950e5c8f8c629b2da0f76510e2 Mon Sep 17 00:00:00 2001 From: psg-19 Date: Thu, 10 Jul 2025 12:46:11 +0530 Subject: [PATCH 18/18] chore: run cargo fmt --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c9d2934..66aa522 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,12 +54,12 @@ //! * `blocking-https-bundled` enables [`minreq`], the blocking client with proxy and TLS (SSL) //! capabilities using a bundled OpenSSL library backend. //! * `async` enables [`async_minreq`], the async client with proxy capabilities. -//! * `async-https` enables [`async_minreq`], the async client with support for proxying and TLS (SSL) -//! using the default [`async_minreq`] TLS backend. -//! * `async-https-native` enables [`async_minreq`], the async client with support for proxying and TLS -//! (SSL) using the platform's native TLS backend (likely OpenSSL). -//! * `async-https-rustls` enables [`async_minreq`], the async client with support for proxying and TLS -//! (SSL) using the `rustls` TLS backend. +//! * `async-https` enables [`async_minreq`], the async client with support for proxying and TLS +//! (SSL) using the default [`async_minreq`] TLS backend. +//! * `async-https-native` enables [`async_minreq`], the async client with support for proxying and +//! TLS (SSL) using the platform's native TLS backend (likely OpenSSL). +//! * `async-https-rustls` enables [`async_minreq`], the async client with support for proxying and +//! TLS (SSL) using the `rustls` TLS backend. //! * `async-https-rustls-manual-roots` enables [`async_minreq`], the async client with support for //! proxying and TLS (SSL) using the `rustls` TLS backend without using its the default root //! certificates.