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;
.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);
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};
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};
}
}
+/// 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 {
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(),
+ )?))
+ }
+}
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 {
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>);