@@ -51,6 +51,8 @@ use crate::utils::BlockchainClient::Electrum;
5151#[ cfg( feature = "cbf" ) ]
5252use bdk_kyoto:: { Info , LightClient } ;
5353use bdk_wallet:: bitcoin:: base64:: prelude:: * ;
54+ #[ cfg( feature = "compiler" ) ]
55+ use bdk_wallet:: bitcoin:: XOnlyPublicKey ;
5456#[ cfg( feature = "cbf" ) ]
5557use tokio:: select;
5658#[ cfg( any(
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