From 8307db08776d7b53dbadcf776a4b786a925291f2 Mon Sep 17 00:00:00 2001 From: Vihiga Tyonum Date: Wed, 5 Mar 2025 09:57:32 +0100 Subject: [PATCH] feat: re-enable `rpc` feature - re-enable `rpc` feature --- .github/workflows/code_coverage.yml | 4 +- .github/workflows/cont_integration.yml | 2 + Cargo.toml | 4 +- ci/test_features.sh | 8 + src/commands.rs | 1160 +----------------------- src/handlers.rs | 93 +- src/utils.rs | 23 +- tests/integration.rs | 6 +- 8 files changed, 139 insertions(+), 1161 deletions(-) diff --git a/.github/workflows/code_coverage.yml b/.github/workflows/code_coverage.yml index dad6ffd..bc031ae 100644 --- a/.github/workflows/code_coverage.yml +++ b/.github/workflows/code_coverage.yml @@ -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 diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index c4e8735..8c0dbe1 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -20,6 +20,8 @@ jobs: - esplora - compiler,sqlite - compiler + - rpc + - verify rpc - verify - verify esplora - verify esplora compiler diff --git a/Cargo.toml b/Cargo.toml index 1b0e7e1..e1fe742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 = [] diff --git a/ci/test_features.sh b/ci/test_features.sh index caf67c9..7407818 100755 --- a/ci/test_features.sh +++ b/ci/test_features.sh @@ -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 diff --git a/src/commands.rs b/src/commands.rs index 7659d2c..9d22a79 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -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, - #[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 } /// 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, - - /// 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 { -// let mut encoded = Vec::::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 -// ); -// } -// } diff --git a/src/handlers.rs b/src/handlers.rs index fb318bb..0e58cbd 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -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 })) } diff --git a/src/utils.rs b/src/utils.rs index 795ebaf..cb6ae47 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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 { + 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) } diff --git a/tests/integration.rs b/tests/integration.rs index 2a8b60c..f6b2be7 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -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(); -- 2.49.0