From 9c76a360dc05e8c9dc1f5d34c3c70c6b13ce576f Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Thu, 17 Dec 2020 20:38:48 -0800 Subject: [PATCH] Reorganize bdk cli module into new stand alone lib and repl bin --- .github/pull_request_template.md | 18 +++---- Cargo.toml | 91 ++++++-------------------------- README.md | 13 +++++ src/{cli.rs => lib.rs} | 70 +++++++++++------------- {examples => src}/repl.rs | 12 ++--- 5 files changed, 76 insertions(+), 128 deletions(-) create mode 100644 README.md rename src/{cli.rs => lib.rs} (94%) rename {examples => src}/repl.rs (93%) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 572282f..3dbc5fd 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -13,18 +13,18 @@ of the PR were done in a specific way --> #### All Submissions: -* [] I've signed all my commits -* [] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) -* [] I ran `cargo fmt` and `cargo clippy` before committing +* [ ] I've signed all my commits +* [ ] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) +* [ ] I ran `cargo fmt` and `cargo clippy` before committing #### New Features: -* [] I've added tests for the new feature -* [] I've added docs for the new feature -* [] I've updated `CHANGELOG.md` +* [ ] I've added tests for the new feature +* [ ] I've added docs for the new feature +* [ ] I've updated `CHANGELOG.md` #### Bugfixes: -* [] This pull request breaks the existing API -* [] I've added tests to reproduce the issue which are now passing -* [] I'm linking the issue being fixed by this PR +* [ ] This pull request breaks the existing API +* [ ] I've added tests to reproduce the issue which are now passing +* [ ] I'm linking the issue being fixed by this PR diff --git a/Cargo.toml b/Cargo.toml index 84c1fa5..110f73e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,89 +1,32 @@ [package] -name = "bdk" +name = "bdk-cli" version = "0.1.0" edition = "2018" authors = ["Alekos Filini ", "Riccardo Casatta "] [dependencies] -bdk-macros = { version = "0.1.0-beta.1", path = "./macros" } -log = "^0.4" -miniscript = "4.0" -bitcoin = { version = "^0.25.2", features = ["use-serde"] } -serde = { version = "^1.0", features = ["derive"] } +bdk = { git = "https://github.com/bitcoindevkit/bdk.git" } +bdk-macros = { git = "https://github.com/bitcoindevkit/bdk.git" } +structopt = "^0.3" serde_json = { version = "^1.0" } -rand = "^0.7" +log = "^0.4" +base64 = "^0.11" # Optional dependencies -sled = { version = "0.34", optional = true } -electrum-client = { version = "0.4.0-beta.1", optional = true } -reqwest = { version = "0.10", optional = true, features = ["json"] } -futures = { version = "0.3", optional = true } -clap = { version = "2.33", optional = true } -base64 = { version = "^0.11", optional = true } async-trait = { version = "0.1", optional = true } -rocksdb = { version = "0.14", optional = true } -# pin cc version to 1.0.62 because 1.0.63 break rocksdb build -cc = { version = "=1.0.62", optional = true } -socks = { version = "0.3", optional = true } -lazy_static = { version = "1.4", optional = true } -tiny-bip39 = { version = "^0.8", optional = true } -structopt = { version = "^0.3", optional = true } - -# Platform-specific dependencies -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -tokio = { version = "0.2", features = ["rt-core"] } - -[target.'cfg(target_arch = "wasm32")'.dependencies] -async-trait = "0.1" -js-sys = "0.3" -rand = { version = "^0.7", features = ["wasm-bindgen"] } +rustyline = { version = "6.0", optional = true } +dirs-next = { version = "2.0", optional = true } +env_logger = { version = "0.7", optional = true } +clap = { version = "2.33", optional = true } [features] -minimal = [] -compiler = ["clap", "miniscript/compiler"] -default = ["key-value-db", "electrum"] -electrum = ["electrum-client"] -esplora = ["reqwest", "futures"] -compact_filters = ["rocksdb", "socks", "lazy_static", "cc"] -key-value-db = ["sled"] -cli-utils = ["clap", "base64", "structopt"] -async-interface = ["async-trait"] -all-keys = ["keys-bip39"] -keys-bip39 = ["tiny-bip39"] - -# Debug/Test features -debug-proc-macros = ["bdk-macros/debug", "bdk-testutils-macros/debug"] -test-electrum = ["electrum"] -test-md-docs = ["base64", "electrum"] +default = ["repl", "esplora"] +repl = ["async-trait", "rustyline", "dirs-next", "env_logger", "clap", "electrum"] +electrum = ["bdk/electrum"] +esplora = ["bdk/esplora"] -[dev-dependencies] -bdk-testutils = { version = "0.1.0-beta.1", path = "./testutils" } -bdk-testutils-macros = { version = "0.1.0-beta.1", path = "./testutils-macros" } -serial_test = "0.4" -lazy_static = "1.4" -rustyline = "6.0" -dirs-next = "2.0" -env_logger = "0.7" -[[example]] +[[bin]] name = "repl" -required-features = ["cli-utils"] -[[example]] -name = "parse_descriptor" -[[example]] -name = "address_validator" - -[[example]] -name = "miniscriptc" -path = "examples/compiler.rs" -required-features = ["compiler"] - -[workspace] -members = ["macros", "testutils", "testutils-macros"] - -# Generate docs with nightly to add the "features required" badge -# https://stackoverflow.com/questions/61417452/how-to-get-a-feature-requirement-tag-in-the-documentation-generated-by-cargo-do -[package.metadata.docs.rs] -features = ["compiler", "electrum", "esplora", "compact_filters", "key-value-db", "all-keys"] -# defines the configuration attribute `docsrs` -rustdoc-args = ["--cfg", "docsrs"] +path = "src/repl.rs" +required-features = ["repl"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..73fc745 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +## About + +This project provides a command line interface (cli) Bitcoin wallet library and [`REPL`](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) +wallet tool based on the [bdk](https://github.com/bitcoindevkit/bdk) library. + +### How to run the REPL tool + +To run the REPL tool use the below command which returns the list of available wallet options and +commands: + +```shell +cargo run +``` \ No newline at end of file diff --git a/src/cli.rs b/src/lib.rs similarity index 94% rename from src/cli.rs rename to src/lib.rs index 44f11d7..aa82585 100644 --- a/src/cli.rs +++ b/src/lib.rs @@ -22,9 +22,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -//! Command line interface +//! BDK Command line interface //! -//! This module provides a [structopt](https://docs.rs/crate/structopt) `struct` and `enum` that +//! This lib provides a [structopt](https://docs.rs/crate/structopt) `struct` and `enum` that //! parse global wallet options and wallet subcommand options needed for a wallet command line //! interface. //! @@ -40,12 +40,12 @@ //! # use bdk::blockchain::esplora::EsploraBlockchainConfig; //! # use bdk::blockchain::{AnyBlockchain, ConfigurableBlockchain}; //! # use bdk::blockchain::{AnyBlockchainConfig, ElectrumBlockchainConfig}; -//! # use bdk::cli::{self, WalletOpt, WalletSubCommand}; +//! # use bdk_cli::{self, WalletOpt, WalletSubCommand}; //! # use bdk::database::MemoryDatabase; //! # use bdk::Wallet; -//! # use bitcoin::hashes::core::str::FromStr; //! # use std::sync::Arc; //! # use structopt::StructOpt; +//! # use std::str::FromStr; //! //! // to get args from cli use: //! // let cli_opt = WalletOpt::from_args(); @@ -85,27 +85,31 @@ //! //! let wallet = Arc::new(wallet); //! -//! let result = cli::handle_wallet_subcommand(&wallet, cli_opt.subcommand).unwrap(); +//! let result = bdk_cli::handle_wallet_subcommand(&wallet, cli_opt.subcommand).unwrap(); //! println!("{}", serde_json::to_string_pretty(&result).unwrap()); //! ``` +pub extern crate bdk; +#[macro_use] +extern crate serde_json; +#[cfg(any(target_arch = "wasm32", feature = "async-interface"))] +#[macro_use] +extern crate async_trait; +#[macro_use] +extern crate bdk_macros; + use std::collections::BTreeMap; use std::str::FromStr; use structopt::StructOpt; -#[allow(unused_imports)] -use log::{debug, error, info, trace, LevelFilter}; - -use bitcoin::consensus::encode::{deserialize, serialize, serialize_hex}; -use bitcoin::hashes::hex::FromHex; -use bitcoin::util::psbt::PartiallySignedTransaction; -use bitcoin::{Address, OutPoint, Script, Txid}; - -use crate::blockchain::log_progress; -use crate::error::Error; -use crate::types::KeychainKind; -use crate::{FeeRate, TxBuilder, Wallet}; +use bdk::bitcoin::consensus::encode::{deserialize, serialize, serialize_hex}; +use bdk::bitcoin::hashes::hex::FromHex; +use bdk::bitcoin::util::psbt::PartiallySignedTransaction; +use bdk::bitcoin::{Address, OutPoint, Script, Txid}; +use bdk::blockchain::log_progress; +use bdk::Error; +use bdk::{FeeRate, KeychainKind, TxBuilder, Wallet}; /// Wallet global options and sub-command /// @@ -116,8 +120,8 @@ use crate::{FeeRate, TxBuilder, Wallet}; /// # Example /// /// ``` -/// # use bdk::cli::{WalletOpt, WalletSubCommand}; /// # use structopt::StructOpt; +/// # use bdk_cli::{WalletSubCommand, WalletOpt}; /// /// let cli_args = vec!["repl", "--network", "testnet", /// "--descriptor", "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/44'/1'/0'/0/*)", @@ -214,14 +218,10 @@ pub struct WalletOpt { /// the command line or from a `String` vector, such as in the [`repl`](https://github.com/bitcoindevkit/bdk/blob/master/examples/repl.rs) /// example app. /// -/// Additional "external" sub-commands can be captured via the [`WalletSubCommand::Other`] enum and passed to a -/// custom `structopt` or another parser. See [structopt "External subcommands"](https://docs.rs/structopt/0.3.21/structopt/index.html#external-subcommands) -/// for more information. -/// /// # Example /// /// ``` -/// # use bdk::cli::WalletSubCommand; +/// # use bdk_cli::WalletSubCommand; /// # use structopt::StructOpt; /// /// let sync_sub_command = WalletSubCommand::from_iter(&["repl", "sync", "--max_addresses", "50"]); @@ -231,13 +231,6 @@ pub struct WalletOpt { /// max_addresses: Some(50) /// } /// )); -/// -/// let other_sub_command = WalletSubCommand::from_iter(&["repl", "custom", "--param1", "20"]); -/// let external_args: Vec = vec!["custom".to_string(), "--param1".to_string(), "20".to_string()]; -/// assert!(matches!( -/// other_sub_command, -/// WalletSubCommand::Other(v) if v == external_args -/// )); /// ``` /// /// To capture wallet sub-commands from a string vector without a preceeding binary name you can @@ -247,7 +240,7 @@ pub struct WalletOpt { /// /// # Example /// ``` -/// # use bdk::cli::WalletSubCommand; +/// # use bdk_cli::WalletSubCommand; /// # use structopt::StructOpt; /// # use clap::AppSettings; /// @@ -385,9 +378,8 @@ pub enum WalletSubCommand { #[structopt(name = "BASE64_PSBT", long = "psbt", required = true)] psbt: Vec, }, - /// Put any extra arguments into this Vec - #[structopt(external_subcommand)] - Other(Vec), + /// Enter REPL command loop mode + Repl, } fn parse_recipient(s: &str) -> Result<(Script, u64), String> { @@ -421,8 +413,8 @@ pub fn handle_wallet_subcommand( wallet_subcommand: WalletSubCommand, ) -> Result where - C: crate::blockchain::Blockchain, - D: crate::database::BatchDatabase, + C: bdk::blockchain::Blockchain, + D: bdk::database::BatchDatabase, { match wallet_subcommand { WalletSubCommand::GetNewAddress => Ok(json!({"address": wallet.get_new_address()?})), @@ -595,15 +587,15 @@ where Ok(json!({ "psbt": base64::encode(&serialize(&final_psbt)) })) } - WalletSubCommand::Other(_) => Ok(json!({})), + WalletSubCommand::Repl => Ok(json!({})), } } #[cfg(test)] mod test { use super::{WalletOpt, WalletSubCommand}; - use bitcoin::hashes::core::str::FromStr; - use bitcoin::{Address, OutPoint}; + use bdk::bitcoin::{Address, OutPoint}; + use std::str::FromStr; use structopt::StructOpt; #[test] diff --git a/examples/repl.rs b/src/repl.rs similarity index 93% rename from examples/repl.rs rename to src/repl.rs index bd04075..f23c384 100644 --- a/examples/repl.rs +++ b/src/repl.rs @@ -40,9 +40,9 @@ use bdk::blockchain::esplora::EsploraBlockchainConfig; use bdk::blockchain::{ AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain, ElectrumBlockchainConfig, }; -use bdk::cli::{self, WalletOpt, WalletSubCommand}; use bdk::sled; use bdk::Wallet; +use bdk_cli::{self, WalletOpt, WalletSubCommand}; #[derive(Debug, StructOpt, Clone, PartialEq)] #[structopt(name = "BDK Wallet", setting = AppSettings::NoBinaryName, @@ -94,7 +94,7 @@ fn main() { let esplora_concurrency = cli_opt.esplora_concurrency; cli_opt.esplora.map(|base_url| { AnyBlockchainConfig::Esplora(EsploraBlockchainConfig { - base_url: base_url.to_string(), + base_url, concurrency: Some(esplora_concurrency), }) }) @@ -123,7 +123,7 @@ fn main() { let wallet = Arc::new(wallet); match cli_opt.subcommand { - WalletSubCommand::Other(external) if external.contains(&"repl".to_string()) => { + WalletSubCommand::Repl => { let mut rl = Editor::<()>::new(); // if rl.load_history("history.txt").is_err() { @@ -138,7 +138,7 @@ fn main() { continue; } rl.add_history_entry(line.as_str()); - let split_line: Vec<&str> = line.split(" ").collect(); + let split_line: Vec<&str> = line.split(' ').collect(); let repl_subcommand: Result = ReplOpt::from_iter_safe(split_line); debug!("repl_subcommand = {:?}", repl_subcommand); @@ -148,7 +148,7 @@ fn main() { continue; } - let result = cli::handle_wallet_subcommand( + let result = bdk_cli::handle_wallet_subcommand( &Arc::clone(&wallet), repl_subcommand.unwrap().subcommand, ) @@ -167,7 +167,7 @@ fn main() { // rl.save_history("history.txt").unwrap(); } _ => { - let result = cli::handle_wallet_subcommand(&wallet, cli_opt.subcommand).unwrap(); + let result = bdk_cli::handle_wallet_subcommand(&wallet, cli_opt.subcommand).unwrap(); println!("{}", serde_json::to_string_pretty(&result).unwrap()); } } -- 2.49.0