]> Untitled Git - bdk-cli/commitdiff
feat: re-enable `rpc` feature
authorVihiga Tyonum <withtvpeter@gmail.com>
Wed, 5 Mar 2025 08:57:32 +0000 (09:57 +0100)
committerVihiga Tyonum <withtvpeter@gmail.com>
Thu, 6 Mar 2025 14:47:45 +0000 (15:47 +0100)
- re-enable `rpc` feature

.github/workflows/code_coverage.yml
.github/workflows/cont_integration.yml
Cargo.toml
ci/test_features.sh
src/commands.rs
src/handlers.rs
src/utils.rs
tests/integration.rs

index dad6ffd30ca02eef4178f7fb8af6c9f632f8f485..bc031aec5cad3f5839759cdea1990eb9848ef309 100644 (file)
@@ -39,8 +39,8 @@ jobs:
       #- name: Test Compact Filters
       #  run: cargo test --features compact_filters
 
-      - name: Test RPC
-        run: cargo test --features rpc
+      - name: Test RPC
+        run: cargo test --features rpc
 
       - id: coverage
         name: Generate coverage
index c4e87354cf636af14d8638b5b82798070bfe4adb..8c0dbe1f98cc2aedbee2b73fcf4cfc0bd385fe96 100644 (file)
@@ -20,6 +20,8 @@ jobs:
           - esplora
           - compiler,sqlite
           - compiler
+          - rpc
+          - verify rpc
           - verify   
           - verify esplora 
           - verify esplora compiler
index 1b0e7e19baffc753a5ccfeda7fddd5772d70746c..e1fe7425df6b4977a0d5ee58b79f9938ed3ebd65 100644 (file)
@@ -12,7 +12,7 @@ readme = "README.md"
 license = "MIT"
 
 [dependencies]
-bdk_wallet = { version = "1.0.0", features = ["rusqlite", "keys-bip39", "compiler"] }
+bdk_wallet = { version = "1.0.0", features = ["rusqlite", "keys-bip39", "compiler", "std"] }
 clap = { version = "4.5", features = ["derive","env"] }
 dirs = {  version = "6.0.0" }
 env_logger = "0.11.6"
@@ -41,7 +41,7 @@ sqlite = ["bdk_wallet/rusqlite"]
 cbf = ["bdk_kyoto"]
 electrum = ["bdk_electrum"]
 esplora = ["bdk_esplora"]
-# rpc = ["bdk_bitcoind_rpc"] temporarily disabled
+rpc = ["bdk_bitcoind_rpc"] 
 
 # Use this to consensus verify transactions at sync time
 verify = []
index caf67c90b9cd832a5f109402aa4edf878f40e836..74078182210313ffbf2d7eb177de75b4dbb0be02 100755 (executable)
@@ -6,6 +6,7 @@ feature_combinations=(
     "sqlite"
     "electrum"
     "esplora"
+    "rpc"
     "verify"
     "compiler"
     "repl sqlite"
@@ -13,14 +14,21 @@ feature_combinations=(
     "repl esplora"
     "repl verify"
     "repl compiler"
+    "repl rpc"
+    "verify rpc"
     "sqlite electrum"
     "sqlite esplora"
     "sqlite verify"
     "sqlite compiler"
+    "rpc esplora"
+    "rpc electrum"
     "verify esplora compiler"
     "verify esplora repl"
     "verify compiler repl"
     "verify esplora compiler repl"
+    "rpc esplora compiler"
+    "rpc compiler electrum"
+    "sqlite rpc compiler"
 )
 
 for features in "${feature_combinations[@]}"; do
index 7659d2c4ed6e87f20668c0ae28d6996b964f70c4..9d22a792ac098aa5fb61ef4fa010cea1579941d1 100644 (file)
@@ -133,13 +133,15 @@ pub enum DatabaseType {
     Sqlite,
 }
 
-#[cfg(any(feature = "electrum", feature = "esplora",))]
+#[cfg(any(feature = "electrum", feature = "esplora", feature = "rpc"))]
 #[derive(Clone, ValueEnum, Debug, Eq, PartialEq)]
 pub enum ClientType {
     #[cfg(feature = "electrum")]
     Electrum,
     #[cfg(feature = "esplora")]
     Esplora,
+    #[cfg(feature = "rpc")]
+    RPC,
 }
 
 /// Config options wallet operations can take.
@@ -157,22 +159,22 @@ pub struct WalletOpts {
     /// Sets the descriptor to use for internal/change addresses.
     #[arg(env = "INT_DESCRIPTOR", short = 'i', long)]
     pub int_descriptor: Option<String>,
-    #[cfg(any(feature = "electrum", feature = "esplora",))]
+    #[cfg(any(feature = "electrum", feature = "esplora", feature = "rpc"))]
     #[arg(env = "CLIENT_TYPE", short = 'c', long, value_enum, required = true)]
     pub client_type: ClientType,
     #[cfg(any(feature = "sqlite",))]
     #[arg(env = "DATABASE_TYPE", short = 'd', long, value_enum, required = true)]
     pub database_type: DatabaseType,
     /// Sets the server url.
-    #[cfg(any(feature = "electrum", feature = "esplora",))]
+    #[cfg(any(feature = "electrum", feature = "esplora", feature = "rpc"))]
     #[arg(env = "SERVER_URL", short = 'u', long, required = true)]
     pub url: String,
     /// Electrum batch size.
-    #[cfg(any(feature = "electrum"))]
+    #[cfg(feature = "electrum")]
     #[arg(env = "ELECTRUM_BATCH_SIZE", short = 'b', long, default_value = "10")]
     pub batch_size: usize,
     /// Esplora parallel requests.
-    #[cfg(any(feature = "esplora"))]
+    #[cfg(feature = "esplora")]
     #[arg(
         env = "ESPLORA_PARALLEL_REQUESTS",
         short = 'p',
@@ -180,6 +182,21 @@ pub struct WalletOpts {
         default_value = "5"
     )]
     pub parallel_requests: usize,
+    #[cfg(feature = "rpc")]
+    /// Sets the rpc basic authentication.
+    #[arg(
+        env = "USER:PASSWD",
+        short = 'a',
+        long,
+        value_parser = parse_proxy_auth,
+        default_value = "user:password",
+    )]
+    pub basic_auth: (String, String),
+
+    #[cfg(feature = "rpc")]
+    /// Sets an optional cookie authentication.
+    #[arg(name = "COOKIE", long)]
+    pub cookie: Option<String>
 }
 
 /// Options to configure a SOCKS5 proxy for a blockchain client connection.
@@ -234,77 +251,6 @@ pub struct CompactFilterOpts {
     pub skip_blocks: usize,
 }
 
-/// Options to configure a bitcoin core rpc backend.
-#[cfg(feature = "rpc")]
-#[derive(Debug, Args, Clone, PartialEq, Eq)]
-pub struct RpcOpts {
-    /// Sets the full node address for rpc connection.
-    #[arg(
-        env = "ADDRESS:PORT",
-        long = "rpc-node",
-        default_value = "127.0.0.1:18443"
-    )]
-    pub address: String,
-
-    /// Sets the rpc basic authentication.
-    #[arg(
-        env = "USER:PASSWD",
-        short = 'a',
-        long = "rpc-basic-auth",
-        value_parser = parse_proxy_auth,
-        default_value = "user:password",
-    )]
-    pub basic_auth: (String, String),
-
-    /// Sets an optional cookie authentication.
-    #[arg(name = "COOKIE", short = 'c', long = "rpc-cookie")]
-    pub cookie: Option<String>,
-
-    /// Time in unix seconds in which initial sync will start scanning from (0 to start from genesis).
-    #[arg(env = "RPC_START_TIME", long = "rpc-start-time", default_value = "0")]
-    pub start_time: u64,
-}
-
-/// Options to configure electrum backend.
-#[cfg(feature = "electrum")]
-#[derive(Debug, Args, Clone, PartialEq, Eq)]
-pub struct ElectrumOpts {
-    /// Sets the Electrum server to use.
-    #[arg(
-        env = "ELECTRUM_URL",
-        short = 'e',
-        long = "electrum",
-        default_value = "ssl://electrum.blockstream.info:60002"
-    )]
-    pub server: String,
-
-    /// Stop searching addresses for transactions after finding an unused gap of this length.
-    #[arg(env = "ELECTRUM_BATCH_SIZE", long = "batch_size", default_value = "10")]
-    pub batch_size: usize,
-}
-
-/// Options to configure Esplora backend.
-#[cfg(feature = "esplora")]
-#[derive(Debug, Args, Clone, PartialEq, Eq)]
-pub struct EsploraOpts {
-    /// Use the esplora server if given as parameter.
-    #[arg(
-        env = "ESPLORA_URL",
-        short = 's',
-        long = "esplora",
-        default_value = "https://blockstream.info/testnet/api/"
-    )]
-    pub server: String,
-
-    /// Socket timeout.
-    #[arg(env = "TIMEOUT", long = "timeout", default_value = "5")]
-    pub timeout: u64,
-
-    /// Number of parallel requests sent to the esplora service.
-    #[arg(env = "CONCURRENCY", long = "esplora-conc", default_value = "4")]
-    pub conc: u8,
-}
-
 /// Wallet subcommands that can be issued without a blockchain backend.
 #[derive(Debug, Subcommand, Clone, PartialEq)]
 #[command(rename_all = "snake")]
@@ -529,1065 +475,3 @@ pub enum ReplSubCommand {
     /// Exit REPL loop.
     Exit,
 }
-
-// #[cfg(test)]
-// mod test {
-//     use super::*;
-//     #[cfg(feature = "compiler")]
-//     use crate::handlers::handle_compile_subcommand;
-//     use crate::handlers::handle_key_subcommand;
-//     use bdk_wallet::bitcoin::bip32::{DerivationPath, Xpriv};
-//     use bdk_wallet::bitcoin::{Address, Network, OutPoint};
-//     use bdk_wallet::miniscript::bitcoin::network::Network::Testnet;
-//     use std::str::{self, FromStr};
-//
-//     use super::OfflineWalletSubCommand::{BumpFee, CreateTx, GetNewAddress};
-//     #[cfg(any(
-//         feature = "electrum",
-//         feature = "esplora",
-//         feature = "cbf",
-//         feature = "rpc"
-//     ))]
-//     use super::OnlineWalletSubCommand::{Broadcast, Sync};
-//     use super::WalletSubCommand::OfflineWalletSubCommand;
-//     #[cfg(any(
-//         feature = "electrum",
-//         feature = "esplora",
-//         feature = "cbf",
-//         feature = "rpc"
-//     ))]
-//     use super::WalletSubCommand::OnlineWalletSubCommand;
-//     #[cfg(feature = "repl")]
-//     use regex::Regex;
-//
-//     #[test]
-//     fn test_clap_args() {
-//         use clap::CommandFactory;
-//         CliOpts::command().debug_assert();
-//     }
-//
-//     #[test]
-//     fn test_parse_wallet_get_new_address() {
-//         let cli_args = vec!["bdk-cli", "--network", "bitcoin", "wallet",
-//                             "--descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "--change_descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)",
-//                             "get_new_address"];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Bitcoin,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     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(),
-//                         stop_gap: 10,
-//                     },
-//                     #[cfg(feature = "esplora")]
-//                     esplora_opts: EsploraOpts {
-//                         server: "https://blockstream.info/testnet/api/".to_string(),
-//                         timeout: 5,
-//                         stop_gap: 10,
-//                         conc: 4,
-//                     },
-//                     #[cfg(feature = "cbf")]
-//                     cbf_opts: CompactFilterOpts{
-//                         address: vec!["127.0.0.1:18444".to_string()],
-//                         conn_count: 4,
-//                         skip_blocks: 0,
-//                     },
-//                     #[cfg(any(feature="compact_filters", feature="electrum", feature="esplora"))]
-//                     proxy_opts: ProxyOpts{
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     },
-//                     #[cfg(feature = "rpc")]
-//                     rpc_opts: RpcOpts {
-//                         address: "127.0.0.1:18443".to_string(),
-//                         basic_auth: ("user".to_string(), "password".to_string()),
-//                         cookie: None,
-//                         start_time: 0,
-//                     },
-//                 },
-//                 subcommand: OfflineWalletSubCommand(GetNewAddress),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(feature = "electrum")]
-//     #[test]
-//     fn test_parse_wallet_electrum() {
-//         let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet",
-//                             "--proxy", "127.0.0.1:9150", "--retries", "3", "--timeout", "10",
-//                             "--descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "--change_descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)",
-//                             "--server","ssl://electrum.blockstream.info:50002",
-//                             "--stop_gap", "20",
-//                             "get_new_address"];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Testnet,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(),
-//                     change_descriptor: Some("wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)".to_string()),
-//                     electrum_opts: ElectrumOpts {
-//                         timeout: Some(10),
-//                         server: "ssl://electrum.blockstream.info:50002".to_string(),
-//                         stop_gap: 20
-//                     },
-//                     proxy_opts: ProxyOpts{
-//                         proxy: Some("127.0.0.1:9150".to_string()),
-//                         proxy_auth: None,
-//                         retries: 3,
-//                     },
-//                 },
-//                 subcommand: OfflineWalletSubCommand(GetNewAddress),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(feature = "esplora")]
-//     #[test]
-//     fn test_parse_wallet_esplora() {
-//         let cli_args = vec!["bdk-cli", "--network", "bitcoin", "wallet",
-//                             "--descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "--change_descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)",
-//                             "--server", "https://blockstream.info/api/",
-//                             "--conc", "10",
-//                             "--stop_gap", "20",
-//                             "get_new_address"];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Bitcoin,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(),
-//                     change_descriptor: Some("wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)".to_string()),
-//                     esplora_opts: EsploraOpts {
-//                         server: "https://blockstream.info/api/".to_string(),
-//                         conc: 10,
-//                         stop_gap: 20,
-//                         timeout: 5,
-//                     },
-//                     proxy_opts: ProxyOpts{
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     }
-//                 },
-//                 subcommand: OfflineWalletSubCommand(GetNewAddress),
-//             },
-//         };
-//
-//         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",
-//                             "--basic-auth", "user:password",
-//                             "--cookie", "/home/user/.bitcoin/regtest/.cookie",
-//                             "--start-time", "123456",
-//                             "get_new_address"];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Bitcoin,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(),
-//                     change_descriptor: Some("wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)".to_string()),
-//                     rpc_opts: RpcOpts {
-//                         address: "125.67.89.101:56678".to_string(),
-//                         basic_auth: ("user".to_string(), "password".to_string()),
-//                         cookie: Some("/home/user/.bitcoin/regtest/.cookie".to_string()),
-//                         start_time: 123456,
-//                     },
-//                 },
-//                 subcommand: OfflineWalletSubCommand(GetNewAddress),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(feature = "cbf")]
-//     #[test]
-//     fn test_parse_wallet_compact_filters() {
-//         let cli_args = vec!["bdk-cli", "--network", "bitcoin", "wallet",
-//                             "--descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "--change_descriptor", "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)",
-//                             "--proxy", "127.0.0.1:9005",
-//                             "--proxy_auth", "random_user:random_passwd",
-//                             "--node", "127.0.0.1:18444",
-//                             "--conn_count", "4",
-//                             "--skip_blocks", "5",
-//                             "get_new_address"];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Bitcoin,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(),
-//                     change_descriptor: Some("wpkh(xpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)".to_string()),
-//                     cbf_opts: CompactFilterOpts{
-//                         address: vec!["127.0.0.1:18444".to_string()],
-//                         conn_count: 4,
-//                         skip_blocks: 5,
-//                     },
-//                     proxy_opts: ProxyOpts{
-//                         proxy: Some("127.0.0.1:9005".to_string()),
-//                         proxy_auth: Some(("random_user".to_string(), "random_passwd".to_string())),
-//                         retries: 5,
-//                     }
-//                 },
-//                 subcommand: OfflineWalletSubCommand(GetNewAddress),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(any(
-//         feature = "electrum",
-//         feature = "esplora",
-//         feature = "cbf",
-//         feature = "rpc"
-//     ))]
-//     #[test]
-//     fn test_parse_wallet_sync() {
-//         let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet",
-//                             "--descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "sync"];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Testnet,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(),
-//                     change_descriptor: None,
-//                     #[cfg(feature = "electrum")]
-//                     electrum_opts: ElectrumOpts {
-//                         timeout: None,
-//                         server: "ssl://electrum.blockstream.info:60002".to_string(),
-//                         stop_gap: 10,
-//                     },
-//                     #[cfg(feature = "esplora")]
-//                     esplora_opts: EsploraOpts {
-//                         server: "https://blockstream.info/testnet/api/".to_string(),
-//                         timeout: 5,
-//                         stop_gap: 10,
-//                         conc: 4,
-//                     },
-//                     #[cfg(feature = "cbf")]
-//                     cbf_opts: CompactFilterOpts{
-//                         address: vec!["127.0.0.1:18444".to_string()],
-//                         conn_count: 4,
-//                         skip_blocks: 0,
-//                     },
-//                     #[cfg(any(feature="compact_filters", feature="electrum", feature="esplora"))]
-//                     proxy_opts: ProxyOpts{
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     },
-//                     #[cfg(feature = "rpc")]
-//                     rpc_opts: RpcOpts {
-//                         address: "127.0.0.1:18443".to_string(),
-//                         basic_auth: ("user".to_string(), "password".to_string()),
-//                         cookie: None,
-//                         start_time: 0,
-//                     },
-//                 },
-//                 subcommand: OnlineWalletSubCommand(Sync),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[test]
-//     fn test_parse_wallet_create_tx() {
-//         let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet",
-//                             "--descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "--change_descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)",
-//                             "create_tx", "--to", "n2Z3YNXtceeJhFkTknVaNjT1mnCGWesykJ:123456", "--to", "mjDZ34icH4V2k9GmC8niCrhzVuR3z8Mgkf:78910",
-//                             "--utxos","87345e46bfd702d24d54890cc094d08a005f773b27c8f965dfe0eb1e23eef88e:1",
-//                             "--utxos","87345e46bfd702d24d54890cc094d08a005f773b27c8f965dfe0eb1e23eef88e:2",
-//                             "--add_string","Hello BDK",
-//                            ];
-//
-//         let cli_opts = CliOpts::parse_from(&cli_args);
-//
-//         let script1 = Address::from_str("n2Z3YNXtceeJhFkTknVaNjT1mnCGWesykJ")
-//             .unwrap()
-//             .assume_checked()
-//             .script_pubkey();
-//
-//         let script2 = Address::from_str("mjDZ34icH4V2k9GmC8niCrhzVuR3z8Mgkf")
-//             .unwrap()
-//             .assume_checked()
-//             .script_pubkey();
-//
-//         let outpoint1 = OutPoint::from_str(
-//             "87345e46bfd702d24d54890cc094d08a005f773b27c8f965dfe0eb1e23eef88e:1",
-//         )
-//         .unwrap();
-//         let outpoint2 = OutPoint::from_str(
-//             "87345e46bfd702d24d54890cc094d08a005f773b27c8f965dfe0eb1e23eef88e:2",
-//         )
-//         .unwrap();
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Testnet,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(),
-//                     change_descriptor: Some("wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)".to_string()),
-//                     #[cfg(feature = "electrum")]
-//                     electrum_opts: ElectrumOpts {
-//                         timeout: None,
-//                         server: "ssl://electrum.blockstream.info:60002".to_string(),
-//                         stop_gap: 10,
-//                     },
-//                     #[cfg(feature = "esplora")]
-//                     esplora_opts: EsploraOpts {
-//                         server: "https://blockstream.info/testnet/api/".to_string(),
-//                         timeout: 5,
-//                         stop_gap: 10,
-//                         conc: 4,
-//                     },
-//                     #[cfg(feature = "cbf")]
-//                     cbf_opts: CompactFilterOpts{
-//                         address: vec!["127.0.0.1:18444".to_string()],
-//                         conn_count: 4,
-//                         skip_blocks: 0,
-//                     },
-//                     #[cfg(any(feature="compact_filters", feature="electrum", feature="esplora"))]
-//                     proxy_opts: ProxyOpts{
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     },
-//                     #[cfg(feature = "rpc")]
-//                     rpc_opts: RpcOpts {
-//                         address: "127.0.0.1:18443".to_string(),
-//                         basic_auth: ("user".to_string(), "password".to_string()),
-//                         cookie: None,
-//                         start_time: 0,
-//                     },
-//                 },
-//                 subcommand: WalletSubCommand::OfflineWalletSubCommand(CreateTx {
-//                     recipients: vec![(script1, 123456), (script2, 78910)],
-//                     send_all: false,
-//                     enable_rbf: true,
-//                     offline_signer: false,
-//                     utxos: Some(vec!(outpoint1, outpoint2)),
-//                     unspendable: None,
-//                     fee_rate: None,
-//                     external_policy: None,
-//                     internal_policy: None,
-//                     add_data: None,
-//                     add_string: Some("Hello BDK".to_string()),
-//                 }),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[test]
-//     fn test_parse_wallet_bump_fee() {
-//         let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet",
-//                             "--descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "--change_descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)",
-//                             "bump_fee", "--fee_rate", "6.1",
-//                             "--txid","35aab0d0213f8996f9e236a28630319b93109754819e8abf48a0835708d33506",
-//                             "--shrink","tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt"];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Testnet,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(),
-//                     change_descriptor: Some("wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/1/*)".to_string()),
-//                     #[cfg(feature = "electrum")]
-//                     electrum_opts: ElectrumOpts {
-//                         timeout: None,
-//                         server: "ssl://electrum.blockstream.info:60002".to_string(),
-//                         stop_gap: 10,
-//                     },
-//                     #[cfg(feature = "esplora")]
-//                     esplora_opts: EsploraOpts {
-//                         server: "https://blockstream.info/testnet/api/".to_string(),
-//                         timeout: 5,
-//                         stop_gap: 10,
-//                         conc: 4,
-//                     },
-//                     #[cfg(feature = "cbf")]
-//                     cbf_opts: CompactFilterOpts{
-//                         address: vec!["127.0.0.1:18444".to_string()],
-//                         conn_count: 4,
-//                         skip_blocks: 0,
-//                     },
-//                     #[cfg(feature = "rpc")]
-//                     rpc_opts: RpcOpts {
-//                         address: "127.0.0.1:18443".to_string(),
-//                         basic_auth: ("user".to_string(), "password".to_string()),
-//                         cookie: None,
-//                         start_time: 0,
-//                     },
-//                     #[cfg(any(feature="compact_filters", feature="electrum", feature="esplora"))]
-//                     proxy_opts: ProxyOpts{
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     }
-//                 },
-//                 subcommand: OfflineWalletSubCommand(BumpFee {
-//                     txid: "35aab0d0213f8996f9e236a28630319b93109754819e8abf48a0835708d33506".to_string(),
-//                     shrink_address: Some(Address::from_str("tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt").unwrap().assume_checked()),
-//                     offline_signer: false,
-//                     utxos: None,
-//                     unspendable: None,
-//                     fee_rate: 6.1
-//                 }),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(any(
-//         feature = "electrum",
-//         feature = "esplora",
-//         feature = "cbf",
-//         feature = "rpc"
-//     ))]
-//     #[test]
-//     fn test_parse_wallet_broadcast() {
-//         let cli_args = vec!["bdk-cli", "--network", "testnet", "wallet",
-//                             "--descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "broadcast",
-//                             "--psbt", "cHNidP8BAEICAAAAASWhGE1AhvtO+2GjJHopssFmgfbq+WweHd8zN/DeaqmDAAAAAAD/////AQAAAAAAAAAABmoEAAECAwAAAAAAAAA="];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Testnet,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)".to_string(),
-//                     change_descriptor: None,
-//                     #[cfg(feature = "electrum")]
-//                     electrum_opts: ElectrumOpts {
-//                         timeout: None,
-//                         server: "ssl://electrum.blockstream.info:60002".to_string(),
-//                         stop_gap: 10,
-//                     },
-//                     #[cfg(feature = "esplora")]
-//                     esplora_opts: EsploraOpts {
-//                         server: "https://blockstream.info/testnet/api/".to_string(),
-//                         timeout: 5,
-//                         stop_gap: 10,
-//                         conc: 4,
-//                     },
-//                     #[cfg(feature = "cbf")]
-//                     cbf_opts: CompactFilterOpts{
-//                         address: vec!["127.0.0.1:18444".to_string()],
-//                         conn_count: 4,
-//                         skip_blocks: 0,
-//                     },
-//                     #[cfg(any(feature="compact_filters", feature="electrum", feature="esplora"))]
-//                     proxy_opts: ProxyOpts{
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     },
-//                     #[cfg(feature = "rpc")]
-//                     rpc_opts: RpcOpts {
-//                         address: "127.0.0.1:18443".to_string(),
-//                         basic_auth: ("user".to_string(), "password".to_string()),
-//                         cookie: None,
-//                         start_time: 0,
-//                     },
-//                 },
-//                 subcommand: OnlineWalletSubCommand(Broadcast {
-//                     psbt: Some("cHNidP8BAEICAAAAASWhGE1AhvtO+2GjJHopssFmgfbq+WweHd8zN/DeaqmDAAAAAAD/////AQAAAAAAAAAABmoEAAECAwAAAAAAAAA=".to_string()),
-//                     tx: None
-//                 }),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[test]
-//     fn test_parse_wrong_network() {
-//         let cli_args = vec!["repl", "--network", "badnet", "wallet",
-//                             "--descriptor", "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)",
-//                             "sync"];
-//
-//         let cli_opts = CliOpts::from_iter_safe(&cli_args);
-//         assert!(cli_opts.is_err());
-//     }
-//
-//     #[test]
-//     fn test_key_generate() {
-//         let network = Testnet;
-//         let key_generate_cmd = KeySubCommand::Generate {
-//             word_count: 12,
-//             password: Some("test123".to_string()),
-//         };
-//
-//         let result = handle_key_subcommand(network, key_generate_cmd).unwrap();
-//         let result_obj = result.as_object().unwrap();
-//
-//         let mnemonic = result_obj.get("mnemonic").unwrap().as_str().unwrap();
-//         let mnemonic: Vec<&str> = mnemonic.split(' ').collect();
-//         let xprv = result_obj.get("xprv").unwrap().as_str().unwrap();
-//
-//         assert_eq!(mnemonic.len(), 12);
-//         assert_eq!(&xprv[0..4], "tprv");
-//     }
-//
-//     #[test]
-//     fn test_key_restore() {
-//         let network = Testnet;
-//         let key_generate_cmd = KeySubCommand::Restore {
-//             mnemonic: "payment battle unit sword token broccoli era violin purse trip blood hire"
-//                 .to_string(),
-//             password: Some("test123".to_string()),
-//         };
-//
-//         let result = handle_key_subcommand(network, key_generate_cmd).unwrap();
-//         let result_obj = result.as_object().unwrap();
-//
-//         let fingerprint = result_obj.get("fingerprint").unwrap().as_str().unwrap();
-//         let xprv = result_obj.get("xprv").unwrap().as_str().unwrap();
-//
-//         assert_eq!(&fingerprint, &"828af366");
-//         assert_eq!(&xprv, &"tprv8ZgxMBicQKsPd18TeiFknZKqaZFwpdX9tvvKh8eeHSSPBQi5g9xPHztBg411o78G8XkrhQb6Q1cVvBJ1a9xuFHpmWgvQsvkJkNxBjfGoqhK");
-//     }
-//
-//     #[test]
-//     fn test_key_derive() {
-//         let network = Testnet;
-//         let key_generate_cmd = KeySubCommand::Derive {
-//             xprv: Xpriv::from_str("tprv8ZgxMBicQKsPfQjJy8ge2cvBfDjLxJSkvNLVQiw7BQ5gTjKadG2rrcQB5zjcdaaUTz5EDNJaS77q4DzjqjogQBfMsaXFFNP3UqoBnwt2kyT").unwrap(),
-//             path: DerivationPath::from_str("m/84'/1'/0'/0").unwrap(),
-//         };
-//
-//         let result = handle_key_subcommand(network, key_generate_cmd).unwrap();
-//         let result_obj = result.as_object().unwrap();
-//
-//         let xpub = result_obj.get("xpub").unwrap().as_str().unwrap();
-//         let xprv = result_obj.get("xprv").unwrap().as_str().unwrap();
-//
-//         assert_eq!(&xpub, &"[566844c5/84'/1'/0'/0]tpubDFeqiDkfwR1tAhPxsXSZMfEmfpDhwhLyhLKZgmeBvuBkZQusoWeL62oGg2oTNGcENeKdwuGepAB85eMvyLemabYe9PSqv6cr5mFXktHc3Ka/*");
-//         assert_eq!(&xprv, &"[566844c5/84'/1'/0'/0]tprv8ixoZoiRo3LDHENAysmxxFaf6nhmnNA582inQFbtWdPMivf7B7pjuYBQVuLC5bkM7tJZEDbfoivENsGZPBnQg1n52Kuc1P8X2Ei3XJuJX7c/*");
-//     }
-//
-//     #[cfg(feature = "compiler")]
-//     #[test]
-//     fn test_parse_compile() {
-//         let cli_args = vec![
-//             "bdk-cli",
-//             "compile",
-//             "thresh(3,pk(Alice),pk(Bob),pk(Carol),older(2))",
-//             "--type",
-//             "sh-wsh",
-//         ];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Testnet,
-//             datadir: None,
-//             subcommand: CliSubCommand::Compile {
-//                 policy: "thresh(3,pk(Alice),pk(Bob),pk(Carol),older(2))".to_string(),
-//                 script_type: "sh-wsh".to_string(),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(feature = "compiler")]
-//     #[test]
-//     fn test_compile() {
-//         let result = handle_compile_subcommand(
-//             Network::Testnet,
-//             "thresh(3,pk(Alice),pk(Bob),pk(Carol),older(2))".to_string(),
-//             "sh-wsh".to_string(),
-//         )
-//         .unwrap();
-//         let result_obj = result.as_object().unwrap();
-//
-//         let descriptor = result_obj.get("descriptor").unwrap().as_str().unwrap();
-//         assert_eq!(
-//             &descriptor,
-//             &"sh(wsh(thresh(3,pk(Alice),s:pk(Bob),s:pk(Carol),snl:older(2))))#rmef3s78"
-//         );
-//     }
-//
-//     #[cfg(all(feature = "reserves", feature = "cbf"))]
-//     #[test]
-//     fn test_parse_produce_proof() {
-//         let message = "Those coins belong to Satoshi Nakamoto";
-//         let cli_args = vec![
-//             "bdk-cli",
-//             "--network",
-//             "bitcoin",
-//             "wallet",
-//             "--descriptor",
-//             "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)",
-//             "produce_proof",
-//             "--message",
-//             message.clone(),
-//         ];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Bitcoin,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"
-//                         .to_string(),
-//                     change_descriptor: None,
-//                     cbf_opts: CompactFilterOpts {
-//                         address: vec!["127.0.0.1:18444".to_string()],
-//                         conn_count: 4,
-//                         skip_blocks: 0,
-//                     },
-//                     proxy_opts: ProxyOpts {
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     },
-//                 },
-//                 subcommand: OnlineWalletSubCommand(ProduceProof {
-//                     msg: message.to_string(),
-//                 }),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(all(feature = "reserves", feature = "esplora-ureq"))]
-//     #[test]
-//     fn test_parse_verify_proof_internal() {
-//         let psbt = r#"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"#;
-//         let message = "Those coins belong to Satoshi Nakamoto";
-//         let cli_args = vec![
-//             "bdk-cli",
-//             "--network",
-//             "bitcoin",
-//             "wallet",
-//             "--descriptor",
-//             "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)",
-//             "verify_proof",
-//             "--psbt",
-//             psbt.clone(),
-//             "--message",
-//             message.clone(),
-//         ];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Bitcoin,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"
-//                         .to_string(),
-//                     change_descriptor: None,
-//                     esplora_opts: EsploraOpts {
-//                         server: "https://blockstream.info/testnet/api/".to_string(),
-//                         timeout: 5,
-//                         stop_gap: 10,
-//                         conc: 4,
-//                     },
-//                     proxy_opts: ProxyOpts {
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     },
-//                 },
-//                 subcommand: OnlineWalletSubCommand(OnlineWalletSubCommand::VerifyProof {
-//                     psbt: psbt.to_string(),
-//                     msg: message.to_string(),
-//                     confirmations: 6,
-//                 }),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(all(feature = "reserves", feature = "esplora-ureq"))]
-//     #[test]
-//     fn test_parse_verify_proof_internal_confirmation() {
-//         let psbt = r#"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"#;
-//         let message = "Those coins belong to Satoshi Nakamoto";
-//         let cli_args = vec![
-//             "bdk-cli",
-//             "--network",
-//             "bitcoin",
-//             "wallet",
-//             "--descriptor",
-//             "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)",
-//             "verify_proof",
-//             "--psbt",
-//             psbt.clone(),
-//             "--message",
-//             message.clone(),
-//             "--confirmations",
-//             "0",
-//         ];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Bitcoin,
-//             datadir: None,
-//             subcommand: CliSubCommand::Wallet {
-//                 wallet_opts: WalletOpts {
-//                     wallet: None,
-//                     verbose: false,
-//                     descriptor: "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"
-//                         .to_string(),
-//                     change_descriptor: None,
-//                     esplora_opts: EsploraOpts {
-//                         server: "https://blockstream.info/testnet/api/".to_string(),
-//                         timeout: 5,
-//                         stop_gap: 10,
-//                         conc: 4,
-//                     },
-//                     proxy_opts: ProxyOpts {
-//                         proxy: None,
-//                         proxy_auth: None,
-//                         retries: 5,
-//                     },
-//                 },
-//                 subcommand: OnlineWalletSubCommand(OnlineWalletSubCommand::VerifyProof {
-//                     psbt: psbt.to_string(),
-//                     msg: message.to_string(),
-//                     confirmations: 0,
-//                 }),
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     #[cfg(all(feature = "reserves", feature = "electrum"))]
-//     #[test]
-//     fn test_parse_verify_proof_external() {
-//         let psbt = r#"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"#.to_string();
-//         let address = "tb1qanjjv4cs20dgv32vncrxw702l8g4qtn2m9wn7d".to_string();
-//         let message = "Those coins belong to Satoshi Nakamoto".to_string();
-//         let cli_args = vec![
-//             "bdk-cli",
-//             "--network",
-//             "bitcoin",
-//             "external_reserves",
-//             &message,
-//             &psbt,
-//             "6",
-//             &address,
-//             "--server",
-//             "ssl://electrum.blockstream.info:60002",
-//         ];
-//
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let expected_cli_opts = CliOpts {
-//             network: Network::Bitcoin,
-//             datadir: None,
-//             subcommand: CliSubCommand::ExternalReserves {
-//                 message,
-//                 psbt,
-//                 confirmations: 6,
-//                 addresses: [address].to_vec(),
-//                 electrum_opts: ElectrumOpts {
-//                     timeout: None,
-//                     server: "ssl://electrum.blockstream.info:60002".to_string(),
-//                     stop_gap: 10,
-//                 },
-//             },
-//         };
-//
-//         assert_eq!(expected_cli_opts, cli_opts);
-//     }
-//
-//     /// Encodes a partially signed transaction as base64 and returns the  bytes of the resulting string.
-//     #[cfg(all(feature = "reserves", feature = "electrum"))]
-//     fn encode_psbt(psbt: Psbt) -> Vec<u8> {
-//         let mut encoded = Vec::<u8>::new();
-//         psbt.consensus_encode(&mut encoded).unwrap();
-//         let base64_psbt = base64::encode(&encoded);
-//
-//         base64_psbt.as_bytes().to_vec()
-//     }
-//
-//     #[cfg(all(feature = "reserves", feature = "electrum"))]
-//     #[test]
-//     fn test_proof_of_reserves_wallet() {
-//         let descriptor = "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)".to_string();
-//         let message = "Those coins belong to Satoshi Nakamoto";
-//
-//         let client = Client::new("ssl://electrum.blockstream.info:60002").unwrap();
-//         let blockchain = ElectrumBlockchain::from(client);
-//         let wallet = Wallet::new(
-//             &descriptor,
-//             None,
-//             Network::Testnet,
-//             MemoryDatabase::default(),
-//         )
-//         .unwrap();
-//
-//         wallet.sync(&blockchain, SyncOptions::default()).unwrap();
-//         let balance = wallet.get_balance().unwrap();
-//
-//         let addr = wallet
-//             .get_address(bdk_wallet::wallet::AddressIndex::New)
-//             .unwrap();
-//         assert_eq!(
-//             "tb1qanjjv4cs20dgv32vncrxw702l8g4qtn2m9wn7d",
-//             addr.to_string()
-//         );
-//
-//         let cli_args = vec![
-//             "bdk-cli",
-//             "--network",
-//             "bitcoin",
-//             "wallet",
-//             "--descriptor",
-//             &descriptor,
-//             "produce_proof",
-//             "--message",
-//             message.clone(),
-//         ];
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let wallet_subcmd = match cli_opts.subcommand {
-//             CliSubCommand::Wallet {
-//                 wallet_opts: _,
-//                 subcommand: OnlineWalletSubCommand(online_subcommand),
-//             } => online_subcommand,
-//             _ => panic!("unexpected subcommand"),
-//         };
-//         let result = handle_online_wallet_subcommand(&wallet, &blockchain, wallet_subcmd).unwrap();
-//         let psbt: PartiallySignedTransaction =
-//             serde_json::from_str(&result.as_object().unwrap().get("psbt").unwrap().to_string())
-//                 .unwrap();
-//         let psbt = encode_psbt(psbt);
-//         let psbt = str::from_utf8(&psbt).unwrap();
-//         assert_eq!(format!("{}", psbt), "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");
-//
-//         let psbt_b64 = &result
-//             .as_object()
-//             .unwrap()
-//             .get("psbt_base64")
-//             .unwrap()
-//             .to_string();
-//         assert_eq!(&format!("{}", psbt), psbt_b64.trim_matches('\"'));
-//
-//         let cli_args = vec![
-//             "bdk-cli",
-//             "--network",
-//             "bitcoin",
-//             "wallet",
-//             "--descriptor",
-//             &descriptor,
-//             "verify_proof",
-//             "--psbt",
-//             psbt,
-//             "--message",
-//             message.clone(),
-//         ];
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let wallet_subcmd = match cli_opts.subcommand {
-//             CliSubCommand::Wallet {
-//                 wallet_opts: _,
-//                 subcommand: OnlineWalletSubCommand(online_subcommand),
-//             } => online_subcommand,
-//             _ => panic!("unexpected subcommand"),
-//         };
-//         let result = handle_online_wallet_subcommand(&wallet, &blockchain, wallet_subcmd).unwrap();
-//         let spendable = result
-//             .as_object()
-//             .unwrap()
-//             .get("spendable")
-//             .unwrap()
-//             .as_u64()
-//             .unwrap();
-//         assert_eq!(spendable, balance.get_spendable());
-//     }
-//
-//     #[cfg(all(feature = "reserves", feature = "electrum"))]
-//     #[test]
-//     fn test_proof_of_reserves_veryfy() {
-//         let message = "Those coins belong to Satoshi Nakamoto";
-//         let address = "tb1qanjjv4cs20dgv32vncrxw702l8g4qtn2m9wn7d";
-//         let psbt = "cHNidP8BAKcBAAAAA9A7AuVMuwIrkAuXtKDqw3BruovK2PH7E90MzCbyaAMlAAAAAAD/////sq+79fxJ+5F8951Xcbp8N5VYVJoesG1zd3AxStcGwPYAAAAAAP/////AUS4n/SkO9SSvIv8MI2Xdm3xdn77Sud6uX5PyqCganAEAAAAA/////wGwrQEAAAAAABl2qRSff9CW037SwOP38M/JJL7vT/zraIisAAAAAAABAQoAAAAAAAAAAAFRAQcAAAEBHxAnAAAAAAAAFgAU7OUmVxBT2oZFTJ4GZ3nq+dFQLmoiAgMrBVgHi+w4aUqEkz1lkwPiV12ufpFoWRFFQRW/1kSH40gwRQIhAPgByvkajQrNeQDSGik2gnxpo/P/owiEHR+0nWefkXurAiBgrAlDvwuTiaGEEWQW/Kd7L7u7YOQnqvrd46DR0A8yPgEBBwABCGwCSDBFAiEA+AHK+RqNCs15ANIaKTaCfGmj8/+jCIQdH7SdZ5+Re6sCIGCsCUO/C5OJoYQRZBb8p3svu7tg5Ceq+t3joNHQDzI+ASEDKwVYB4vsOGlKhJM9ZZMD4lddrn6RaFkRRUEVv9ZEh+MAAQEfoIYBAAAAAAAWABTs5SZXEFPahkVMngZneer50VAuaiICAysFWAeL7DhpSoSTPWWTA+JXXa5+kWhZEUVBFb/WRIfjRzBEAiBSfiX0qP7vR+2Qx/mRJS8pwma8nTfOWKerzo6c0iSAfwIgEfX4Wt7YXd8MkKUEY627GWYCmKfMsJGcIC0U1wgc1vUBAQcAAQhrAkcwRAIgUn4l9Kj+70ftkMf5kSUvKcJmvJ03zlinq86OnNIkgH8CIBH1+Fre2F3fDJClBGOtuxlmApinzLCRnCAtFNcIHNb1ASEDKwVYB4vsOGlKhJM9ZZMD4lddrn6RaFkRRUEVv9ZEh+MAAA==";
-//
-//         let cli_args = vec![
-//             "bdk-cli",
-//             "--network",
-//             "bitcoin",
-//             "external_reserves",
-//             message,
-//             psbt,
-//             "6",
-//             address,
-//             address, // passing the address twice on purpose, to test passing of multiple addresses
-//             "--server",
-//             "ssl://electrum.blockstream.info:60002",
-//         ];
-//         let cli_opts = CliOpts::from_iter(&cli_args);
-//
-//         let (message, psbt, confirmations, addresses, electrum_opts) = match cli_opts.subcommand {
-//             CliSubCommand::ExternalReserves {
-//                 message,
-//                 psbt,
-//                 confirmations,
-//                 addresses,
-//                 electrum_opts,
-//             } => (message, psbt, confirmations, addresses, electrum_opts),
-//             _ => panic!("unexpected subcommand"),
-//         };
-//         let result = handle_ext_reserves_subcommand(
-//             Network::Bitcoin,
-//             message,
-//             psbt,
-//             confirmations,
-//             addresses,
-//             electrum_opts,
-//         )
-//         .unwrap();
-//         let spendable = result
-//             .as_object()
-//             .unwrap()
-//             .get("spendable")
-//             .unwrap()
-//             .as_u64()
-//             .unwrap();
-//         assert!(spendable > 0);
-//     }
-//
-//     #[cfg(feature = "repl")]
-//     #[test]
-//     fn test_regex_double_quotes() {
-//         let split_regex = Regex::new(crate::REPL_LINE_SPLIT_REGEX).unwrap();
-//         let line = r#"restore -m "word1 word2 word3" -p 'test! 123 -test' "#;
-//         let split_line: Vec<&str> = split_regex
-//             .captures_iter(&line)
-//             .map(|c| {
-//                 c.get(1)
-//                     .or_else(|| c.get(2))
-//                     .or_else(|| c.get(3))
-//                     .unwrap()
-//                     .as_str()
-//             })
-//             .collect();
-//         assert_eq!(
-//             vec!(
-//                 "restore",
-//                 "-m",
-//                 "word1 word2 word3",
-//                 "-p",
-//                 "test! 123 -test"
-//             ),
-//             split_line
-//         );
-//     }
-//
-//     #[cfg(feature = "repl")]
-//     #[test]
-//     fn test_regex_single_quotes() {
-//         let split_regex = Regex::new(crate::REPL_LINE_SPLIT_REGEX).unwrap();
-//         let line = r#"restore -m 'word1 word2 word3' -p "test *123 -test" "#;
-//         let split_line: Vec<&str> = split_regex
-//             .captures_iter(&line)
-//             .map(|c| {
-//                 c.get(1)
-//                     .or_else(|| c.get(2))
-//                     .or_else(|| c.get(3))
-//                     .unwrap()
-//                     .as_str()
-//             })
-//             .collect();
-//         assert_eq!(
-//             vec!(
-//                 "restore",
-//                 "-m",
-//                 "word1 word2 word3",
-//                 "-p",
-//                 "test *123 -test"
-//             ),
-//             split_line
-//         );
-//     }
-// }
index fb318bbd504df2a8b82074e72c3deb9fe9e6c9ec..0e58cbd9043c60e7f0c970eb3954207e17f5c349 100644 (file)
@@ -29,31 +29,38 @@ use bdk_wallet::bitcoin::Network;
 use bdk_wallet::bitcoin::{secp256k1::Secp256k1, Transaction, Txid};
 use bdk_wallet::bitcoin::{Amount, FeeRate, Psbt, Sequence};
 use bdk_wallet::descriptor::Segwitv0;
-#[cfg(feature = "compiler")]
-use bdk_wallet::{descriptor::{Descriptor, Legacy, Miniscript}, miniscript::policy::Concrete};
 use bdk_wallet::keys::bip39::WordCount;
 #[cfg(feature = "sqlite")]
 use bdk_wallet::rusqlite::Connection;
+#[cfg(feature = "compiler")]
+use bdk_wallet::{
+    descriptor::{Descriptor, Legacy, Miniscript},
+    miniscript::policy::Concrete,
+};
 use bdk_wallet::{KeychainKind, SignOptions, Wallet};
 
 use bdk_wallet::keys::DescriptorKey::Secret;
 use bdk_wallet::keys::{DerivableKey, DescriptorKey, ExtendedKey, GeneratableKey, GeneratedKey};
 use bdk_wallet::miniscript::miniscript;
+use serde_json::json;
 use std::collections::{BTreeMap, HashSet};
 use std::convert::TryFrom;
 use std::io::Write;
-use serde_json::json;
 use std::str::FromStr;
 
 #[cfg(feature = "electrum")]
 use crate::utils::BlockchainClient::Electrum;
-#[cfg(feature = "esplora")]
-use {crate::utils::BlockchainClient::Esplora,
-    bdk_esplora::EsploraAsyncExt
-};
 use bdk_wallet::bitcoin::base64::prelude::*;
 use bdk_wallet::bitcoin::consensus::Decodable;
 use bdk_wallet::bitcoin::hex::FromHex;
+#[cfg(feature = "esplora")]
+use {crate::utils::BlockchainClient::Esplora, bdk_esplora::EsploraAsyncExt};
+#[cfg(feature = "rpc")]
+use {
+    crate::utils::BlockchainClient::RpcClient,
+    bdk_bitcoind_rpc::{Emitter, bitcoincore_rpc::RpcApi},
+    bdk_wallet::chain::{BlockId, CheckPoint},
+};
 
 /// Execute an offline wallet sub-command
 ///
@@ -354,7 +361,9 @@ pub(crate) async fn handle_online_wallet_subcommand(
                     client
                         .populate_tx_cache(wallet.tx_graph().full_txs().map(|tx_node| tx_node.tx));
 
-                    let update = client.full_scan(request, stop_gap, batch_size, false)?;
+                    let update = client
+                        .full_scan(request, stop_gap, batch_size, false)
+                        .map_err(|e| Error::Generic(e.to_string()))?;
                     wallet.apply_update(update)?;
                 }
                 #[cfg(feature = "esplora")]
@@ -365,9 +374,37 @@ pub(crate) async fn handle_online_wallet_subcommand(
                     let update = client
                         .full_scan(request, stop_gap, parallel_requests)
                         .await
-                        .map_err(|e| *e)?;
+                        .map_err(|e| Error::Generic(e.to_string()))?;
                     wallet.apply_update(update)?;
                 }
+
+                #[cfg(feature = "rpc")]
+                RpcClient { client } => {
+                    let genesis_block =
+                        bdk_wallet::bitcoin::constants::genesis_block(wallet.network());
+                    let genesis_cp = CheckPoint::new(BlockId {
+                        height: 0,
+                        hash: genesis_block.block_hash(),
+                    });
+                    let mut emitter =
+                        Emitter::new(&client, genesis_cp.clone(), genesis_cp.height());
+
+                    while let Some(block_event) = emitter
+                        .next_block()
+                        .map_err(|e| Error::Generic(e.to_string()))?
+                    {
+                        wallet
+                            .apply_block_connected_to(
+                                &block_event.block,
+                                block_event.block_height(),
+                                block_event.connected_to(),
+                            )
+                            .map_err(|e| Error::Generic(e.to_string()))?;
+                    }
+
+                    let mempool_txs = emitter.mempool().unwrap();
+                    wallet.apply_unconfirmed_txs(mempool_txs);
+                }
             }
             Ok(json!({}))
         }
@@ -386,7 +423,9 @@ pub(crate) async fn handle_online_wallet_subcommand(
                     client
                         .populate_tx_cache(wallet.tx_graph().full_txs().map(|tx_node| tx_node.tx));
 
-                    let update = client.sync(request, batch_size, false)?;
+                    let update = client
+                        .sync(request, batch_size, false)
+                        .map_err(|e| Error::Generic(e.to_string()))?;
                     wallet.apply_update(update)?;
                 }
                 #[cfg(feature = "esplora")]
@@ -397,9 +436,30 @@ pub(crate) async fn handle_online_wallet_subcommand(
                     let update = client
                         .sync(request, parallel_requests)
                         .await
-                        .map_err(|e| *e)?;
+                        .map_err(|e| Error::Generic(e.to_string()))?;
                     wallet.apply_update(update)?;
                 }
+                #[cfg(feature = "rpc")]
+                RpcClient { client } => {
+                    let wallet_cp = wallet.latest_checkpoint();
+                    let mut emitter = Emitter::new(&client, wallet_cp.clone(), wallet_cp.height());
+
+                    while let Some(block_event) = emitter
+                        .next_block()
+                        .map_err(|e| Error::Generic(e.to_string()))?
+                    {
+                        wallet
+                            .apply_block_connected_to(
+                                &block_event.block,
+                                block_event.block_height(),
+                                block_event.connected_to(),
+                            )
+                            .map_err(|e| Error::Generic(e.to_string()))?;
+                    }
+
+                    let mempool_txs = emitter.mempool().unwrap();
+                    wallet.apply_unconfirmed_txs(mempool_txs);
+                }
             }
             Ok(json!({}))
         }
@@ -426,7 +486,9 @@ pub(crate) async fn handle_online_wallet_subcommand(
                 Electrum {
                     client,
                     batch_size: _,
-                } => client.transaction_broadcast(&tx)?,
+                } => client
+                    .transaction_broadcast(&tx)
+                    .map_err(|e| Error::Generic(e.to_string()))?,
                 #[cfg(feature = "esplora")]
                 Esplora {
                     client,
@@ -434,7 +496,12 @@ pub(crate) async fn handle_online_wallet_subcommand(
                 } => client
                     .broadcast(&tx)
                     .await
-                    .map(|()| tx.compute_txid().clone())?,
+                    .map(|()| tx.compute_txid().clone())
+                    .map_err(|e| Error::Generic(e.to_string()))?,
+                #[cfg(feature = "rpc")]
+                RpcClient { client } => client
+                    .send_raw_transaction(&tx)
+                    .map_err(|e| Error::Generic(e.to_string()))?,
             };
             Ok(json!({ "txid": txid }))
         }
index 795ebaf1c6bddcf9dec6b35816a7d0cc8e1c2635..cb6ae474787303c96631e212ca44882bf829b4c7 100644 (file)
@@ -18,7 +18,7 @@ use std::path::{Path, PathBuf};
 use crate::commands::WalletOpts;
 use bdk_wallet::bitcoin::{Address, Network, OutPoint, ScriptBuf};
 
-#[cfg(any(feature = "electrum", feature = "esplora"))]
+#[cfg(any(feature = "electrum", feature = "esplora", feature = "rpc"))]
 use crate::commands::ClientType;
 
 #[cfg(any(feature = "sqlite",))]
@@ -134,14 +134,17 @@ pub(crate) enum BlockchainClient {
         client: bdk_esplora::esplora_client::AsyncClient,
         parallel_requests: usize,
     },
-    // TODO rbf
+    #[cfg(feature = "rpc")]
+    RpcClient {
+        client: bdk_bitcoind_rpc::bitcoincore_rpc::Client,
+    },
     // TODO cbf
 }
 
 #[cfg(any(
     feature = "electrum",
     feature = "esplora",
-    // feature = "rpc",
+    feature = "rpc",
     feature = "cbf",
 ))]
 /// Create a new blockchain from the wallet configuration options.
@@ -165,6 +168,20 @@ pub(crate) fn new_blockchain_client(wallet_opts: &WalletOpts) -> Result<Blockcha
                 parallel_requests: wallet_opts.parallel_requests,
             }
         }
+
+        #[cfg(feature = "rpc")]
+        ClientType::RPC => {
+            let auth = match &wallet_opts.cookie {
+                Some(cookie) => bdk_bitcoind_rpc::bitcoincore_rpc::Auth::CookieFile(cookie.into()),
+                None => bdk_bitcoind_rpc::bitcoincore_rpc::Auth::UserPass(
+                    wallet_opts.basic_auth.0.clone(),
+                    wallet_opts.basic_auth.1.clone(),
+                ),
+            };
+            let client = bdk_bitcoind_rpc::bitcoincore_rpc::Client::new(url, auth)
+                .map_err(|e| Error::Generic(e.to_string()))?;
+            BlockchainClient::RpcClient { client }
+        }
     };
     Ok(client)
 }
index 2a8b60cfde0343080d06f16ad7556014ee165031..f6b2be760b055ca2ea7f7bec4abb9ce1bf346589 100644 (file)
@@ -13,9 +13,9 @@
 
 #[cfg(feature = "rpc")]
 mod test {
-    use electrsd::bitcoind::tempfile::TempDir;
     use serde_json::{json, Value};
     use std::convert::From;
+    use std::env::temp_dir;
     use std::path::PathBuf;
     use std::process::Command;
 
@@ -200,8 +200,8 @@ mod test {
         let mut test_dir = std::env::current_dir().unwrap();
         test_dir.push("bdk-testing");
 
-        let test_temp_dir = TempDir::new().unwrap();
-        let test_dir = test_temp_dir.into_path().to_path_buf();
+        let test_dir = temp_dir();
+        // let test_dir = test_temp_dir.into_path().to_path_buf();
 
         // Create bdk-cli instance
         let bdk_cli = BdkCli::new("regtest", Some(test_dir), false, &[feature]).unwrap();