]> Untitled Git - bdk/commitdiff
Rename internal esplora modules, fix docs
authorAlekos Filini <alekos.filini@gmail.com>
Thu, 29 Sep 2022 09:59:21 +0000 (11:59 +0200)
committerAlekos Filini <alekos.filini@gmail.com>
Thu, 29 Sep 2022 10:00:09 +0000 (12:00 +0200)
src/blockchain/esplora/async.rs [new file with mode: 0644]
src/blockchain/esplora/blocking.rs [new file with mode: 0644]
src/blockchain/esplora/mod.rs
src/blockchain/esplora/reqwest.rs [deleted file]
src/blockchain/esplora/ureq.rs [deleted file]

diff --git a/src/blockchain/esplora/async.rs b/src/blockchain/esplora/async.rs
new file mode 100644 (file)
index 0000000..5ddbdeb
--- /dev/null
@@ -0,0 +1,249 @@
+// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Esplora by way of `reqwest` HTTP client.
+
+use std::collections::{HashMap, HashSet};
+use std::ops::Deref;
+
+use bitcoin::{Transaction, Txid};
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+use esplora_client::{convert_fee_rate, AsyncClient, Builder, Tx};
+use futures::stream::{FuturesOrdered, TryStreamExt};
+
+use crate::blockchain::*;
+use crate::database::BatchDatabase;
+use crate::error::Error;
+use crate::FeeRate;
+
+/// Structure that implements the logic to sync with Esplora
+///
+/// ## Example
+/// See the [`blockchain::esplora`](crate::blockchain::esplora) module for a usage example.
+#[derive(Debug)]
+pub struct EsploraBlockchain {
+    url_client: AsyncClient,
+    stop_gap: usize,
+    concurrency: u8,
+}
+
+impl std::convert::From<AsyncClient> for EsploraBlockchain {
+    fn from(url_client: AsyncClient) -> Self {
+        EsploraBlockchain {
+            url_client,
+            stop_gap: 20,
+            concurrency: super::DEFAULT_CONCURRENT_REQUESTS,
+        }
+    }
+}
+
+impl EsploraBlockchain {
+    /// Create a new instance of the client from a base URL and `stop_gap`.
+    pub fn new(base_url: &str, stop_gap: usize) -> Self {
+        let url_client = Builder::new(base_url)
+            .build_async()
+            .expect("Should never fail with no proxy and timeout");
+
+        Self::from_client(url_client, stop_gap)
+    }
+
+    /// Build a new instance given a client
+    pub fn from_client(url_client: AsyncClient, stop_gap: usize) -> Self {
+        EsploraBlockchain {
+            url_client,
+            stop_gap,
+            concurrency: super::DEFAULT_CONCURRENT_REQUESTS,
+        }
+    }
+
+    /// Set the concurrency to use when doing batch queries against the Esplora instance.
+    pub fn with_concurrency(mut self, concurrency: u8) -> Self {
+        self.concurrency = concurrency;
+        self
+    }
+}
+
+#[maybe_async]
+impl Blockchain for EsploraBlockchain {
+    fn get_capabilities(&self) -> HashSet<Capability> {
+        vec![
+            Capability::FullHistory,
+            Capability::GetAnyTx,
+            Capability::AccurateFees,
+        ]
+        .into_iter()
+        .collect()
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        Ok(await_or_block!(self.url_client.broadcast(tx))?)
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        let estimates = await_or_block!(self.url_client.get_fee_estimates())?;
+        Ok(FeeRate::from_sat_per_vb(convert_fee_rate(
+            target, estimates,
+        )?))
+    }
+}
+
+impl Deref for EsploraBlockchain {
+    type Target = AsyncClient;
+
+    fn deref(&self) -> &Self::Target {
+        &self.url_client
+    }
+}
+
+impl StatelessBlockchain for EsploraBlockchain {}
+
+#[maybe_async]
+impl GetHeight for EsploraBlockchain {
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(await_or_block!(self.url_client.get_height())?)
+    }
+}
+
+#[maybe_async]
+impl GetTx for EsploraBlockchain {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(await_or_block!(self.url_client.get_tx(txid))?)
+    }
+}
+
+#[maybe_async]
+impl GetBlockHash for EsploraBlockchain {
+    fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
+        let block_header = await_or_block!(self.url_client.get_header(height as u32))?;
+        Ok(block_header.block_hash())
+    }
+}
+
+#[maybe_async]
+impl WalletSync for EsploraBlockchain {
+    fn wallet_setup<D: BatchDatabase>(
+        &self,
+        database: &mut D,
+        _progress_update: Box<dyn Progress>,
+    ) -> Result<(), Error> {
+        use crate::blockchain::script_sync::Request;
+        let mut request = script_sync::start(database, self.stop_gap)?;
+        let mut tx_index: HashMap<Txid, Tx> = HashMap::new();
+
+        let batch_update = loop {
+            request = match request {
+                Request::Script(script_req) => {
+                    let futures: FuturesOrdered<_> = script_req
+                        .request()
+                        .take(self.concurrency as usize)
+                        .map(|script| async move {
+                            let mut related_txs: Vec<Tx> =
+                                self.url_client.scripthash_txs(script, None).await?;
+
+                            let n_confirmed =
+                                related_txs.iter().filter(|tx| tx.status.confirmed).count();
+                            // esplora pages on 25 confirmed transactions. If there's 25 or more we
+                            // keep requesting to see if there's more.
+                            if n_confirmed >= 25 {
+                                loop {
+                                    let new_related_txs: Vec<Tx> = self
+                                        .url_client
+                                        .scripthash_txs(
+                                            script,
+                                            Some(related_txs.last().unwrap().txid),
+                                        )
+                                        .await?;
+                                    let n = new_related_txs.len();
+                                    related_txs.extend(new_related_txs);
+                                    // we've reached the end
+                                    if n < 25 {
+                                        break;
+                                    }
+                                }
+                            }
+                            Result::<_, Error>::Ok(related_txs)
+                        })
+                        .collect();
+                    let txs_per_script: Vec<Vec<Tx>> = await_or_block!(futures.try_collect())?;
+                    let mut satisfaction = vec![];
+
+                    for txs in txs_per_script {
+                        satisfaction.push(
+                            txs.iter()
+                                .map(|tx| (tx.txid, tx.status.block_height))
+                                .collect(),
+                        );
+                        for tx in txs {
+                            tx_index.insert(tx.txid, tx);
+                        }
+                    }
+
+                    script_req.satisfy(satisfaction)?
+                }
+                Request::Conftime(conftime_req) => {
+                    let conftimes = conftime_req
+                        .request()
+                        .map(|txid| {
+                            tx_index
+                                .get(txid)
+                                .expect("must be in index")
+                                .confirmation_time()
+                                .map(Into::into)
+                        })
+                        .collect();
+                    conftime_req.satisfy(conftimes)?
+                }
+                Request::Tx(tx_req) => {
+                    let full_txs = tx_req
+                        .request()
+                        .map(|txid| {
+                            let tx = tx_index.get(txid).expect("must be in index");
+                            Ok((tx.previous_outputs(), tx.to_tx()))
+                        })
+                        .collect::<Result<_, Error>>()?;
+                    tx_req.satisfy(full_txs)?
+                }
+                Request::Finish(batch_update) => break batch_update,
+            }
+        };
+
+        database.commit_batch(batch_update)?;
+        Ok(())
+    }
+}
+
+impl ConfigurableBlockchain for EsploraBlockchain {
+    type Config = super::EsploraBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        let mut builder = Builder::new(config.base_url.as_str());
+
+        if let Some(timeout) = config.timeout {
+            builder = builder.timeout(timeout);
+        }
+
+        if let Some(proxy) = &config.proxy {
+            builder = builder.proxy(proxy);
+        }
+
+        let mut blockchain =
+            EsploraBlockchain::from_client(builder.build_async()?, config.stop_gap);
+
+        if let Some(concurrency) = config.concurrency {
+            blockchain = blockchain.with_concurrency(concurrency);
+        }
+
+        Ok(blockchain)
+    }
+}
diff --git a/src/blockchain/esplora/blocking.rs b/src/blockchain/esplora/blocking.rs
new file mode 100644 (file)
index 0000000..1e9d1cf
--- /dev/null
@@ -0,0 +1,239 @@
+// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Esplora by way of `ureq` HTTP client.
+
+use std::collections::{HashMap, HashSet};
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+use bitcoin::{Transaction, Txid};
+
+use esplora_client::{convert_fee_rate, BlockingClient, Builder, Tx};
+
+use crate::blockchain::*;
+use crate::database::BatchDatabase;
+use crate::error::Error;
+use crate::FeeRate;
+
+/// Structure that implements the logic to sync with Esplora
+///
+/// ## Example
+/// See the [`blockchain::esplora`](crate::blockchain::esplora) module for a usage example.
+#[derive(Debug)]
+pub struct EsploraBlockchain {
+    url_client: BlockingClient,
+    stop_gap: usize,
+    concurrency: u8,
+}
+
+impl EsploraBlockchain {
+    /// 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 {
+        let url_client = Builder::new(base_url)
+            .build_blocking()
+            .expect("Should never fail with no proxy and timeout");
+
+        Self::from_client(url_client, stop_gap)
+    }
+
+    /// Build a new instance given a client
+    pub fn from_client(url_client: BlockingClient, stop_gap: usize) -> Self {
+        EsploraBlockchain {
+            url_client,
+            concurrency: super::DEFAULT_CONCURRENT_REQUESTS,
+            stop_gap,
+        }
+    }
+
+    /// Set the number of parallel requests the client can make.
+    pub fn with_concurrency(mut self, concurrency: u8) -> Self {
+        self.concurrency = concurrency;
+        self
+    }
+}
+
+impl Blockchain for EsploraBlockchain {
+    fn get_capabilities(&self) -> HashSet<Capability> {
+        vec![
+            Capability::FullHistory,
+            Capability::GetAnyTx,
+            Capability::AccurateFees,
+        ]
+        .into_iter()
+        .collect()
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        self.url_client.broadcast(tx)?;
+        Ok(())
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        let estimates = self.url_client.get_fee_estimates()?;
+        Ok(FeeRate::from_sat_per_vb(convert_fee_rate(
+            target, estimates,
+        )?))
+    }
+}
+
+impl Deref for EsploraBlockchain {
+    type Target = BlockingClient;
+
+    fn deref(&self) -> &Self::Target {
+        &self.url_client
+    }
+}
+
+impl StatelessBlockchain for EsploraBlockchain {}
+
+impl GetHeight for EsploraBlockchain {
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(self.url_client.get_height()?)
+    }
+}
+
+impl GetTx for EsploraBlockchain {
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.url_client.get_tx(txid)?)
+    }
+}
+
+impl GetBlockHash for EsploraBlockchain {
+    fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
+        let block_header = self.url_client.get_header(height as u32)?;
+        Ok(block_header.block_hash())
+    }
+}
+
+impl WalletSync for EsploraBlockchain {
+    fn wallet_setup<D: BatchDatabase>(
+        &self,
+        database: &mut D,
+        _progress_update: Box<dyn Progress>,
+    ) -> Result<(), Error> {
+        use crate::blockchain::script_sync::Request;
+        let mut request = script_sync::start(database, self.stop_gap)?;
+        let mut tx_index: HashMap<Txid, Tx> = HashMap::new();
+        let batch_update = loop {
+            request = match request {
+                Request::Script(script_req) => {
+                    let scripts = script_req
+                        .request()
+                        .take(self.concurrency as usize)
+                        .cloned();
+
+                    let mut handles = vec![];
+                    for script in scripts {
+                        let client = self.url_client.clone();
+                        // make each request in its own thread.
+                        handles.push(std::thread::spawn(move || {
+                            let mut related_txs: Vec<Tx> = client.scripthash_txs(&script, None)?;
+
+                            let n_confirmed =
+                                related_txs.iter().filter(|tx| tx.status.confirmed).count();
+                            // esplora pages on 25 confirmed transactions. If there's 25 or more we
+                            // keep requesting to see if there's more.
+                            if n_confirmed >= 25 {
+                                loop {
+                                    let new_related_txs: Vec<Tx> = client.scripthash_txs(
+                                        &script,
+                                        Some(related_txs.last().unwrap().txid),
+                                    )?;
+                                    let n = new_related_txs.len();
+                                    related_txs.extend(new_related_txs);
+                                    // we've reached the end
+                                    if n < 25 {
+                                        break;
+                                    }
+                                }
+                            }
+                            Result::<_, Error>::Ok(related_txs)
+                        }));
+                    }
+
+                    let txs_per_script: Vec<Vec<Tx>> = handles
+                        .into_iter()
+                        .map(|handle| handle.join().unwrap())
+                        .collect::<Result<_, _>>()?;
+                    let mut satisfaction = vec![];
+
+                    for txs in txs_per_script {
+                        satisfaction.push(
+                            txs.iter()
+                                .map(|tx| (tx.txid, tx.status.block_height))
+                                .collect(),
+                        );
+                        for tx in txs {
+                            tx_index.insert(tx.txid, tx);
+                        }
+                    }
+
+                    script_req.satisfy(satisfaction)?
+                }
+                Request::Conftime(conftime_req) => {
+                    let conftimes = conftime_req
+                        .request()
+                        .map(|txid| {
+                            tx_index
+                                .get(txid)
+                                .expect("must be in index")
+                                .confirmation_time()
+                                .map(Into::into)
+                        })
+                        .collect();
+                    conftime_req.satisfy(conftimes)?
+                }
+                Request::Tx(tx_req) => {
+                    let full_txs = tx_req
+                        .request()
+                        .map(|txid| {
+                            let tx = tx_index.get(txid).expect("must be in index");
+                            Ok((tx.previous_outputs(), tx.to_tx()))
+                        })
+                        .collect::<Result<_, Error>>()?;
+                    tx_req.satisfy(full_txs)?
+                }
+                Request::Finish(batch_update) => break batch_update,
+            }
+        };
+
+        database.commit_batch(batch_update)?;
+
+        Ok(())
+    }
+}
+
+impl ConfigurableBlockchain for EsploraBlockchain {
+    type Config = super::EsploraBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        let mut builder = Builder::new(config.base_url.as_str());
+
+        if let Some(timeout) = config.timeout {
+            builder = builder.timeout(timeout);
+        }
+
+        if let Some(proxy) = &config.proxy {
+            builder = builder.proxy(proxy);
+        }
+
+        let mut blockchain =
+            EsploraBlockchain::from_client(builder.build_blocking()?, config.stop_gap);
+
+        if let Some(concurrency) = config.concurrency {
+            blockchain = blockchain.with_concurrency(concurrency);
+        }
+
+        Ok(blockchain)
+    }
+}
index 7a4b193728521d454d16f11f011264f16e323a9d..57032e49d30396f7f200da0846bdf64ef71539fa 100644 (file)
 //! depending on your needs (blocking or async respectively).
 //!
 //! Please note, to configure the Esplora HTTP client correctly use one of:
-//! Blocking:  --features='esplora,ureq'
-//! Async:     --features='async-interface,esplora,reqwest' --no-default-features
+//! Blocking:  --features='use-esplora-blocking'
+//! Async:     --features='async-interface,use-esplora-async' --no-default-features
 
 pub use esplora_client::Error as EsploraError;
 
 #[cfg(feature = "use-esplora-async")]
-mod reqwest;
+mod r#async;
 
 #[cfg(feature = "use-esplora-async")]
-pub use self::reqwest::*;
+pub use self::r#async::*;
 
 #[cfg(feature = "use-esplora-blocking")]
-mod ureq;
+mod blocking;
 
 #[cfg(feature = "use-esplora-blocking")]
-pub use self::ureq::*;
+pub use self::blocking::*;
 
 /// Configuration for an [`EsploraBlockchain`]
 #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq)]
diff --git a/src/blockchain/esplora/reqwest.rs b/src/blockchain/esplora/reqwest.rs
deleted file mode 100644 (file)
index 5ddbdeb..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-// Bitcoin Dev Kit
-// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
-//
-// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-//! Esplora by way of `reqwest` HTTP client.
-
-use std::collections::{HashMap, HashSet};
-use std::ops::Deref;
-
-use bitcoin::{Transaction, Txid};
-
-#[allow(unused_imports)]
-use log::{debug, error, info, trace};
-
-use esplora_client::{convert_fee_rate, AsyncClient, Builder, Tx};
-use futures::stream::{FuturesOrdered, TryStreamExt};
-
-use crate::blockchain::*;
-use crate::database::BatchDatabase;
-use crate::error::Error;
-use crate::FeeRate;
-
-/// Structure that implements the logic to sync with Esplora
-///
-/// ## Example
-/// See the [`blockchain::esplora`](crate::blockchain::esplora) module for a usage example.
-#[derive(Debug)]
-pub struct EsploraBlockchain {
-    url_client: AsyncClient,
-    stop_gap: usize,
-    concurrency: u8,
-}
-
-impl std::convert::From<AsyncClient> for EsploraBlockchain {
-    fn from(url_client: AsyncClient) -> Self {
-        EsploraBlockchain {
-            url_client,
-            stop_gap: 20,
-            concurrency: super::DEFAULT_CONCURRENT_REQUESTS,
-        }
-    }
-}
-
-impl EsploraBlockchain {
-    /// Create a new instance of the client from a base URL and `stop_gap`.
-    pub fn new(base_url: &str, stop_gap: usize) -> Self {
-        let url_client = Builder::new(base_url)
-            .build_async()
-            .expect("Should never fail with no proxy and timeout");
-
-        Self::from_client(url_client, stop_gap)
-    }
-
-    /// Build a new instance given a client
-    pub fn from_client(url_client: AsyncClient, stop_gap: usize) -> Self {
-        EsploraBlockchain {
-            url_client,
-            stop_gap,
-            concurrency: super::DEFAULT_CONCURRENT_REQUESTS,
-        }
-    }
-
-    /// Set the concurrency to use when doing batch queries against the Esplora instance.
-    pub fn with_concurrency(mut self, concurrency: u8) -> Self {
-        self.concurrency = concurrency;
-        self
-    }
-}
-
-#[maybe_async]
-impl Blockchain for EsploraBlockchain {
-    fn get_capabilities(&self) -> HashSet<Capability> {
-        vec![
-            Capability::FullHistory,
-            Capability::GetAnyTx,
-            Capability::AccurateFees,
-        ]
-        .into_iter()
-        .collect()
-    }
-
-    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
-        Ok(await_or_block!(self.url_client.broadcast(tx))?)
-    }
-
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
-        let estimates = await_or_block!(self.url_client.get_fee_estimates())?;
-        Ok(FeeRate::from_sat_per_vb(convert_fee_rate(
-            target, estimates,
-        )?))
-    }
-}
-
-impl Deref for EsploraBlockchain {
-    type Target = AsyncClient;
-
-    fn deref(&self) -> &Self::Target {
-        &self.url_client
-    }
-}
-
-impl StatelessBlockchain for EsploraBlockchain {}
-
-#[maybe_async]
-impl GetHeight for EsploraBlockchain {
-    fn get_height(&self) -> Result<u32, Error> {
-        Ok(await_or_block!(self.url_client.get_height())?)
-    }
-}
-
-#[maybe_async]
-impl GetTx for EsploraBlockchain {
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(await_or_block!(self.url_client.get_tx(txid))?)
-    }
-}
-
-#[maybe_async]
-impl GetBlockHash for EsploraBlockchain {
-    fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
-        let block_header = await_or_block!(self.url_client.get_header(height as u32))?;
-        Ok(block_header.block_hash())
-    }
-}
-
-#[maybe_async]
-impl WalletSync for EsploraBlockchain {
-    fn wallet_setup<D: BatchDatabase>(
-        &self,
-        database: &mut D,
-        _progress_update: Box<dyn Progress>,
-    ) -> Result<(), Error> {
-        use crate::blockchain::script_sync::Request;
-        let mut request = script_sync::start(database, self.stop_gap)?;
-        let mut tx_index: HashMap<Txid, Tx> = HashMap::new();
-
-        let batch_update = loop {
-            request = match request {
-                Request::Script(script_req) => {
-                    let futures: FuturesOrdered<_> = script_req
-                        .request()
-                        .take(self.concurrency as usize)
-                        .map(|script| async move {
-                            let mut related_txs: Vec<Tx> =
-                                self.url_client.scripthash_txs(script, None).await?;
-
-                            let n_confirmed =
-                                related_txs.iter().filter(|tx| tx.status.confirmed).count();
-                            // esplora pages on 25 confirmed transactions. If there's 25 or more we
-                            // keep requesting to see if there's more.
-                            if n_confirmed >= 25 {
-                                loop {
-                                    let new_related_txs: Vec<Tx> = self
-                                        .url_client
-                                        .scripthash_txs(
-                                            script,
-                                            Some(related_txs.last().unwrap().txid),
-                                        )
-                                        .await?;
-                                    let n = new_related_txs.len();
-                                    related_txs.extend(new_related_txs);
-                                    // we've reached the end
-                                    if n < 25 {
-                                        break;
-                                    }
-                                }
-                            }
-                            Result::<_, Error>::Ok(related_txs)
-                        })
-                        .collect();
-                    let txs_per_script: Vec<Vec<Tx>> = await_or_block!(futures.try_collect())?;
-                    let mut satisfaction = vec![];
-
-                    for txs in txs_per_script {
-                        satisfaction.push(
-                            txs.iter()
-                                .map(|tx| (tx.txid, tx.status.block_height))
-                                .collect(),
-                        );
-                        for tx in txs {
-                            tx_index.insert(tx.txid, tx);
-                        }
-                    }
-
-                    script_req.satisfy(satisfaction)?
-                }
-                Request::Conftime(conftime_req) => {
-                    let conftimes = conftime_req
-                        .request()
-                        .map(|txid| {
-                            tx_index
-                                .get(txid)
-                                .expect("must be in index")
-                                .confirmation_time()
-                                .map(Into::into)
-                        })
-                        .collect();
-                    conftime_req.satisfy(conftimes)?
-                }
-                Request::Tx(tx_req) => {
-                    let full_txs = tx_req
-                        .request()
-                        .map(|txid| {
-                            let tx = tx_index.get(txid).expect("must be in index");
-                            Ok((tx.previous_outputs(), tx.to_tx()))
-                        })
-                        .collect::<Result<_, Error>>()?;
-                    tx_req.satisfy(full_txs)?
-                }
-                Request::Finish(batch_update) => break batch_update,
-            }
-        };
-
-        database.commit_batch(batch_update)?;
-        Ok(())
-    }
-}
-
-impl ConfigurableBlockchain for EsploraBlockchain {
-    type Config = super::EsploraBlockchainConfig;
-
-    fn from_config(config: &Self::Config) -> Result<Self, Error> {
-        let mut builder = Builder::new(config.base_url.as_str());
-
-        if let Some(timeout) = config.timeout {
-            builder = builder.timeout(timeout);
-        }
-
-        if let Some(proxy) = &config.proxy {
-            builder = builder.proxy(proxy);
-        }
-
-        let mut blockchain =
-            EsploraBlockchain::from_client(builder.build_async()?, config.stop_gap);
-
-        if let Some(concurrency) = config.concurrency {
-            blockchain = blockchain.with_concurrency(concurrency);
-        }
-
-        Ok(blockchain)
-    }
-}
diff --git a/src/blockchain/esplora/ureq.rs b/src/blockchain/esplora/ureq.rs
deleted file mode 100644 (file)
index 1e9d1cf..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-// Bitcoin Dev Kit
-// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
-//
-// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-//! Esplora by way of `ureq` HTTP client.
-
-use std::collections::{HashMap, HashSet};
-
-#[allow(unused_imports)]
-use log::{debug, error, info, trace};
-
-use bitcoin::{Transaction, Txid};
-
-use esplora_client::{convert_fee_rate, BlockingClient, Builder, Tx};
-
-use crate::blockchain::*;
-use crate::database::BatchDatabase;
-use crate::error::Error;
-use crate::FeeRate;
-
-/// Structure that implements the logic to sync with Esplora
-///
-/// ## Example
-/// See the [`blockchain::esplora`](crate::blockchain::esplora) module for a usage example.
-#[derive(Debug)]
-pub struct EsploraBlockchain {
-    url_client: BlockingClient,
-    stop_gap: usize,
-    concurrency: u8,
-}
-
-impl EsploraBlockchain {
-    /// 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 {
-        let url_client = Builder::new(base_url)
-            .build_blocking()
-            .expect("Should never fail with no proxy and timeout");
-
-        Self::from_client(url_client, stop_gap)
-    }
-
-    /// Build a new instance given a client
-    pub fn from_client(url_client: BlockingClient, stop_gap: usize) -> Self {
-        EsploraBlockchain {
-            url_client,
-            concurrency: super::DEFAULT_CONCURRENT_REQUESTS,
-            stop_gap,
-        }
-    }
-
-    /// Set the number of parallel requests the client can make.
-    pub fn with_concurrency(mut self, concurrency: u8) -> Self {
-        self.concurrency = concurrency;
-        self
-    }
-}
-
-impl Blockchain for EsploraBlockchain {
-    fn get_capabilities(&self) -> HashSet<Capability> {
-        vec![
-            Capability::FullHistory,
-            Capability::GetAnyTx,
-            Capability::AccurateFees,
-        ]
-        .into_iter()
-        .collect()
-    }
-
-    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
-        self.url_client.broadcast(tx)?;
-        Ok(())
-    }
-
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
-        let estimates = self.url_client.get_fee_estimates()?;
-        Ok(FeeRate::from_sat_per_vb(convert_fee_rate(
-            target, estimates,
-        )?))
-    }
-}
-
-impl Deref for EsploraBlockchain {
-    type Target = BlockingClient;
-
-    fn deref(&self) -> &Self::Target {
-        &self.url_client
-    }
-}
-
-impl StatelessBlockchain for EsploraBlockchain {}
-
-impl GetHeight for EsploraBlockchain {
-    fn get_height(&self) -> Result<u32, Error> {
-        Ok(self.url_client.get_height()?)
-    }
-}
-
-impl GetTx for EsploraBlockchain {
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(self.url_client.get_tx(txid)?)
-    }
-}
-
-impl GetBlockHash for EsploraBlockchain {
-    fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
-        let block_header = self.url_client.get_header(height as u32)?;
-        Ok(block_header.block_hash())
-    }
-}
-
-impl WalletSync for EsploraBlockchain {
-    fn wallet_setup<D: BatchDatabase>(
-        &self,
-        database: &mut D,
-        _progress_update: Box<dyn Progress>,
-    ) -> Result<(), Error> {
-        use crate::blockchain::script_sync::Request;
-        let mut request = script_sync::start(database, self.stop_gap)?;
-        let mut tx_index: HashMap<Txid, Tx> = HashMap::new();
-        let batch_update = loop {
-            request = match request {
-                Request::Script(script_req) => {
-                    let scripts = script_req
-                        .request()
-                        .take(self.concurrency as usize)
-                        .cloned();
-
-                    let mut handles = vec![];
-                    for script in scripts {
-                        let client = self.url_client.clone();
-                        // make each request in its own thread.
-                        handles.push(std::thread::spawn(move || {
-                            let mut related_txs: Vec<Tx> = client.scripthash_txs(&script, None)?;
-
-                            let n_confirmed =
-                                related_txs.iter().filter(|tx| tx.status.confirmed).count();
-                            // esplora pages on 25 confirmed transactions. If there's 25 or more we
-                            // keep requesting to see if there's more.
-                            if n_confirmed >= 25 {
-                                loop {
-                                    let new_related_txs: Vec<Tx> = client.scripthash_txs(
-                                        &script,
-                                        Some(related_txs.last().unwrap().txid),
-                                    )?;
-                                    let n = new_related_txs.len();
-                                    related_txs.extend(new_related_txs);
-                                    // we've reached the end
-                                    if n < 25 {
-                                        break;
-                                    }
-                                }
-                            }
-                            Result::<_, Error>::Ok(related_txs)
-                        }));
-                    }
-
-                    let txs_per_script: Vec<Vec<Tx>> = handles
-                        .into_iter()
-                        .map(|handle| handle.join().unwrap())
-                        .collect::<Result<_, _>>()?;
-                    let mut satisfaction = vec![];
-
-                    for txs in txs_per_script {
-                        satisfaction.push(
-                            txs.iter()
-                                .map(|tx| (tx.txid, tx.status.block_height))
-                                .collect(),
-                        );
-                        for tx in txs {
-                            tx_index.insert(tx.txid, tx);
-                        }
-                    }
-
-                    script_req.satisfy(satisfaction)?
-                }
-                Request::Conftime(conftime_req) => {
-                    let conftimes = conftime_req
-                        .request()
-                        .map(|txid| {
-                            tx_index
-                                .get(txid)
-                                .expect("must be in index")
-                                .confirmation_time()
-                                .map(Into::into)
-                        })
-                        .collect();
-                    conftime_req.satisfy(conftimes)?
-                }
-                Request::Tx(tx_req) => {
-                    let full_txs = tx_req
-                        .request()
-                        .map(|txid| {
-                            let tx = tx_index.get(txid).expect("must be in index");
-                            Ok((tx.previous_outputs(), tx.to_tx()))
-                        })
-                        .collect::<Result<_, Error>>()?;
-                    tx_req.satisfy(full_txs)?
-                }
-                Request::Finish(batch_update) => break batch_update,
-            }
-        };
-
-        database.commit_batch(batch_update)?;
-
-        Ok(())
-    }
-}
-
-impl ConfigurableBlockchain for EsploraBlockchain {
-    type Config = super::EsploraBlockchainConfig;
-
-    fn from_config(config: &Self::Config) -> Result<Self, Error> {
-        let mut builder = Builder::new(config.base_url.as_str());
-
-        if let Some(timeout) = config.timeout {
-            builder = builder.timeout(timeout);
-        }
-
-        if let Some(proxy) = &config.proxy {
-            builder = builder.proxy(proxy);
-        }
-
-        let mut blockchain =
-            EsploraBlockchain::from_client(builder.build_blocking()?, config.stop_gap);
-
-        if let Some(concurrency) = config.concurrency {
-            blockchain = blockchain.with_concurrency(concurrency);
-        }
-
-        Ok(blockchain)
-    }
-}