diff --git a/examples/repl.rs b/examples/repl.rs index 857d6abd..bcd9a9fb 100644 --- a/examples/repl.rs +++ b/examples/repl.rs @@ -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); diff --git a/src/blockchain/compact_filters/mod.rs b/src/blockchain/compact_filters/mod.rs index 9c357fc5..f1ca414c 100644 --- a/src/blockchain/compact_filters/mod.rs +++ b/src/blockchain/compact_filters/mod.rs @@ -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, + pub socks5_credentials: Option<(String, String)>, +} + +/// Configuration for a [`CompactFiltersBlockchain`] +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct CompactFiltersBlockchainConfig { + pub peers: Vec, + pub network: Network, + pub storage_dir: String, + pub skip_blocks: Option, +} + +impl ConfigurableBlockchain for CompactFiltersBlockchain { + type Config = CompactFiltersBlockchainConfig; + + fn from_config(config: &Self::Config) -> Result { + 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::>()?; + + 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 { diff --git a/src/blockchain/electrum.rs b/src/blockchain/electrum.rs index 33cd72a9..9655ebbb 100644 --- a/src/blockchain/electrum.rs +++ b/src/blockchain/electrum.rs @@ -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, +} + +impl ConfigurableBlockchain for ElectrumBlockchain { + type Config = ElectrumBlockchainConfig; + + fn from_config(config: &Self::Config) -> Result { + Ok(ElectrumBlockchain(Client::new( + config.url.as_str(), + config.socks5.as_deref(), + )?)) + } +} diff --git a/src/blockchain/esplora.rs b/src/blockchain/esplora.rs index 916c5df4..ef649d0b 100644 --- a/src/blockchain/esplora.rs +++ b/src/blockchain/esplora.rs @@ -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 { + Ok(EsploraBlockchain::new(config.base_url.as_str())) + } +} + /// Errors that can happen during a sync with [`EsploraBlockchain`] #[derive(Debug)] pub enum EsploraError { diff --git a/src/blockchain/mod.rs b/src/blockchain/mod.rs index 8fcee951..7d40a4c6 100644 --- a/src/blockchain/mod.rs +++ b/src/blockchain/mod.rs @@ -152,6 +152,15 @@ pub trait Blockchain: BlockchainMarker { fn estimate_fee(&self, target: usize) -> Result; } +/// 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; +} + /// Data sent with a progress update over a [`channel`] pub type ProgressData = (f32, Option);