Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding importdescriptors for Descriptor-Based Wallets #199

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,20 +276,33 @@ pub trait RpcApi: Sized {
blank: Option<bool>,
passphrase: Option<&str>,
avoid_reuse: Option<bool>,
descriptors: Option<bool>,
) -> Result<json::LoadWalletResult> {
let mut args = [
wallet.into(),
opt_into_json(disable_private_keys)?,
opt_into_json(blank)?,
opt_into_json(passphrase)?,
opt_into_json(avoid_reuse)?,
opt_into_json(descriptors)?,
];
self.call(
"createwallet",
handle_defaults(&mut args, &[false.into(), false.into(), into_json("")?, false.into()]),
handle_defaults(
&mut args,
&[false.into(), false.into(), into_json("")?, false.into(), false.into()],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last default option should be true.into() to be compatible with Bitcoin Core 23.

),
)
}

fn import_descriptors(
&self,
descriptors: Vec<json::ImportDescriptorRequest>,
) -> Result<Vec<json::ImportDescriptorResult>> {
let arg = into_json(descriptors)?;
self.call("importdescriptors", &[arg])
}

fn list_wallets(&self) -> Result<Vec<String>> {
self.call("listwallets", &[])
}
Expand Down Expand Up @@ -1136,7 +1149,6 @@ impl RpcApi for Client {
if log_enabled!(Debug) {
debug!(target: "bitcoincore_rpc", "JSON-RPC request: {} {}", cmd, serde_json::Value::from(args));
}

let resp = self.client.send_request(req).map_err(Error::from);
log_response(cmd, &resp);
Ok(resp?.result()?)
Expand Down
2 changes: 1 addition & 1 deletion integration_test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ authors = ["Steven Roose <steven@stevenroose.org>"]

[dependencies]
bitcoincore-rpc = { path = "../client" }
bitcoin = { version = "0.26", features = [ "use-serde", "rand" ] }
bitcoin = { version = "0.27", features = [ "use-serde", "rand" ] }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently master is at 0.28.0, but I believe we should drop the patch specification as before so users of the library can resolve the latest patch.

So just a rebase is in order and then we can drop the patch version :)

Suggested change
bitcoin = { version = "0.27", features = [ "use-serde", "rand" ] }
bitcoin = { version = "0.28", features = [ "use-serde", "rand" ] }

lazy_static = "1.4.0"
log = "0.4"
4 changes: 2 additions & 2 deletions integration_test/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ PID1=$!
sleep 3

BLOCKFILTERARG=""
if bitcoind -version | grep -q "v0\.\(19\|2\)"; then
if bitcoind -version | grep -q "v\(0\.19\|0\.2\|2\)"; then
BLOCKFILTERARG="-blockfilterindex=1"
fi

FALLBACKFEEARG=""
if bitcoind -version | grep -q "v0\.2"; then
if bitcoind -version | grep -q "v\(0\.2\|2\)"; then
FALLBACKFEEARG="-fallbackfee=0.00001000"
fi

Expand Down
41 changes: 37 additions & 4 deletions integration_test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ extern crate lazy_static;
extern crate log;

use std::collections::HashMap;
use std::str::FromStr;

use bitcoincore_rpc::json;
use bitcoincore_rpc::jsonrpc::error::Error as JsonRpcError;
Expand Down Expand Up @@ -125,15 +126,13 @@ fn main() {
log::set_logger(&LOGGER).map(|()| log::set_max_level(log::LevelFilter::max())).unwrap();

let rpc_url = format!("{}/wallet/testwallet", get_rpc_url());
let auth = get_auth();

let cl = Client::new(&rpc_url, auth).unwrap();
let cl = Client::new(&rpc_url, get_auth()).unwrap();

test_get_network_info(&cl);
unsafe { VERSION = cl.version().unwrap() };
println!("Version: {}", version());

cl.create_wallet("testwallet", None, None, None, None).unwrap();
cl.create_wallet("testwallet", None, None, None, None, None).unwrap();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to be Some(false) for Bitcoin Core 23 compatibility.


test_get_mining_info(&cl);
test_get_blockchain_info(&cl);
Expand Down Expand Up @@ -203,6 +202,11 @@ fn main() {
//TODO load_wallet(&self, wallet: &str) -> Result<json::LoadWalletResult> {
//TODO unload_wallet(&self, wallet: Option<&str>) -> Result<()> {
//TODO backup_wallet(&self, destination: Option<&str>) -> Result<()> {

let rpc_url = format!("{}/wallet/testdescriptorwallet", get_rpc_url());
let desc_cl = Client::new(&rpc_url, get_auth()).unwrap();

test_descriptor_wallet(&desc_cl);
test_stop(cl);
}

Expand Down Expand Up @@ -905,6 +909,7 @@ fn test_create_wallet(cl: &Client) {
blank: Option<bool>,
passphrase: Option<&'a str>,
avoid_reuse: Option<bool>,
descriptors: Option<bool>,
}

let mut wallet_params = vec![
Expand All @@ -914,20 +919,23 @@ fn test_create_wallet(cl: &Client) {
blank: None,
passphrase: None,
avoid_reuse: None,
descriptors: None,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bitcoin Core 23 now creates descriptor wallets by default. So in order for these tests to pass, this needs to be descriptors: Some(false) for each of these WalletParams.

},
WalletParams {
name: wallet_names[1],
disable_private_keys: Some(true),
blank: None,
passphrase: None,
avoid_reuse: None,
descriptors: None,
},
WalletParams {
name: wallet_names[2],
disable_private_keys: None,
blank: Some(true),
passphrase: None,
avoid_reuse: None,
descriptors: None,
},
];

Expand All @@ -938,13 +946,15 @@ fn test_create_wallet(cl: &Client) {
blank: None,
passphrase: Some("pass"),
avoid_reuse: None,
descriptors: None,
});
wallet_params.push(WalletParams {
name: wallet_names[4],
disable_private_keys: None,
blank: None,
passphrase: None,
avoid_reuse: Some(true),
descriptors: None,
});
}

Expand All @@ -956,6 +966,7 @@ fn test_create_wallet(cl: &Client) {
wallet_param.blank,
wallet_param.passphrase,
wallet_param.avoid_reuse,
wallet_param.descriptors,
)
.unwrap();

Expand Down Expand Up @@ -1050,3 +1061,25 @@ fn test_getblocktemplate(cl: &Client) {
fn test_stop(cl: Client) {
println!("Stopping: '{}'", cl.stop().unwrap());
}

fn test_descriptor_wallet(cl: &Client) {
cl.create_wallet(
"testdescriptorwallet",
Some(false),
Some(true),
Some(""),
Some(false),
Some(true),
)
.unwrap();

cl.import_descriptors(
vec![
json::ImportDescriptorRequest::new("wpkh(tprv8ZgxMBicQKsPeRBCAfUGsZhyHy9dwWyPqhSJmaMnMJQWWtt8L2SkTeHaiF82CUCGtiTiHAs3cMkjdKckGKiCWeYtvMPF1jDTWYTryRMicpx/86h/1h/0h/0/*)#ymr4jlz6", false),
json::ImportDescriptorRequest::new("wpkh(tprv8ZgxMBicQKsPeRBCAfUGsZhyHy9dwWyPqhSJmaMnMJQWWtt8L2SkTeHaiF82CUCGtiTiHAs3cMkjdKckGKiCWeYtvMPF1jDTWYTryRMicpx/86h/1h/0h/1/*)#40x502jz", true),
]
).unwrap();

let add = cl.get_new_address(None, Some(json::AddressType::Bech32)).unwrap();
assert_eq!(add, Address::from_str("bcrt1q7crcza94drr00skmu5x0n00rhmwnthde2frhwk").unwrap());
}
2 changes: 1 addition & 1 deletion json/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ path = "src/lib.rs"
serde = { version = "1", features = [ "derive" ] }
serde_json = "1"

bitcoin = { version = "0.26", features = [ "use-serde" ] }
bitcoin = { version = "0.27", features = [ "use-serde" ] }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bitcoin = { version = "0.27", features = [ "use-serde" ] }
bitcoin = { version = "0.28", features = [ "use-serde" ] }

39 changes: 38 additions & 1 deletion json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1066,11 +1066,13 @@ pub struct GetPeerInfoResult {
}

#[derive(Copy, Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
#[serde(rename_all = "lowercase")]
#[serde(rename_all = "snake_case")]
pub enum GetPeerInfoResultNetwork {
Ipv4,
Ipv6,
Onion,
I2p,
NotPubliclyRoutable,
// this is undocumented upstream
Unroutable,
}
Expand Down Expand Up @@ -1607,6 +1609,7 @@ pub enum AddressType {
Legacy,
P2shSegwit,
Bech32,
Bech32m,
}

/// Used to represent arguments that can either be an address or a public key.
Expand Down Expand Up @@ -1686,3 +1689,37 @@ where
}
Ok(Some(res))
}

/// Import Descriptor Request
#[derive(Serialize, Clone, PartialEq, Eq, Debug)]
pub struct ImportDescriptorRequest {
pub active: bool,
#[serde(rename = "desc")]
pub descriptor: String,
pub range: [i64; 2],
pub next_index: i64,
pub timestamp: String,
pub internal: bool,
}

impl ImportDescriptorRequest {
/// Create a new Import Descriptor request providing just the descriptor and internal flags
pub fn new(descriptor: &str, internal: bool) -> Self {
ImportDescriptorRequest {
descriptor: descriptor.to_string(),
internal,
active: true,
range: [0, 100],
next_index: 0,
timestamp: "now".to_string(),
}
}
}

/// Imported Descriptor Result
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct ImportDescriptorResult {
pub success: bool,
pub warnings: Option<Vec<String>>,
pub error: Option<String>,
}