From 7328fdaf08b37ce417ba05efd5575f82b64656ed Mon Sep 17 00:00:00 2001 From: Chibey-max Date: Mon, 12 Oct 2026 17:20:30 +0100 Subject: [PATCH] fix(descriptor): explain descriptor key expression input --- CHANGELOG.md | 1 + src/utils/descriptors.rs | 6 ++++++ tests/integration/init.rs | 43 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b68802b3..1cdfb526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ page. See [DEVELOPMENT_CYCLE.md](DEVELOPMENT_CYCLE.md) for more details. - Routed compact filter (cbf) traffic through the configured SOCKS5 proxy - Rejected `--proxy` on the `rpc` backend, and unsupported proxy options (`--proxy_auth`, `--timeout`) on the `rpc` and `cbf` backends, instead of silently ignoring them - Fixed `compile` rejecting policies that are valid for the requested script type +- Improved the `descriptor` error when given a descriptor key expression instead of a raw extended key ## [4.0.0] diff --git a/src/utils/descriptors.rs b/src/utils/descriptors.rs index 3fa0490f..45abe09e 100644 --- a/src/utils/descriptors.rs +++ b/src/utils/descriptors.rs @@ -29,6 +29,12 @@ pub fn generate_descriptors( key: &str, network: NetworkKind, ) -> Result { + if key.trim_start().starts_with('[') { + return Err(Error::Generic( + "Descriptor key expressions are not accepted by this command. Provide a raw xpub/xprv, or use the expression in a full descriptor with `wallet config --ext-descriptor`.".to_string(), + )); + } + let is_private = key.starts_with("xprv") || key.starts_with("tprv"); if is_private { diff --git a/tests/integration/init.rs b/tests/integration/init.rs index 120341ab..d6b843da 100644 --- a/tests/integration/init.rs +++ b/tests/integration/init.rs @@ -48,6 +48,49 @@ mod test_key { .stdout(predicate::str::contains("\"xpub\":")); } + #[test] + fn test_descriptor_rejects_descriptor_key_expression_with_guidance() { + let temp_dir = TempDir::new().unwrap(); + let cli = BdkCli::new("testnet", Some(temp_dir.path().to_path_buf())); + + let generate_output = cli + .key_cmd(&["generate"]) + .output() + .expect("Failed to execute generate command"); + assert!(generate_output.status.success(), "Generate command failed"); + + let generate_json: Value = + serde_json::from_slice(&generate_output.stdout).expect("Invalid JSON"); + let xprv = generate_json["xprv"].as_str().expect("Missing XPRV"); + + let derive_output = cli + .key_cmd(&[ + "derive", + "--xprv", + xprv, + "--derivation_path", + "m/84'/1'/0'/0", + ]) + .output() + .expect("Failed to execute derive command"); + assert!(derive_output.status.success(), "Derive command failed"); + + let derive_json: Value = + serde_json::from_slice(&derive_output.stdout).expect("Invalid JSON"); + let descriptor_key = derive_json["xprv"] + .as_str() + .expect("Missing derived descriptor key"); + + cli.cmd("descriptor", &["--type", "wpkh", descriptor_key]) + .assert() + .failure() + .stderr(predicate::str::contains( + "Descriptor key expressions are not accepted by this command", + )) + .stderr(predicate::str::contains("Provide a raw xpub/xprv")) + .stderr(predicate::str::contains("wallet config --ext-descriptor")); + } + #[test] fn test_cli_key_restore() { let temp_dir = TempDir::new().unwrap();