@@ -292,11 +292,18 @@ impl Plan {
292292 } )
293293 . into_script ( ) ,
294294 ) ,
295- DescriptorType :: Wpkh
296- | DescriptorType :: Wsh
295+ DescriptorType :: Wpkh | DescriptorType :: Tr => ( stack, ScriptBuf :: new ( ) ) ,
296+ DescriptorType :: ShWpkh => ( stack, self . descriptor . unsigned_script_sig ( ) ) ,
297+ DescriptorType :: Wsh
297298 | DescriptorType :: WshSortedMulti
298- | DescriptorType :: Tr => ( stack, ScriptBuf :: new ( ) ) ,
299- DescriptorType :: ShWsh | DescriptorType :: ShWshSortedMulti | DescriptorType :: ShWpkh => {
299+ | DescriptorType :: ShWsh
300+ | DescriptorType :: ShWshSortedMulti => {
301+ let mut stack = stack;
302+ let witness_script = self
303+ . descriptor
304+ . explicit_script ( )
305+ . expect ( "wsh descriptors have explicit script" ) ;
306+ stack. push ( witness_script. into_bytes ( ) ) ;
300307 ( stack, self . descriptor . unsigned_script_sig ( ) )
301308 }
302309 } )
@@ -1154,4 +1161,89 @@ mod test {
11541161 assert ! ( psbt_input. redeem_script. is_none( ) , "Redeem script present" ) ;
11551162 assert_eq ! ( psbt_input. bip32_derivation. len( ) , 2 , "Unexpected number of bip32_derivation" ) ;
11561163 }
1164+
1165+ #[ test]
1166+ fn test_plan_satisfy_wsh ( ) {
1167+ use std:: collections:: BTreeMap ;
1168+
1169+ use bitcoin:: secp256k1:: { self , Secp256k1 } ;
1170+
1171+ let secp = Secp256k1 :: new ( ) ;
1172+
1173+ let sk =
1174+ secp256k1:: SecretKey :: from_slice ( & b"sally was a secret key, she said" [ ..] ) . unwrap ( ) ;
1175+ let pk = bitcoin:: PublicKey :: new ( secp256k1:: PublicKey :: from_secret_key ( & secp, & sk) ) ;
1176+
1177+ let desc =
1178+ Descriptor :: < DefiniteDescriptorKey > :: from_str ( & format ! ( "wsh(pk({}))" , pk) ) . unwrap ( ) ;
1179+
1180+ let sighash =
1181+ secp256k1:: Message :: from_digest_slice ( & b"michael was a message, amusingly" [ ..] )
1182+ . expect ( "32 bytes" ) ;
1183+ let ecdsa_sig = bitcoin:: ecdsa:: Signature {
1184+ signature : secp. sign_ecdsa ( & sighash, & sk) ,
1185+ sighash_type : bitcoin:: sighash:: EcdsaSighashType :: All ,
1186+ } ;
1187+
1188+ // This witness script should exist in the witness stack returned by `Plan::satisfy`.
1189+ let exp_witness_script = desc. explicit_script ( ) . expect ( "wsh has explicit script" ) ;
1190+
1191+ let mut satisfier = BTreeMap :: < DefiniteDescriptorKey , bitcoin:: ecdsa:: Signature > :: new ( ) ;
1192+ satisfier. insert ( DefiniteDescriptorKey :: from_str ( & pk. to_string ( ) ) . unwrap ( ) , ecdsa_sig) ;
1193+
1194+ let assets = Assets :: new ( ) . add ( DescriptorPublicKey :: from_str ( & pk. to_string ( ) ) . unwrap ( ) ) ;
1195+ let plan = desc. plan ( & assets) . expect ( "plan should succeed" ) ;
1196+
1197+ let ( witness, script_sig) = plan. satisfy ( & satisfier) . expect ( "satisfy should succeed" ) ;
1198+
1199+ // For native P2WSH:
1200+ // - script_sig should be empty
1201+ // - witness should contain [signature, witness_script]
1202+ assert_eq ! ( script_sig, ScriptBuf :: new( ) ) ;
1203+ assert_eq ! ( witness. len( ) , 2 ) ;
1204+ assert_eq ! ( witness. last( ) . unwrap( ) , & exp_witness_script. into_bytes( ) ) ;
1205+ }
1206+
1207+ #[ test]
1208+ fn test_plan_satisfy_sh_wsh ( ) {
1209+ use std:: collections:: BTreeMap ;
1210+
1211+ use bitcoin:: secp256k1:: { self , Secp256k1 } ;
1212+
1213+ let secp = Secp256k1 :: new ( ) ;
1214+ let sk =
1215+ secp256k1:: SecretKey :: from_slice ( & b"sally was a secret key, she said" [ ..] ) . unwrap ( ) ;
1216+ let pk = bitcoin:: PublicKey :: new ( secp256k1:: PublicKey :: from_secret_key ( & secp, & sk) ) ;
1217+
1218+ let desc =
1219+ Descriptor :: < DefiniteDescriptorKey > :: from_str ( & format ! ( "sh(wsh(pk({})))" , pk) ) . unwrap ( ) ;
1220+
1221+ let sighash =
1222+ secp256k1:: Message :: from_digest_slice ( & b"michael was a message, amusingly" [ ..] )
1223+ . expect ( "32 bytes" ) ;
1224+ let ecdsa_sig = bitcoin:: ecdsa:: Signature {
1225+ signature : secp. sign_ecdsa ( & sighash, & sk) ,
1226+ sighash_type : bitcoin:: sighash:: EcdsaSighashType :: All ,
1227+ } ;
1228+
1229+ // Get expected values before plan() consumes the descriptor.
1230+ let exp_witness_script = desc. explicit_script ( ) . expect ( "sh-wsh has explicit script" ) ;
1231+ let exp_script_sig = desc. unsigned_script_sig ( ) ;
1232+
1233+ let mut satisfier: BTreeMap < DefiniteDescriptorKey , bitcoin:: ecdsa:: Signature > =
1234+ BTreeMap :: new ( ) ;
1235+ satisfier. insert ( DefiniteDescriptorKey :: from_str ( & pk. to_string ( ) ) . unwrap ( ) , ecdsa_sig) ;
1236+
1237+ let assets = Assets :: new ( ) . add ( DescriptorPublicKey :: from_str ( & pk. to_string ( ) ) . unwrap ( ) ) ;
1238+ let plan = desc. plan ( & assets) . expect ( "plan should succeed" ) ;
1239+
1240+ let ( witness, script_sig) = plan. satisfy ( & satisfier) . expect ( "satisfy should succeed" ) ;
1241+
1242+ // For P2SH-P2WSH:
1243+ // - script_sig should be the unsigned_script_sig (pushes the P2WSH redeemScript)
1244+ // - witness should contain [signature, witness_script]
1245+ assert_eq ! ( script_sig, exp_script_sig) ;
1246+ assert_eq ! ( witness. len( ) , 2 ) ;
1247+ assert_eq ! ( witness. last( ) . unwrap( ) , & exp_witness_script. into_bytes( ) ) ;
1248+ }
11571249}
0 commit comments