]> Untitled Git - bdk/commitdiff
[blockchain] Add a trait to create `Blockchain`s from a configuration
authorAlekos Filini <alekos.filini@gmail.com>
Thu, 10 Sep 2020 16:08:37 +0000 (18:08 +0200)
committerAlekos Filini <alekos.filini@gmail.com>
Tue, 15 Sep 2020 10:03:04 +0000 (12:03 +0200)
This is the first set of changes for #42

examples/repl.rs
src/blockchain/compact_filters/mod.rs
src/blockchain/electrum.rs
src/blockchain/esplora.rs
src/blockchain/mod.rs

index 857d6abdf2acfc3534f27091a28618afbd05f7ec..bcd9a9fb3b5ddacaf4760dc5f04a13a960ecc69d 100644 (file)
@@ -37,9 +37,9 @@ use log::{debug, error, info, trace, LevelFilter};
 use bitcoin::Network;
 
 use bdk::bitcoin;
-use bdk::blockchain::ElectrumBlockchain;
+use bdk::blockchain::electrum::{ElectrumBlockchain, ElectrumBlockchainConfig};
+use bdk::blockchain::ConfigurableBlockchain;
 use bdk::cli;
-use bdk::electrum_client::Client;
 use bdk::sled;
 use bdk::Wallet;
 
@@ -89,17 +89,16 @@ fn main() {
         .unwrap();
     debug!("database opened successfully");
 
-    let client = Client::new(
-        matches.value_of("server").unwrap(),
-        matches.value_of("proxy"),
-    )
-    .unwrap();
+    let blockchain_config = ElectrumBlockchainConfig {
+        url: matches.value_of("server").unwrap().to_string(),
+        socks5: matches.value_of("proxy").map(ToString::to_string),
+    };
     let wallet = Wallet::new(
         descriptor,
         change_descriptor,
         network,
         tree,
-        ElectrumBlockchain::from(client),
+        ElectrumBlockchain::from_config(&blockchain_config).unwrap(),
     )
     .unwrap();
     let wallet = Arc::new(wallet);
index 9c357fc5788e7402d230ef050f01d4b07b36e478..f1ca414c3b6714b45062577b9e03834ae597e4f2 100644 (file)
@@ -68,7 +68,7 @@ use std::sync::{Arc, Mutex};
 use log::{debug, error, info, trace};
 
 use bitcoin::network::message_blockdata::Inventory;
-use bitcoin::{OutPoint, Transaction, Txid};
+use bitcoin::{Network, OutPoint, Transaction, Txid};
 
 use rocksdb::{Options, SliceTransform, DB};
 
@@ -76,7 +76,7 @@ mod peer;
 mod store;
 mod sync;
 
-use super::{Blockchain, Capability, Progress};
+use super::{Blockchain, Capability, ConfigurableBlockchain, Progress};
 use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
 use crate::error::Error;
 use crate::types::{ScriptType, TransactionDetails, UTXO};
@@ -460,6 +460,54 @@ impl Blockchain for CompactFiltersBlockchain {
     }
 }
 
+/// Data to connect to a Bitcoin P2P peer
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct BitcoinPeerConfig {
+    pub address: String,
+    pub socks5: Option<String>,
+    pub socks5_credentials: Option<(String, String)>,
+}
+
+/// Configuration for a [`CompactFiltersBlockchain`]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct CompactFiltersBlockchainConfig {
+    pub peers: Vec<BitcoinPeerConfig>,
+    pub network: Network,
+    pub storage_dir: String,
+    pub skip_blocks: Option<usize>,
+}
+
+impl ConfigurableBlockchain for CompactFiltersBlockchain {
+    type Config = CompactFiltersBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        let mempool = Arc::new(Mempool::default());
+        let peers = config
+            .peers
+            .iter()
+            .map(|peer_conf| match &peer_conf.socks5 {
+                None => Peer::connect(&peer_conf.address, Arc::clone(&mempool), config.network),
+                Some(proxy) => Peer::connect_proxy(
+                    peer_conf.address.as_str(),
+                    proxy,
+                    peer_conf
+                        .socks5_credentials
+                        .as_ref()
+                        .map(|(a, b)| (a.as_str(), b.as_str())),
+                    Arc::clone(&mempool),
+                    config.network,
+                ),
+            })
+            .collect::<Result<_, _>>()?;
+
+        Ok(CompactFiltersBlockchain::new(
+            peers,
+            &config.storage_dir,
+            config.skip_blocks,
+        )?)
+    }
+}
+
 /// An error that can occur during sync with a [`CompactFiltersBlockchain`]
 #[derive(Debug)]
 pub enum CompactFiltersError {
index 33cd72a99fd280c74b363f846aff754d547f14a7..9655ebbb8396bc4278db05b22c74368bd499487f 100644 (file)
@@ -173,3 +173,21 @@ impl ElectrumLikeSync for Client {
         self.transaction_get(txid).map_err(Error::Electrum)
     }
 }
+
+/// Configuration for an [`ElectrumBlockchain`]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct ElectrumBlockchainConfig {
+    pub url: String,
+    pub socks5: Option<String>,
+}
+
+impl ConfigurableBlockchain for ElectrumBlockchain {
+    type Config = ElectrumBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        Ok(ElectrumBlockchain(Client::new(
+            config.url.as_str(),
+            config.socks5.as_deref(),
+        )?))
+    }
+}
index 916c5df442243fd5b257a968c4da3f8501c75358..ef649d0bfa33e3bb4b1b02ed21c6852899af5344 100644 (file)
@@ -340,6 +340,20 @@ struct EsploraListUnspent {
     status: EsploraGetHistoryStatus,
 }
 
+/// Configuration for an [`EsploraBlockchain`]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct EsploraBlockchainConfig {
+    pub base_url: String,
+}
+
+impl ConfigurableBlockchain for EsploraBlockchain {
+    type Config = EsploraBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        Ok(EsploraBlockchain::new(config.base_url.as_str()))
+    }
+}
+
 /// Errors that can happen during a sync with [`EsploraBlockchain`]
 #[derive(Debug)]
 pub enum EsploraError {
index 8fcee951ef38896679358cdc39bb1d29ac2da6a1..7d40a4c676a4395ecf02a4978159995614cb5ade 100644 (file)
@@ -152,6 +152,15 @@ pub trait Blockchain: BlockchainMarker {
     fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error>;
 }
 
+/// Trait for [`Blockchain`] types that can be created given a configuration
+pub trait ConfigurableBlockchain: Blockchain + Sized {
+    /// Type that contains the configuration
+    type Config: std::fmt::Debug;
+
+    /// Create a new instance given a configuration
+    fn from_config(config: &Self::Config) -> Result<Self, Error>;
+}
+
 /// Data sent with a progress update over a [`channel`]
 pub type ProgressData = (f32, Option<String>);