From: rajarshimaitra Date: Fri, 13 Aug 2021 11:09:54 +0000 (+0530) Subject: Add RPC backend X-Git-Tag: v0.3.0~8 X-Git-Url: http://internal-gitweb-vhost/script/%22https:/database/enum.FromScriptError.html?a=commitdiff_plain;h=a1e30369df6258e01521d6144b448e4b9676a2e2;p=bdk-cli Add RPC backend Expose the RPC backend feature via cli arg options. RPC backend can be connected via all default parameters without specifying any arg options. --- diff --git a/Cargo.lock b/Cargo.lock index 25888a1..aa5a6c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,6 +78,16 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] + [[package]] name = "base64" version = "0.10.1" @@ -117,12 +127,13 @@ dependencies = [ "async-trait", "bdk-macros 0.6.0", "bitcoin", + "bitcoincore-rpc", "cc", "electrum-client", "futures", "js-sys", "lazy_static", - "log", + "log 0.4.14", "miniscript", "rand 0.7.3", "reqwest", @@ -146,7 +157,7 @@ dependencies = [ "clap", "dirs-next 2.0.0", "env_logger", - "log", + "log 0.4.14", "regex", "rustyline", "serde_json", @@ -223,6 +234,31 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoincore-rpc" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d708433972bf78bd5f909d1d288f9ac1cceeab1460edb954e962f83e1f440a3" +dependencies = [ + "bitcoincore-rpc-json", + "jsonrpc", + "log 0.4.14", + "serde", + "serde_json", +] + +[[package]] +name = "bitcoincore-rpc-json" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977e55a945ab1e3c446dea93267876703c15e07c7d6eeb1dfa1766b3190c560f" +dependencies = [ + "bitcoin", + "hex", + "serde", + "serde_json", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -459,8 +495,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd12f125852d77980725243b2a8b3bea73cd4c7a22c33bc52b08b664c561dc7" dependencies = [ "bitcoin", - "log", - "rustls 0.16.0", + "log 0.4.14", + "rustls", "serde", "serde_json", "socks", @@ -485,7 +521,7 @@ checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", "humantime", - "log", + "log 0.4.14", "regex", "termcolor", ] @@ -546,7 +582,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", - "percent-encoding", + "percent-encoding 2.1.0", ] [[package]] @@ -756,6 +792,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" + [[package]] name = "hmac" version = "0.7.1" @@ -846,6 +888,17 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.2.3" @@ -906,6 +959,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonrpc" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436f3455a8a4e9c7b14de9f1206198ee5d0bdc2db1b560339d2141093d7dd389" +dependencies = [ + "hyper 0.10.16", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" + [[package]] name = "lazy_static" version = "1.4.0" @@ -955,6 +1026,15 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +dependencies = [ + "log 0.4.14", +] + [[package]] name = "log" version = "0.4.14" @@ -1072,7 +1152,7 @@ dependencies = [ "bitvec", "funty", "memchr", - "version_check", + "version_check 0.9.3", ] [[package]] @@ -1179,6 +1259,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1219,7 +1305,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "version_check", + "version_check 0.9.3", ] [[package]] @@ -1230,7 +1316,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", - "version_check", + "version_check 0.9.3", ] [[package]] @@ -1481,7 +1567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" dependencies = [ "base64 0.10.1", - "log", + "log 0.4.14", "ring", "sct", "webpki", @@ -1509,7 +1595,7 @@ dependencies = [ "cfg-if 0.1.10", "dirs-next 1.0.2", "libc", - "log", + "log 0.4.14", "memchr", "nix", "scopeguard", @@ -1672,7 +1758,7 @@ dependencies = [ "fs2", "fxhash", "libc", - "log", + "log 0.4.14", "parking_lot", ] @@ -1827,6 +1913,16 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi 0.3.9", +] + [[package]] name = "tiny-bip39" version = "0.7.3" @@ -1953,6 +2049,12 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" +[[package]] +name = "unicode-bidi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -2005,6 +2107,17 @@ dependencies = [ "webpki-roots 0.21.1", ] +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", +] + [[package]] name = "url" version = "2.2.2" @@ -2012,9 +2125,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", - "idna", + "idna 0.2.3", "matches", - "percent-encoding", + "percent-encoding 2.1.0", ] [[package]] @@ -2035,6 +2148,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + [[package]] name = "version_check" version = "0.9.3" @@ -2083,7 +2202,7 @@ checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", - "log", + "log 0.4.14", "proc-macro2", "quote", "syn", diff --git a/Cargo.toml b/Cargo.toml index 872e30c..a159428 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ esplora-ureq = ["esplora", "bdk/use-esplora-ureq"] esplora-reqwest = ["esplora", "bdk/use-esplora-reqwest"] compiler = ["bdk/compiler"] compact_filters = ["bdk/compact_filters"] +rpc = ["bdk/rpc"] [[bin]] name = "bdk-cli" diff --git a/src/bdk_cli.rs b/src/bdk_cli.rs index b11cb31..4c39ff9 100644 --- a/src/bdk_cli.rs +++ b/src/bdk_cli.rs @@ -25,6 +25,8 @@ use std::fs; use std::path::PathBuf; +#[cfg(feature = "rpc")] +use bitcoin::secp256k1::Secp256k1; use bitcoin::Network; use clap::AppSettings; use log::{debug, error, info, warn}; @@ -43,9 +45,17 @@ use bdk::blockchain::electrum::ElectrumBlockchainConfig; #[cfg(feature = "esplora")] use bdk::blockchain::esplora::EsploraBlockchainConfig; -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] use bdk::blockchain::{AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain}; +#[cfg(feature = "rpc")] +use bdk::blockchain::rpc::{wallet_name_from_descriptor, Auth, RpcConfig}; + use bdk::database::BatchDatabase; use bdk::sled; use bdk::sled::Tree; @@ -54,7 +64,12 @@ use bdk::{bitcoin, Error}; use bdk_cli::WalletSubCommand; use bdk_cli::{CliOpts, CliSubCommand, KeySubCommand, OfflineWalletSubCommand, WalletOpts}; -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] use bdk_cli::OnlineWalletSubCommand; #[cfg(feature = "repl")] @@ -69,7 +84,12 @@ 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"))] + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" + ))] #[structopt(flatten)] OnlineWalletSubCommand(OnlineWalletSubCommand), #[structopt(flatten)] @@ -107,7 +127,12 @@ fn open_database(wallet_opts: &WalletOpts) -> Tree { tree } -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] fn new_online_wallet( network: Network, wallet_opts: &WalletOpts, @@ -163,6 +188,34 @@ where }) }; + #[cfg(feature = "rpc")] + let config: AnyBlockchainConfig = { + let auth = Auth::UserPass { + username: wallet_opts.rpc_opts.auth.0.clone(), + password: wallet_opts.rpc_opts.auth.1.clone(), + }; + + // Use deterministic wallet name derived from descriptor + let wallet_name = wallet_name_from_descriptor( + &wallet_opts.descriptor[..], + wallet_opts.change_descriptor.as_deref(), + network, + &Secp256k1::new(), + )?; + + let mut rpc_url = "http://".to_string(); + rpc_url.push_str(&wallet_opts.rpc_opts.address[..]); + + let rpc_config = RpcConfig { + url: rpc_url, + auth, + network, + wallet_name, + skip_blocks: wallet_opts.rpc_opts.skip_blocks, + }; + + AnyBlockchainConfig::Rpc(rpc_config) + }; let descriptor = wallet_opts.descriptor.as_str(); let change_descriptor = wallet_opts.change_descriptor.as_deref(); @@ -214,7 +267,12 @@ 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"))] + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" + ))] CliSubCommand::Wallet { wallet_opts, subcommand: WalletSubCommand::OnlineWalletSubCommand(online_subcommand), @@ -255,13 +313,19 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result CliSubCommand::Repl { wallet_opts } => { let database = open_database(&wallet_opts); - #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" + ))] let wallet = new_online_wallet(network, &wallet_opts, database)?; #[cfg(not(any( feature = "electrum", feature = "esplora", - feature = "compact_filters" + feature = "compact_filters", + feature = "rpc" )))] let wallet = new_offline_wallet(network, &wallet_opts, database)?; @@ -307,7 +371,8 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result #[cfg(any( feature = "electrum", feature = "esplora", - feature = "compact_filters" + feature = "compact_filters", + feature = "rpc" ))] ReplSubCommand::OnlineWalletSubCommand(online_subcommand) => { bdk_cli::handle_online_wallet_subcommand(&wallet, online_subcommand) diff --git a/src/lib.rs b/src/lib.rs index bd1ce48..bd8d04b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,7 +99,12 @@ pub extern crate bdk; #[macro_use] extern crate serde_json; -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] #[macro_use] extern crate bdk_macros; @@ -110,16 +115,31 @@ pub use structopt; use structopt::StructOpt; use crate::OfflineWalletSubCommand::*; -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] use crate::OnlineWalletSubCommand::*; use bdk::bitcoin::consensus::encode::{deserialize, serialize, serialize_hex}; -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] use bdk::bitcoin::hashes::hex::FromHex; use bdk::bitcoin::secp256k1::Secp256k1; use bdk::bitcoin::util::bip32::{DerivationPath, ExtendedPrivKey, KeySource}; use bdk::bitcoin::util::psbt::PartiallySignedTransaction; use bdk::bitcoin::{Address, Network, OutPoint, Script, Txid}; -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] use bdk::blockchain::{log_progress, Blockchain}; use bdk::database::BatchDatabase; use bdk::descriptor::Segwitv0; @@ -144,7 +164,7 @@ use bdk::{FeeRate, KeychainKind, Wallet}; /// # Example /// /// ``` -/// # #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +/// # #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters", feature = "rpc"))] /// # { /// # use bdk::bitcoin::Network; /// # use structopt::StructOpt; @@ -153,6 +173,8 @@ use bdk::{FeeRate, KeychainKind, Wallet}; /// # use bdk_cli::ElectrumOpts; /// # #[cfg(feature = "esplora")] /// # use bdk_cli::EsploraOpts; +/// # #[cfg(feature = "rpc")] +/// # use bdk_cli::RpcOpts; /// # #[cfg(feature = "compact_filters")] /// # use bdk_cli::CompactFilterOpts; /// # #[cfg(any(feature = "compact_filters", feature = "electrum", feature="esplora"))] @@ -194,6 +216,12 @@ use bdk::{FeeRate, KeychainKind, Wallet}; /// conc: 4, /// stop_gap: 10 /// }, +/// #[cfg(feature = "rpc")] +/// rpc_opts: RpcOpts{ +/// address: "127.0.0.1:18443".to_string(), +/// auth: ("user".to_string(), "password".to_string()), +/// skip_blocks: None, +/// }, /// #[cfg(feature = "compact_filters")] /// compactfilter_opts: CompactFilterOpts{ /// address: vec!["127.0.0.1:18444".to_string()], @@ -216,6 +244,7 @@ use bdk::{FeeRate, KeychainKind, Wallet}; /// assert_eq!(expected_cli_opts, cli_opts); /// # } /// ``` + #[derive(Debug, StructOpt, Clone, PartialEq)] #[structopt(name = "BDK CLI", version = option_env ! ("CARGO_PKG_VERSION").unwrap_or("unknown"), @@ -287,7 +316,12 @@ 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"))] + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" + ))] #[structopt(flatten)] OnlineWalletSubCommand(OnlineWalletSubCommand), #[structopt(flatten)] @@ -312,6 +346,8 @@ pub enum WalletSubCommand { /// # use bdk_cli::EsploraOpts; /// # #[cfg(feature = "compact_filters")] /// # use bdk_cli::CompactFilterOpts; +/// # #[cfg(feature = "rpc")] +/// # use bdk_cli::RpcOpts; /// # #[cfg(any(feature = "compact_filters", feature = "electrum", feature="esplora"))] /// # use bdk_cli::ProxyOpts; /// @@ -353,6 +389,12 @@ pub enum WalletSubCommand { /// conn_count: 4, /// skip_blocks: 0, /// }, +/// #[cfg(feature = "rpc")] +/// rpc_opts: RpcOpts{ +/// address: "127.0.0.1:18443".to_string(), +/// auth: ("user".to_string(), "password".to_string()), +/// skip_blocks: None, +/// }, /// #[cfg(any(feature="compact_filters", feature="electrum", feature="esplora"))] /// proxy_opts: ProxyOpts{ /// proxy: None, @@ -363,6 +405,7 @@ pub enum WalletSubCommand { /// /// assert_eq!(expected_wallet_opts, wallet_opts); /// ``` + #[derive(Debug, StructOpt, Clone, PartialEq)] pub struct WalletOpts { /// Selects the wallet to use @@ -391,6 +434,9 @@ pub struct WalletOpts { #[cfg(feature = "compact_filters")] #[structopt(flatten)] pub compactfilter_opts: CompactFilterOpts, + #[cfg(feature = "rpc")] + #[structopt(flatten)] + pub rpc_opts: RpcOpts, #[cfg(any(feature = "compact_filters", feature = "electrum", feature = "esplora"))] #[structopt(flatten)] pub proxy_opts: ProxyOpts, @@ -449,6 +495,33 @@ pub struct CompactFilterOpts { pub skip_blocks: usize, } +#[cfg(feature = "rpc")] +#[derive(Debug, StructOpt, Clone, PartialEq)] +pub struct RpcOpts { + /// Sets the full node address for rpc connection + #[structopt( + name = "ADDRESS:PORT", + short = "n", + long = "node", + default_value = "127.0.0.1:18443" + )] + pub address: String, + + /// Sets the rpc authentication username:password + #[structopt( + name = "USER:PASSWD", + short = "a", + long = "auth", + parse(try_from_str = parse_proxy_auth), + default_value = "user:password", + )] + pub auth: (String, String), + + /// Optionally skip initial `skip_blocks` blocks + #[structopt(name = "SKIP_BLOCKS", short = "s", long = "skip-blocks")] + pub skip_blocks: Option, +} + /// Electrum options /// /// Electrum blockchain client information used by [`OnlineWalletSubCommand`]s. @@ -704,7 +777,12 @@ blockchain client and network connection. )] #[derive(Debug, StructOpt, Clone, PartialEq)] #[structopt(rename_all = "snake")] -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] pub enum OnlineWalletSubCommand { /// Syncs with the chosen blockchain server Sync { @@ -750,8 +828,12 @@ fn parse_recipient(s: &str) -> Result<(Script, u64), String> { Ok((addr.unwrap().script_pubkey(), val.unwrap())) } - -#[cfg(any(feature = "electrum", feature = "compact_filters", feature = "esplora"))] +#[cfg(any( + feature = "electrum", + feature = "compact_filters", + feature = "esplora", + feature = "rpc" +))] fn parse_proxy_auth(s: &str) -> Result<(String, String), String> { let parts: Vec<_> = s.split(':').collect(); if parts.len() != 2 { @@ -959,7 +1041,12 @@ where /// /// Online wallet sub-commands are described in [`OnlineWalletSubCommand`]. See [`crate`] for /// example usage. -#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" +))] #[maybe_async] pub fn handle_online_wallet_subcommand( wallet: &Wallet, @@ -1144,10 +1231,17 @@ mod test { #[cfg(feature = "esplora")] use crate::EsploraOpts; use crate::OfflineWalletSubCommand::{CreateTx, GetNewAddress}; - #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" + ))] use crate::OnlineWalletSubCommand::{Broadcast, Sync}; #[cfg(any(feature = "compact_filters", feature = "electrum", feature = "esplora"))] use crate::ProxyOpts; + #[cfg(feature = "rpc")] + use crate::RpcOpts; use crate::{handle_key_subcommand, CliSubCommand, KeySubCommand, WalletSubCommand}; use bdk::bitcoin::util::bip32::{DerivationPath, ExtendedPrivKey}; @@ -1203,7 +1297,13 @@ mod test { proxy: None, proxy_auth: None, retries: 5, - } + }, + #[cfg(feature = "rpc")] + rpc_opts: RpcOpts { + address: "127.0.0.1:18443".to_string(), + auth: ("user".to_string(), "password".to_string()), + skip_blocks: None, + }, }, subcommand: WalletSubCommand::OfflineWalletSubCommand(GetNewAddress), }, @@ -1242,6 +1342,12 @@ mod test { proxy: Some("127.0.0.1:9150".to_string()), proxy_auth: None, retries: 3, + }, + #[cfg(feature = "rpc")] + rpc_opts: RpcOpts { + address: "127.0.0.1:18443".to_string(), + auth: ("user".to_string(), "password".to_string()), + skip_blocks: None, } }, subcommand: WalletSubCommand::OfflineWalletSubCommand(GetNewAddress), @@ -1331,6 +1437,63 @@ mod test { assert_eq!(expected_cli_opts, cli_opts); } + #[cfg(feature = "rpc")] + #[test] + fn test_parse_wallet_rpc() { + let cli_args = vec!["bdk-cli", "--network", "bitcoin", "wallet", + "--descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)", + "--change_descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)", + "--node", "125.67.89.101:56678", + "--auth", "user:password", + "--skip-blocks", "5", + "get_new_address"]; + + let cli_opts = CliOpts::from_iter(&cli_args); + + let expected_cli_opts = CliOpts { + network: Network::Bitcoin, + subcommand: CliSubCommand::Wallet { + wallet_opts: WalletOpts { + wallet: "main".to_string(), + verbose: false, + descriptor: "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(), + change_descriptor: Some("wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)".to_string()), + #[cfg(feature = "electrum")] + electrum_opts: ElectrumOpts { + timeout: None, + server: "ssl://electrum.blockstream.info:60002".to_string(), + }, + #[cfg(feature = "esplora")] + esplora_opts: EsploraOpts { + server: "https://blockstream.info/api/".to_string(), + concurrency: 5, + }, + #[cfg(feature = "compact_filters")] + compactfilter_opts: CompactFilterOpts{ + address: vec!["127.0.0.1:18444".to_string()], + skip_blocks: 0, + conn_count: 4, + }, + #[cfg(any(feature="compact_filters", feature="electrum"))] + proxy_opts: ProxyOpts{ + proxy: None, + proxy_auth: None, + retries: 5, + }, + #[cfg(feature = "rpc")] + rpc_opts: RpcOpts { + address: "125.67.89.101:56678".to_string(), + auth: ("user".to_string(), "password".to_string()), + skip_blocks: Some(5), + }, + }, + subcommand: WalletSubCommand::OfflineWalletSubCommand(GetNewAddress), + }, + }; + + assert_eq!(expected_cli_opts, cli_opts); + } + #[cfg(feature = "compact_filters")] #[test] fn test_parse_wallet_compact_filters() { @@ -1372,7 +1535,12 @@ mod test { assert_eq!(expected_cli_opts, cli_opts); } - #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" + ))] #[test] fn test_parse_wallet_sync() { let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet", @@ -1419,7 +1587,13 @@ mod test { proxy: None, proxy_auth: None, retries: 5, - } + }, + #[cfg(feature = "rpc")] + rpc_opts: RpcOpts { + address: "127.0.0.1:18443".to_string(), + auth: ("user".to_string(), "password".to_string()), + skip_blocks: None, + }, }, subcommand: WalletSubCommand::OnlineWalletSubCommand(Sync { max_addresses: Some(50) @@ -1494,7 +1668,13 @@ mod test { proxy: None, proxy_auth: None, retries: 5, - } + }, + #[cfg(feature = "rpc")] + rpc_opts: RpcOpts { + address: "127.0.0.1:18443".to_string(), + auth: ("user".to_string(), "password".to_string()), + skip_blocks: None, + }, }, subcommand: WalletSubCommand::OfflineWalletSubCommand(CreateTx { recipients: vec![(script1, 123456), (script2, 78910)], @@ -1513,7 +1693,12 @@ mod test { assert_eq!(expected_cli_opts, cli_opts); } - #[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))] + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "compact_filters", + feature = "rpc" + ))] #[test] fn test_parse_wallet_broadcast() { let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet", @@ -1561,7 +1746,13 @@ mod test { proxy: None, proxy_auth: None, retries: 5, - } + }, + #[cfg(feature = "rpc")] + rpc_opts: RpcOpts { + address: "127.0.0.1:18443".to_string(), + auth: ("user".to_string(), "password".to_string()), + skip_blocks: None, + }, }, subcommand: WalletSubCommand::OnlineWalletSubCommand(Broadcast { psbt: Some("cHNidP8BAEICAAAAASWhGE1AhvtO+2GjJHopssFmgfbq+WweHd8zN/DeaqmDAAAAAAD/////AQAAAAAAAAAABmoEAAECAwAAAAAAAAA=".to_string()),