From aa93a829043e7279ab4c7ab4411446834c8ab732 Mon Sep 17 00:00:00 2001 From: Alekos Filini Date: Wed, 29 Apr 2020 11:52:45 +0200 Subject: [PATCH] Add a miniscript compiler CLI --- Cargo.toml | 7 +++ examples/compiler.rs | 110 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 +- src/wallet/mod.rs | 2 + 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 examples/compiler.rs diff --git a/Cargo.toml b/Cargo.toml index d185ad9f..0edd8c32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ electrum-client = { version = "0.1.0-beta.5", optional = true } [features] minimal = [] +compiler = ["miniscript/compiler"] default = ["sled", "electrum-client"] electrum = ["electrum-client"] key-value-db = ["sled"] @@ -27,6 +28,7 @@ rustyline = "5.0" # newer version requires 2018 edition clap = "2.33" dirs = "2.0" env_logger = "0.7" +rand = "0.7" [[example]] name = "repl" @@ -35,6 +37,11 @@ name = "psbt" [[example]] name = "parse_descriptor" +[[example]] +name = "miniscriptc" +path = "examples/compiler.rs" +required-features = ["compiler"] + # Provide a more user-friendly alias for the REPL [[example]] name = "magic" diff --git a/examples/compiler.rs b/examples/compiler.rs new file mode 100644 index 00000000..09cad948 --- /dev/null +++ b/examples/compiler.rs @@ -0,0 +1,110 @@ +extern crate bitcoin; +extern crate clap; +extern crate log; +extern crate magical_bitcoin_wallet; +extern crate miniscript; +extern crate rand; +extern crate serde_json; +extern crate sled; + +use std::str::FromStr; + +use log::info; + +use rand::distributions::Alphanumeric; +use rand::{thread_rng, Rng}; + +use clap::{App, Arg}; + +use bitcoin::Network; +use miniscript::policy::Concrete; +use miniscript::Descriptor; + +use magical_bitcoin_wallet::types::ScriptType; +use magical_bitcoin_wallet::{OfflineWallet, Wallet}; + +fn main() { + env_logger::init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), + ); + + let matches = App::new("Miniscript Compiler") + .arg( + Arg::with_name("POLICY") + .help("Sets the spending policy to compile") + .required(true) + .index(1), + ) + .arg( + Arg::with_name("TYPE") + .help("Sets the script type used to embed the compiled policy") + .required(true) + .index(2) + .possible_values(&["sh", "wsh", "sh-wsh"]), + ) + .arg( + Arg::with_name("parsed_policy") + .long("parsed_policy") + .short("p") + .help("Also return the parsed spending policy in JSON format"), + ) + .arg( + Arg::with_name("network") + .short("n") + .long("network") + .help("Sets the network") + .takes_value(true) + .default_value("testnet") + .possible_values(&["testnet", "regtest"]), + ) + .get_matches(); + + let policy_str = matches.value_of("POLICY").unwrap(); + info!("Compiling policy: {}", policy_str); + + let policy = Concrete::::from_str(&policy_str).unwrap(); + let compiled = policy.compile().unwrap(); + + let descriptor = match matches.value_of("TYPE").unwrap() { + "sh" => Descriptor::Sh(compiled), + "wsh" => Descriptor::Wsh(compiled), + "sh-wsh" => Descriptor::ShWsh(compiled), + _ => panic!("Invalid type"), + }; + + info!("... Descriptor: {}", descriptor); + + let temp_db = { + let mut temp_db = std::env::temp_dir(); + let rand_string: String = thread_rng().sample_iter(&Alphanumeric).take(15).collect(); + temp_db.push(rand_string); + + let database = sled::open(&temp_db).unwrap(); + + let network = match matches.value_of("network") { + Some("regtest") => Network::Regtest, + Some("testnet") | _ => Network::Testnet, + }; + let wallet: OfflineWallet<_> = Wallet::new_offline( + &format!("{}", descriptor), + None, + network, + database.open_tree("").unwrap(), + ) + .unwrap(); + + info!("... First address: {}", wallet.get_new_address().unwrap()); + + if matches.is_present("parsed_policy") { + let spending_policy = wallet.policies(ScriptType::External).unwrap(); + info!( + "... Spending policy:\n{}", + serde_json::to_string_pretty(&spending_policy).unwrap() + ); + } + + temp_db + }; + + std::fs::remove_dir_all(temp_db).unwrap(); +} diff --git a/src/lib.rs b/src/lib.rs index 2553d1ad..2d122d98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,4 +26,4 @@ pub mod types; pub mod wallet; pub use descriptor::ExtendedDescriptor; -pub use wallet::Wallet; +pub use wallet::{OfflineWallet, Wallet}; diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 048e5153..871d09ed 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -23,6 +23,8 @@ use log::{debug, error, info, trace}; pub mod offline_stream; pub mod utils; +pub type OfflineWallet = Wallet; + use self::utils::{ChunksIterator, IsDust}; use crate::database::{BatchDatabase, BatchOperations}; use crate::descriptor::{get_checksum, DescriptorMeta, ExtendedDescriptor, ExtractPolicy, Policy};