bdk/examples/compiler.rs
LLFourn 326bfe82a8
Remove Blockchain from wallet
Although somewhat convenient to have, coupling the Wallet with
the blockchain trait causes development friction and complexity.
What if sometimes the wallet is "offline" (no access to the blockchain)
but sometimes its online?
The only thing the Wallet needs the blockchain for is to sync.
But not all applications will even use the sync method and the sync
method doesn't require the full blockchain functionality.
So we instead pass the blockchain in when we want to sync.

- To further reduce the coupling with blockchain I removed the get_height call from `new` and just use the height of the
last sync in the database.
- I split up the blockchain trait a bit into subtraits.
2022-02-24 20:39:00 +11:00

106 lines
3.1 KiB
Rust

// Bitcoin Dev Kit
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
//
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
extern crate bdk;
extern crate bitcoin;
extern crate clap;
extern crate log;
extern crate miniscript;
extern crate serde_json;
use std::error::Error;
use std::str::FromStr;
use log::info;
use clap::{App, Arg};
use bitcoin::Network;
use miniscript::policy::Concrete;
use miniscript::Descriptor;
use bdk::database::memory::MemoryDatabase;
use bdk::wallet::AddressIndex::New;
use bdk::{KeychainKind, Wallet};
fn main() -> Result<(), Box<dyn Error>> {
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", "bitcoin", "signet"]),
)
.get_matches();
let policy_str = matches.value_of("POLICY").unwrap();
info!("Compiling policy: {}", policy_str);
let policy = Concrete::<String>::from_str(policy_str)?;
let descriptor = match matches.value_of("TYPE").unwrap() {
"sh" => Descriptor::new_sh(policy.compile()?)?,
"wsh" => Descriptor::new_wsh(policy.compile()?)?,
"sh-wsh" => Descriptor::new_sh_wsh(policy.compile()?)?,
_ => panic!("Invalid type"),
};
info!("... Descriptor: {}", descriptor);
let database = MemoryDatabase::new();
let network = matches
.value_of("network")
.map(|n| Network::from_str(n))
.transpose()
.unwrap()
.unwrap_or(Network::Testnet);
let wallet = Wallet::new(&format!("{}", descriptor), None, network, database)?;
info!("... First address: {}", wallet.get_address(New)?);
if matches.is_present("parsed_policy") {
let spending_policy = wallet.policies(KeychainKind::External)?;
info!(
"... Spending policy:\n{}",
serde_json::to_string_pretty(&spending_policy)?
);
}
Ok(())
}