From 47e09626a274088ac5b3b5aa14a600f5a414dc5e Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 4 Aug 2021 21:52:58 -0700 Subject: [PATCH] Require only one blockchain client feature at a time --- .github/workflows/cont_integration.yml | 1 - Cargo.toml | 4 +- src/bdk_cli.rs | 110 +++++++++++++++---------- src/lib.rs | 62 ++++++++------ 4 files changed, 104 insertions(+), 73 deletions(-) diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index c51cad0..41967fa 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -19,7 +19,6 @@ jobs: - esplora - compiler - compact_filters - - repl,electrum,esplora,compiler steps: - name: Checkout uses: actions/checkout@v2 diff --git a/Cargo.toml b/Cargo.toml index 65e8ffd..507c2f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ compact_filters = ["bdk/compact_filters"] [[bin]] name = "bdk-cli" path = "src/bdk_cli.rs" -required-features = ["repl", "electrum"] +required-features = ["repl"] [package.metadata.docs.rs] -features = ["esplora", "compiler"] +features = ["compiler"] diff --git a/src/bdk_cli.rs b/src/bdk_cli.rs index 25df3b7..e6d8b8c 100644 --- a/src/bdk_cli.rs +++ b/src/bdk_cli.rs @@ -34,21 +34,25 @@ use structopt::StructOpt; #[cfg(feature = "compact_filters")] use bdk::blockchain::compact_filters::{BitcoinPeerConfig, CompactFiltersBlockchainConfig}; +#[cfg(feature = "electrum")] +use bdk::blockchain::electrum::ElectrumBlockchainConfig; #[cfg(feature = "esplora")] use bdk::blockchain::esplora::EsploraBlockchainConfig; -use bdk::blockchain::{ - AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain, ElectrumBlockchainConfig, -}; + +#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +use bdk::blockchain::{AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain}; + use bdk::database::BatchDatabase; use bdk::sled; use bdk::sled::Tree; use bdk::Wallet; use bdk::{bitcoin, Error}; use bdk_cli::WalletSubCommand; -use bdk_cli::{ - CliOpts, CliSubCommand, KeySubCommand, OfflineWalletSubCommand, OnlineWalletSubCommand, - WalletOpts, -}; +use bdk_cli::{CliOpts, CliSubCommand, KeySubCommand, OfflineWalletSubCommand, WalletOpts}; + +#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +use bdk_cli::OnlineWalletSubCommand; + use regex::Regex; const REPL_LINE_SPLIT_REGEX: &str = r#""([^"]*)"|'([^']*)'|([\w\-]+)"#; @@ -59,6 +63,7 @@ const REPL_LINE_SPLIT_REGEX: &str = r#""([^"]*)"|'([^']*)'|([\w\-]+)"#; version = option_env ! ("CARGO_PKG_VERSION").unwrap_or("unknown"), author = option_env ! ("CARGO_PKG_AUTHORS").unwrap_or(""))] pub enum ReplSubCommand { + #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] #[structopt(flatten)] OnlineWalletSubCommand(OnlineWalletSubCommand), #[structopt(flatten)] @@ -96,6 +101,7 @@ fn open_database(wallet_opts: &WalletOpts) -> Tree { tree } +#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] fn new_online_wallet( network: Network, wallet_opts: &WalletOpts, @@ -104,29 +110,40 @@ fn new_online_wallet( where D: BatchDatabase, { - // Try to use Esplora config if "esplora" feature is enabled - #[cfg(feature = "esplora")] - let config_esplora: Option = { - let esplora_concurrency = wallet_opts.esplora_opts.esplora_concurrency; - wallet_opts.esplora_opts.esplora.clone().map(|base_url| { - AnyBlockchainConfig::Esplora(EsploraBlockchainConfig { - base_url, - concurrency: Some(esplora_concurrency), - }) - }) - }; - #[cfg(not(feature = "esplora"))] - let config_esplora = None; - - let config_electrum = AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig { + #[cfg(all( + feature = "electrum", + any(feature = "esplora", feature = "compact_filters") + ))] + compile_error!("Only one blockchain client feature can be enabled at a time. The 'electrum' feature can not be enabled with 'esplora' or 'compact_filters'."); + + #[cfg(feature = "electrum")] + let config = AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig { url: wallet_opts.electrum_opts.electrum.clone(), socks5: wallet_opts.proxy_opts.proxy.clone(), retry: wallet_opts.proxy_opts.retries, timeout: wallet_opts.electrum_opts.timeout, }); + #[cfg(all( + feature = "esplora", + any(feature = "electrum", feature = "compact_filters") + ))] + compile_error!("Only one blockchain client feature can be enabled at a time. The 'esplora' feature can not be enabled with 'electrum' or 'compact_filters'."); + + #[cfg(feature = "esplora")] + let config = AnyBlockchainConfig::Esplora(EsploraBlockchainConfig { + base_url: wallet_opts.esplora_opts.server.clone(), + concurrency: Some(wallet_opts.esplora_opts.concurrency), + }); + + #[cfg(all( + feature = "compact_filters", + any(feature = "electrum", feature = "esplora") + ))] + compile_error!("Only one blockchain client feature can be enabled at a time. The 'esplora' feature can not be enabled with 'electrum' or 'compact_filters'."); + #[cfg(feature = "compact_filters")] - let config_compact_filters: Option = { + let config = { let mut peers = vec![]; for addrs in wallet_opts.compactfilter_opts.address.clone() { for _ in 0..wallet_opts.compactfilter_opts.conn_count { @@ -138,26 +155,17 @@ where } } - Some(AnyBlockchainConfig::CompactFilters( - CompactFiltersBlockchainConfig { - peers, - network, - storage_dir: prepare_home_dir().into_os_string().into_string().unwrap(), - skip_blocks: Some(wallet_opts.compactfilter_opts.skip_blocks), - }, - )) + AnyBlockchainConfig::CompactFilters(CompactFiltersBlockchainConfig { + peers, + network, + storage_dir: prepare_home_dir().into_os_string().into_string().unwrap(), + skip_blocks: Some(wallet_opts.compactfilter_opts.skip_blocks), + }) }; - #[cfg(not(feature = "compact_filters"))] - let config_compact_filters = None; - - // Fall back to Electrum config if Esplora or Compact Filter config isn't provided - let config = config_esplora - .or(config_compact_filters) - .unwrap_or(config_electrum); - let descriptor = wallet_opts.descriptor.as_str(); let change_descriptor = wallet_opts.change_descriptor.as_deref(); + let wallet = Wallet::new( descriptor, change_descriptor, @@ -206,6 +214,7 @@ fn main() { fn handle_command(cli_opts: CliOpts, network: Network) -> Result { let result = match cli_opts.subcommand { + #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] CliSubCommand::Wallet { wallet_opts, subcommand: WalletSubCommand::OnlineWalletSubCommand(online_subcommand), @@ -244,7 +253,16 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result } CliSubCommand::Repl { wallet_opts } => { let database = open_database(&wallet_opts); - let online_wallet = new_online_wallet(network, &wallet_opts, database)?; + + #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] + let wallet = new_online_wallet(network, &wallet_opts, database)?; + + #[cfg(not(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters" + )))] + let wallet = new_offline_wallet(network, &wallet_opts, database)?; let mut rl = Editor::<()>::new(); @@ -285,15 +303,17 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result let repl_subcommand = repl_subcommand.unwrap(); let result = match repl_subcommand { + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters" + ))] ReplSubCommand::OnlineWalletSubCommand(online_subcommand) => { - bdk_cli::handle_online_wallet_subcommand( - &online_wallet, - online_subcommand, - ) + bdk_cli::handle_online_wallet_subcommand(&wallet, online_subcommand) } ReplSubCommand::OfflineWalletSubCommand(offline_subcommand) => { bdk_cli::handle_offline_wallet_subcommand( - &online_wallet, + &wallet, &wallet_opts, offline_subcommand, ) diff --git a/src/lib.rs b/src/lib.rs index 872cd9e..4f423ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,6 +138,8 @@ use bdk::{FeeRate, KeychainKind, Wallet}; /// # Example /// /// ``` +/// # #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +/// # { /// # use bdk::bitcoin::Network; /// # use structopt::StructOpt; /// # use bdk_cli::{CliOpts, WalletOpts, CliSubCommand, WalletSubCommand}; @@ -174,8 +176,8 @@ use bdk::{FeeRate, KeychainKind, Wallet}; /// }, /// #[cfg(feature = "esplora")] /// esplora_opts: EsploraOpts { -/// esplora: None, -/// esplora_concurrency: 4, +/// server: "https://blockstream.info/api/".to_string(), +/// concurrency: 4, /// }, /// #[cfg(feature = "compact_filters")] /// compactfilter_opts: CompactFilterOpts{ @@ -197,6 +199,7 @@ use bdk::{FeeRate, KeychainKind, Wallet}; /// }; /// /// assert_eq!(expected_cli_opts, cli_opts); +/// # } /// ``` #[derive(Debug, StructOpt, Clone, PartialEq)] #[structopt(name = "BDK CLI", @@ -268,6 +271,7 @@ pub enum CliSubCommand { /// client and network connection and an [`OfflineWalletSubCommand`] does not. #[derive(Debug, StructOpt, Clone, PartialEq)] pub enum WalletSubCommand { + #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] #[structopt(flatten)] OnlineWalletSubCommand(OnlineWalletSubCommand), #[structopt(flatten)] @@ -315,8 +319,8 @@ pub enum WalletSubCommand { /// }, /// #[cfg(feature = "esplora")] /// esplora_opts: EsploraOpts { -/// esplora: None, -/// esplora_concurrency: 4, +/// server: "https://blockstream.info/api/".to_string(), +/// concurrency: 4, /// }, /// #[cfg(feature = "compact_filters")] /// compactfilter_opts: CompactFilterOpts{ @@ -431,7 +435,7 @@ pub struct ElectrumOpts { pub timeout: Option, /// Sets the Electrum server to use #[structopt( - name = "SERVER:PORT", + name = "ELECTRUM_URL", short = "s", long = "server", default_value = "ssl://electrum.blockstream.info:60002" @@ -446,15 +450,20 @@ pub struct ElectrumOpts { #[derive(Debug, StructOpt, Clone, PartialEq)] pub struct EsploraOpts { /// Use the esplora server if given as parameter - #[structopt(name = "ESPLORA_URL", short = "e", long = "esplora")] - pub esplora: Option, + #[structopt( + name = "ESPLORA_URL", + short = "s", + long = "server", + default_value = "https://blockstream.info/api/" + )] + pub server: String, /// Concurrency of requests made to the esplora server #[structopt( name = "ESPLORA_CONCURRENCY", - long = "esplora_concurrency", + long = "concurrency", default_value = "4" )] - pub esplora_concurrency: u8, + pub concurrency: u8, } // This is a workaround for `structopt` issue #333, #391, #418; see https://github.com/TeXitoi/structopt/issues/333#issuecomment-712265332 @@ -1064,6 +1073,7 @@ mod test { #[cfg(feature = "esplora")] use crate::EsploraOpts; use crate::OfflineWalletSubCommand::{CreateTx, GetNewAddress}; + #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] use crate::OnlineWalletSubCommand::{Broadcast, Sync}; #[cfg(any(feature = "compact_filters", feature = "electrum"))] use crate::ProxyOpts; @@ -1098,8 +1108,8 @@ mod test { }, #[cfg(feature = "esplora")] esplora_opts: EsploraOpts { - esplora: None, - esplora_concurrency: 4 + server: "https://blockstream.info/api/".to_string(), + concurrency: 4 }, #[cfg(feature = "compact_filters")] compactfilter_opts: CompactFilterOpts{ @@ -1148,8 +1158,8 @@ mod test { }, #[cfg(feature = "esplora")] esplora_opts: EsploraOpts { - esplora: None, - esplora_concurrency: 4, + server: "https://blockstream.info/api/".to_string(), + concurrency: 4, }, #[cfg(feature = "compact_filters")] compactfilter_opts: CompactFilterOpts{ @@ -1177,8 +1187,8 @@ mod test { let cli_args = vec!["bdk-cli", "--network", "bitcoin", "wallet", "--descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)", "--change_descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)", - "--esplora", "https://blockstream.info/api/", - "--esplora_concurrency", "5", + "--server", "https://blockstream.info/api/", + "--concurrency", "5", "get_new_address"]; let cli_opts = CliOpts::from_iter(&cli_args); @@ -1198,8 +1208,8 @@ mod test { }, #[cfg(feature = "esplora")] esplora_opts: EsploraOpts { - esplora: Some("https://blockstream.info/api/".to_string()), - esplora_concurrency: 5, + server: "https://blockstream.info/api/".to_string(), + concurrency: 5, }, #[cfg(feature = "compact_filters")] compactfilter_opts: CompactFilterOpts{ @@ -1251,8 +1261,8 @@ mod test { }, #[cfg(feature = "esplora")] esplora_opts: EsploraOpts { - esplora: None, - esplora_concurrency: 4, + server: "https://blockstream.info/api/".to_string(), + concurrency: 4, }, #[cfg(feature = "compact_filters")] compactfilter_opts: CompactFilterOpts{ @@ -1274,6 +1284,7 @@ mod test { assert_eq!(expected_cli_opts, cli_opts); } + #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] #[test] fn test_parse_wallet_sync() { let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet", @@ -1297,8 +1308,8 @@ mod test { }, #[cfg(feature = "esplora")] esplora_opts: EsploraOpts { - esplora: None, - esplora_concurrency: 4, + server: "https://blockstream.info/api/".to_string(), + concurrency: 4, }, #[cfg(feature = "compact_filters")] compactfilter_opts: CompactFilterOpts{ @@ -1363,8 +1374,8 @@ mod test { }, #[cfg(feature = "esplora")] esplora_opts: EsploraOpts { - esplora: None, - esplora_concurrency: 4, + server: "https://blockstream.info/api/".to_string(), + concurrency: 4, }, #[cfg(feature = "compact_filters")] compactfilter_opts: CompactFilterOpts{ @@ -1396,6 +1407,7 @@ mod test { assert_eq!(expected_cli_opts, cli_opts); } + #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] #[test] fn test_parse_wallet_broadcast() { let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet", @@ -1420,8 +1432,8 @@ mod test { }, #[cfg(feature = "esplora")] esplora_opts: EsploraOpts { - esplora: None, - esplora_concurrency: 4, + server: "https://blockstream.info/api/".to_string(), + concurrency: 4, }, #[cfg(feature = "compact_filters")] compactfilter_opts: CompactFilterOpts{