[blockchain] Add a trait to create Blockchains from a configuration

This is the first set of changes for #42
This commit is contained in:
Alekos Filini 2020-09-10 18:08:37 +02:00
parent 6094656a54
commit 5eee18bed2
No known key found for this signature in database
GPG Key ID: 5E8AFC3034FDFA4F
5 changed files with 98 additions and 10 deletions

View File

@ -37,9 +37,9 @@ use log::{debug, error, info, trace, LevelFilter};
use bitcoin::Network; use bitcoin::Network;
use bdk::bitcoin; use bdk::bitcoin;
use bdk::blockchain::ElectrumBlockchain; use bdk::blockchain::electrum::{ElectrumBlockchain, ElectrumBlockchainConfig};
use bdk::blockchain::ConfigurableBlockchain;
use bdk::cli; use bdk::cli;
use bdk::electrum_client::Client;
use bdk::sled; use bdk::sled;
use bdk::Wallet; use bdk::Wallet;
@ -89,17 +89,16 @@ fn main() {
.unwrap(); .unwrap();
debug!("database opened successfully"); debug!("database opened successfully");
let client = Client::new( let blockchain_config = ElectrumBlockchainConfig {
matches.value_of("server").unwrap(), url: matches.value_of("server").unwrap().to_string(),
matches.value_of("proxy"), socks5: matches.value_of("proxy").map(ToString::to_string),
) };
.unwrap();
let wallet = Wallet::new( let wallet = Wallet::new(
descriptor, descriptor,
change_descriptor, change_descriptor,
network, network,
tree, tree,
ElectrumBlockchain::from(client), ElectrumBlockchain::from_config(&blockchain_config).unwrap(),
) )
.unwrap(); .unwrap();
let wallet = Arc::new(wallet); let wallet = Arc::new(wallet);

View File

@ -68,7 +68,7 @@ use std::sync::{Arc, Mutex};
use log::{debug, error, info, trace}; use log::{debug, error, info, trace};
use bitcoin::network::message_blockdata::Inventory; use bitcoin::network::message_blockdata::Inventory;
use bitcoin::{OutPoint, Transaction, Txid}; use bitcoin::{Network, OutPoint, Transaction, Txid};
use rocksdb::{Options, SliceTransform, DB}; use rocksdb::{Options, SliceTransform, DB};
@ -76,7 +76,7 @@ mod peer;
mod store; mod store;
mod sync; mod sync;
use super::{Blockchain, Capability, Progress}; use super::{Blockchain, Capability, ConfigurableBlockchain, Progress};
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils}; use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
use crate::error::Error; use crate::error::Error;
use crate::types::{ScriptType, TransactionDetails, UTXO}; 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`] /// An error that can occur during sync with a [`CompactFiltersBlockchain`]
#[derive(Debug)] #[derive(Debug)]
pub enum CompactFiltersError { pub enum CompactFiltersError {

View File

@ -173,3 +173,21 @@ impl ElectrumLikeSync for Client {
self.transaction_get(txid).map_err(Error::Electrum) 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(),
)?))
}
}

View File

@ -340,6 +340,20 @@ struct EsploraListUnspent {
status: EsploraGetHistoryStatus, 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`] /// Errors that can happen during a sync with [`EsploraBlockchain`]
#[derive(Debug)] #[derive(Debug)]
pub enum EsploraError { pub enum EsploraError {

View File

@ -152,6 +152,15 @@ pub trait Blockchain: BlockchainMarker {
fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error>; 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`] /// Data sent with a progress update over a [`channel`]
pub type ProgressData = (f32, Option<String>); pub type ProgressData = (f32, Option<String>);