From 36e41a3afa66f575955bf81c62b91dd32e43a9e5 Mon Sep 17 00:00:00 2001 From: Ikeh Celestine Chukwudi Date: Fri, 9 Oct 2026 11:17:58 +0100 Subject: [PATCH 1/2] refactor(compile): use ValueEnum for script type Replace the String script_type in CompileCommand with a ScriptType enum deriving clap::ValueEnum. The match in execute is now exhaustive, so the unreachable fallback arm is removed. No CLI behavior change. --- src/handlers/descriptor.rs | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/handlers/descriptor.rs b/src/handlers/descriptor.rs index e35fcea3..ba5005c5 100644 --- a/src/handlers/descriptor.rs +++ b/src/handlers/descriptor.rs @@ -13,6 +13,8 @@ use crate::{ }; use clap::Parser; #[cfg(feature = "compiler")] +use clap::ValueEnum; +#[cfg(feature = "compiler")] use { bdk_wallet::{ bitcoin::{ @@ -70,9 +72,24 @@ pub struct CompileCommand { #[arg(env = "POLICY", required = true, index = 1)] policy: String, /// Sets the script type used to embed the compiled policy. - #[arg(env = "TYPE", short = 't', long = "type", default_value = "wsh", value_parser = ["sh","wsh", "sh-wsh", "tr"] - )] - script_type: String, + #[arg( + env = "TYPE", + short = 't', + long = "type", + value_enum, + default_value_t = ScriptType::Wsh + )] + script_type: ScriptType, +} + +/// Script types the compiled policy can be embedded in. +#[cfg(feature = "compiler")] +#[derive(Clone, Copy, ValueEnum, Debug, Eq, PartialEq)] +pub enum ScriptType { + Sh, + Wsh, + ShWsh, + Tr, } #[cfg(feature = "compiler")] @@ -87,11 +104,11 @@ impl AppCommand> for CompileCommand { // Compile per branch, not once up front: the contexts have different script // limits, and the narrowest one would reject policies valid for the requested type. - let descriptor = match self.script_type.as_str() { - "sh" => Descriptor::new_sh(policy.compile()?), - "wsh" => Descriptor::new_wsh(policy.compile()?), - "sh-wsh" => Descriptor::new_sh_wsh(policy.compile()?), - "tr" => { + let descriptor = match self.script_type { + ScriptType::Sh => Descriptor::new_sh(policy.compile()?), + ScriptType::Wsh => Descriptor::new_wsh(policy.compile()?), + ScriptType::ShWsh => Descriptor::new_sh_wsh(policy.compile()?), + ScriptType::Tr => { // Use a randomized unspendable internal key (H + rG) instead of a fixed NUMS // point. This improves privacy by preventing observers from determining whether // key-path spending is disabled. `r` is returned so the user can verify the key @@ -113,11 +130,6 @@ impl AppCommand> for CompileCommand { let tree = TapTree::Leaf(Arc::new(policy.compile()?)); Descriptor::new_tr(xonly_internal_key.to_string(), Some(tree)) } - _ => { - return Err(Error::Generic( - "Invalid script type. Supported: sh, wsh, sh-wsh, tr".into(), - )); - } }?; Ok(DescriptorResult { From 79b2b8377bd0977d3f806ce1b82e3e88f0424f88 Mon Sep 17 00:00:00 2001 From: Ikeh Celestine Chukwudi Date: Fri, 9 Oct 2026 21:34:09 +0100 Subject: [PATCH 2/2] test(compile): cover sh and sh-wsh script types The existing compile tests only exercise wsh and tr. Add a test for the sh and sh-wsh branches so every ScriptType variant is covered. --- tests/integration/init.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/integration/init.rs b/tests/integration/init.rs index 5244d996..120341ab 100644 --- a/tests/integration/init.rs +++ b/tests/integration/init.rs @@ -223,6 +223,26 @@ mod test_compile { .stdout(predicate::str::contains("wsh(")); } + #[test] + fn test_compile_sh_and_sh_wsh() { + let temp_dir = TempDir::new().unwrap(); + let cli = BdkCli::new("testnet", Some(temp_dir.path().to_path_buf())); + + let policy = "pk(02e5b88fdb71c696e1a473f309a47535b7190e21a22bd25e7fc8bd055db3bba12f)"; + + // compile sh + cli.cmd("compile", &[policy, "--type", "sh"]) + .assert() + .success() + .stdout(predicate::str::contains("\"descriptor\": \"sh(pk(")); + + // compile sh-wsh + cli.cmd("compile", &[policy, "--type", "sh-wsh"]) + .assert() + .success() + .stdout(predicate::str::contains("\"descriptor\": \"sh(wsh(pk(")); + } + #[test] fn test_compile_invalid_policy() { let temp_dir = TempDir::new().unwrap();