diff --git a/CHANGELOG.md b/CHANGELOG.md index 90805b0c..f179e654 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [v0.11.0] - [v0.10.0] - Added `flush` method to the `Database` trait to explicitly flush to disk latest changes on the db. +- Add support for proxies in `EsploraBlockchain` ## [v0.10.0] - [v0.9.0] diff --git a/Cargo.toml b/Cargo.toml index e4d7c8c5..efc402e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,8 +77,8 @@ rpc = ["core-rpc"] async-interface = ["async-trait"] electrum = ["electrum-client"] # MUST ALSO USE `--no-default-features`. -use-esplora-reqwest = ["esplora", "reqwest", "futures"] -use-esplora-ureq = ["esplora", "ureq"] +use-esplora-reqwest = ["esplora", "reqwest", "reqwest/socks", "futures"] +use-esplora-ureq = ["esplora", "ureq", "ureq/socks"] # Typical configurations will not need to use `esplora` feature directly. esplora = [] diff --git a/src/blockchain/esplora/reqwest.rs b/src/blockchain/esplora/reqwest.rs index 528fb7ad..6e9c7aad 100644 --- a/src/blockchain/esplora/reqwest.rs +++ b/src/blockchain/esplora/reqwest.rs @@ -333,6 +333,17 @@ pub struct EsploraBlockchainConfig { /// /// eg. `https://blockstream.info/api/` pub base_url: String, + /// Optional URL of the proxy to use to make requests to the Esplora server + /// + /// The string should be formatted as: `://:@host:`. + /// + /// Note that the format of this value and the supported protocols change slightly between the + /// sync version of esplora (using `ureq`) and the async version (using `reqwest`). For more + /// details check with the documentation of the two crates. Both of them are compiled with + /// the `socks` feature enabled. + /// + /// The proxy is ignored when targeting `wasm32`. + pub proxy: Option, /// Number of parallel requests sent to the esplora service (default: 4) pub concurrency: Option, /// Stop searching addresses for transactions after finding an unused gap of this length. @@ -343,10 +354,19 @@ impl ConfigurableBlockchain for EsploraBlockchain { type Config = EsploraBlockchainConfig; fn from_config(config: &Self::Config) -> Result { + let map_e = |e: reqwest::Error| Error::Esplora(Box::new(e.into())); + let mut blockchain = EsploraBlockchain::new(config.base_url.as_str(), config.stop_gap); if let Some(concurrency) = config.concurrency { blockchain.url_client.concurrency = concurrency; - }; + } + #[cfg(not(target_arch = "wasm32"))] + if let Some(proxy) = &config.proxy { + blockchain.url_client.client = Client::builder() + .proxy(reqwest::Proxy::all(proxy).map_err(map_e)?) + .build() + .map_err(map_e)?; + } Ok(blockchain) } } diff --git a/src/blockchain/esplora/ureq.rs b/src/blockchain/esplora/ureq.rs index 24a37e86..177b773d 100644 --- a/src/blockchain/esplora/ureq.rs +++ b/src/blockchain/esplora/ureq.rs @@ -19,7 +19,7 @@ use std::time::Duration; #[allow(unused_imports)] use log::{debug, error, info, trace}; -use ureq::{Agent, Response}; +use ureq::{Agent, Proxy, Response}; use bitcoin::consensus::{deserialize, serialize}; use bitcoin::hashes::hex::{FromHex, ToHex}; @@ -59,7 +59,7 @@ impl std::convert::From for EsploraBlockchain { } impl EsploraBlockchain { - /// Create a new instance of the client from a base URL and `stop_gap`. + /// Create a new instance of the client from a base URL and the `stop_gap`. pub fn new(base_url: &str, stop_gap: usize) -> Self { EsploraBlockchain { url_client: UrlClient { @@ -358,6 +358,17 @@ impl ElectrumLikeSync for UrlClient { pub struct EsploraBlockchainConfig { /// Base URL of the esplora service eg. `https://blockstream.info/api/` pub base_url: String, + /// Optional URL of the proxy to use to make requests to the Esplora server + /// + /// The string should be formatted as: `://:@host:`. + /// + /// Note that the format of this value and the supported protocols change slightly between the + /// sync version of esplora (using `ureq`) and the async version (using `reqwest`). For more + /// details check with the documentation of the two crates. Both of them are compiled with + /// the `socks` feature enabled. + /// + /// The proxy is ignored when targeting `wasm32`. + pub proxy: Option, /// Socket read timeout. pub timeout_read: u64, /// Socket write timeout. @@ -370,10 +381,18 @@ impl ConfigurableBlockchain for EsploraBlockchain { type Config = EsploraBlockchainConfig; fn from_config(config: &Self::Config) -> Result { - let agent: Agent = ureq::AgentBuilder::new() + let mut agent_builder = ureq::AgentBuilder::new() .timeout_read(Duration::from_secs(config.timeout_read)) - .timeout_write(Duration::from_secs(config.timeout_write)) - .build(); - Ok(EsploraBlockchain::new(config.base_url.as_str(), config.stop_gap).with_agent(agent)) + .timeout_write(Duration::from_secs(config.timeout_write)); + + if let Some(proxy) = &config.proxy { + agent_builder = agent_builder + .proxy(Proxy::new(proxy).map_err(|e| Error::Esplora(Box::new(e.into())))?); + } + + Ok( + EsploraBlockchain::new(config.base_url.as_str(), config.stop_gap) + .with_agent(agent_builder.build()), + ) } }