Skip to content

Commit 78bf36c

Browse files
committed
fix(review): resolve review comments
1 parent 69df5b3 commit 78bf36c

1 file changed

Lines changed: 57 additions & 8 deletions

File tree

src/handlers.rs

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ use crate::utils::BlockchainClient::Electrum;
5151
#[cfg(feature = "cbf")]
5252
use bdk_kyoto::{Info, LightClient};
5353
use bdk_wallet::bitcoin::base64::prelude::*;
54+
#[cfg(feature = "compiler")]
55+
use bdk_wallet::bitcoin::XOnlyPublicKey;
5456
#[cfg(feature = "cbf")]
5557
use tokio::select;
5658
#[cfg(any(
@@ -72,10 +74,8 @@ use {
7274
bdk_wallet::chain::{BlockId, CanonicalizationParams, CheckPoint},
7375
};
7476

75-
/// Well-known unspendable key used for Taproot descriptors when only script path is intended.
76-
/// This is a NUMS (Nothing Up My Sleeve) point that ensures the key path cannot be used.
7777
#[cfg(feature = "compiler")]
78-
const NUMS_UNSPENDABLE_KEY: &str =
78+
const NUMS_UNSPENDABLE_KEY_HEX: &str =
7979
"50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
8080

8181
/// Execute an offline wallet sub-command
@@ -741,10 +741,19 @@ pub(crate) fn handle_compile_subcommand(
741741
// For tr descriptors, we use a well-known unspendable key (NUMS point).
742742
// This ensures the key path is effectively disabled and only script path can be used.
743743
// See https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs
744+
745+
// Validate that the NUMS key is a valid XOnlyPublicKey
746+
XOnlyPublicKey::from_str(NUMS_UNSPENDABLE_KEY_HEX)
747+
.map_err(|e| Error::Generic(format!("Invalid NUMS key: {e}")))?;
748+
744749
let tree = TapTree::Leaf(Arc::new(taproot_policy));
745-
Descriptor::new_tr(NUMS_UNSPENDABLE_KEY.to_string(), Some(tree))
750+
Descriptor::new_tr(NUMS_UNSPENDABLE_KEY_HEX.to_string(), Some(tree))
751+
}
752+
_ => {
753+
return Err(Error::Generic(
754+
"Invalid script type. Supported types: sh, wsh, sh-wsh, tr".to_string(),
755+
))
746756
}
747-
_ => panic!("Invalid type"),
748757
}?;
749758

750759
Ok(json!({"descriptor": descriptor.to_string()}))
@@ -1016,7 +1025,7 @@ mod test {
10161025
#[cfg(feature = "compiler")]
10171026
#[test]
10181027
fn test_compile_taproot() {
1019-
use super::{handle_compile_subcommand, NUMS_UNSPENDABLE_KEY};
1028+
use super::{handle_compile_subcommand, NUMS_UNSPENDABLE_KEY_HEX};
10201029
use bdk_wallet::bitcoin::Network;
10211030

10221031
// Expected taproot descriptors with checksums
@@ -1025,8 +1034,8 @@ mod test {
10251034
const EXPECTED_AND_AB: &str = "tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,and_v(v:pk(A),pk(B)))#sfplm6kv";
10261035

10271036
// Verify our test expectations use the same NUMS key
1028-
assert!(EXPECTED_PK_A.contains(NUMS_UNSPENDABLE_KEY));
1029-
assert!(EXPECTED_AND_AB.contains(NUMS_UNSPENDABLE_KEY));
1037+
assert!(EXPECTED_PK_A.contains(NUMS_UNSPENDABLE_KEY_HEX));
1038+
assert!(EXPECTED_AND_AB.contains(NUMS_UNSPENDABLE_KEY_HEX));
10301039

10311040
// Test simple pk policy compilation to taproot
10321041
let result =
@@ -1047,4 +1056,44 @@ mod test {
10471056
let descriptor = json_result.get("descriptor").unwrap().as_str().unwrap();
10481057
assert_eq!(descriptor, EXPECTED_AND_AB);
10491058
}
1059+
1060+
#[cfg(feature = "compiler")]
1061+
#[test]
1062+
fn test_compile_invalid_cases() {
1063+
use super::handle_compile_subcommand;
1064+
use bdk_wallet::bitcoin::Network;
1065+
1066+
// Test invalid policy syntax
1067+
let result = handle_compile_subcommand(
1068+
Network::Testnet,
1069+
"invalid_policy".to_string(),
1070+
"tr".to_string(),
1071+
);
1072+
assert!(result.is_err());
1073+
1074+
// Test invalid script type
1075+
let result = handle_compile_subcommand(
1076+
Network::Testnet,
1077+
"pk(A)".to_string(),
1078+
"invalid_type".to_string(),
1079+
);
1080+
assert!(result.is_err());
1081+
1082+
// Test empty policy
1083+
let result = handle_compile_subcommand(Network::Testnet, "".to_string(), "tr".to_string());
1084+
assert!(result.is_err());
1085+
1086+
// Test malformed policy with unmatched parentheses
1087+
let result =
1088+
handle_compile_subcommand(Network::Testnet, "pk(A".to_string(), "tr".to_string());
1089+
assert!(result.is_err());
1090+
1091+
// Test policy with unknown function
1092+
let result = handle_compile_subcommand(
1093+
Network::Testnet,
1094+
"unknown_func(A)".to_string(),
1095+
"tr".to_string(),
1096+
);
1097+
assert!(result.is_err());
1098+
}
10501099
}

0 commit comments

Comments
 (0)