diff --git a/src/descriptor/dsl.rs b/src/descriptor/dsl.rs index 76eb4ecd..b9acce3b 100644 --- a/src/descriptor/dsl.rs +++ b/src/descriptor/dsl.rs @@ -571,8 +571,9 @@ macro_rules! fragment { ( pk ( $key:expr ) ) => ({ $crate::fragment!(c:pk_k ( $key )) }); - ( pk_h ( $key_hash:expr ) ) => ({ - $crate::impl_leaf_opcode_value!(PkH, $key_hash) + ( pk_h ( $key:expr ) ) => ({ + let secp = $crate::bitcoin::secp256k1::Secp256k1::new(); + $crate::keys::make_pkh($key, &secp) }); ( after ( $value:expr ) ) => ({ $crate::impl_leaf_opcode_value!(After, $value) @@ -601,6 +602,9 @@ macro_rules! fragment { ( and_or ( $( $inner:tt )* ) ) => ({ $crate::impl_node_opcode_three!(AndOr, $( $inner )*) }); + ( andor ( $( $inner:tt )* ) ) => ({ + $crate::impl_node_opcode_three!(AndOr, $( $inner )*) + }); ( or_b ( $( $inner:tt )* ) ) => ({ $crate::impl_node_opcode_two!(OrB, $( $inner )*) }); diff --git a/src/descriptor/policy.rs b/src/descriptor/policy.rs index 4a6e93b4..f3baa3e0 100644 --- a/src/descriptor/policy.rs +++ b/src/descriptor/policy.rs @@ -47,14 +47,12 @@ use bitcoin::util::bip32::Fingerprint; use bitcoin::PublicKey; use miniscript::descriptor::{DescriptorPublicKey, ShInner, SortedMultiVec, WshInner}; -use miniscript::{ - Descriptor, Miniscript, MiniscriptKey, Satisfier, ScriptContext, Terminal, ToPublicKey, -}; +use miniscript::{Descriptor, Miniscript, MiniscriptKey, Satisfier, ScriptContext, Terminal}; #[allow(unused_imports)] use log::{debug, error, info, trace}; -use crate::descriptor::{DerivedDescriptorKey, ExtractPolicy}; +use crate::descriptor::ExtractPolicy; use crate::wallet::signer::{SignerId, SignersContainer}; use crate::wallet::utils::{self, After, Older, SecpCtx}; @@ -88,13 +86,6 @@ impl PkOrF { }, } } - - fn from_key_hash(k: hash160::Hash) -> Self { - PkOrF { - pubkey_hash: Some(k), - ..Default::default() - } - } } /// An item that needs to be satisfied @@ -779,25 +770,6 @@ fn signature_in_psbt(psbt: &Psbt, key: &DescriptorPublicKey, secp: &SecpCtx) -> }) } -fn signature_key( - key: &::Hash, - signers: &SignersContainer, - secp: &SecpCtx, -) -> Policy { - let key_hash = DerivedDescriptorKey::new(key.clone(), secp) - .to_public_key() - .to_pubkeyhash(); - let mut policy: Policy = SatisfiableItem::Signature(PkOrF::from_key_hash(key_hash)).into(); - - if signers.find(SignerId::PkHash(key_hash)).is_some() { - policy.contribution = Satisfaction::Complete { - condition: Default::default(), - } - } - - policy -} - impl ExtractPolicy for Miniscript { fn extract_policy( &self, @@ -809,7 +781,7 @@ impl ExtractPolicy for Miniscript // Leaves Terminal::True | Terminal::False => None, Terminal::PkK(pubkey) => Some(signature(pubkey, signers, build_sat, secp)), - Terminal::PkH(pubkey_hash) => Some(signature_key(pubkey_hash, signers, secp)), + Terminal::PkH(pubkey_hash) => Some(signature(pubkey_hash, signers, build_sat, secp)), Terminal::After(value) => { let mut policy: Policy = SatisfiableItem::AbsoluteTimelock { value: *value }.into(); policy.contribution = Satisfaction::Complete { @@ -1444,6 +1416,7 @@ mod test { const ALICE_TPRV_STR:&str = "tprv8ZgxMBicQKsPf6T5X327efHnvJDr45Xnb8W4JifNWtEoqXu9MRYS4v1oYe6DFcMVETxy5w3bqpubYRqvcVTqovG1LifFcVUuJcbwJwrhYzP"; const BOB_TPRV_STR:&str = "tprv8ZgxMBicQKsPeinZ155cJAn117KYhbaN6MV3WeG6sWhxWzcvX1eg1awd4C9GpUN1ncLEM2rzEvunAg3GizdZD4QPPCkisTz99tXXB4wZArp"; + const CAROL_TPRV_STR:&str = "tprv8ZgxMBicQKsPdC3CicFifuLCEyVVdXVUNYorxUWj3iGZ6nimnLAYAY9SYB7ib8rKzRxrCKFcEytCt6szwd2GHnGPRCBLAEAoSVDefSNk4Bt"; const ALICE_BOB_PATH: &str = "m/0'"; #[test] @@ -1602,4 +1575,28 @@ mod test { ); //println!("{}", serde_json::to_string(&policy_expired_signed).unwrap()); } + + #[test] + fn test_extract_pkh() { + let secp = Secp256k1::new(); + + let (prvkey_alice, _, _) = setup_keys(ALICE_TPRV_STR, ALICE_BOB_PATH, &secp); + let (prvkey_bob, _, _) = setup_keys(BOB_TPRV_STR, ALICE_BOB_PATH, &secp); + let (prvkey_carol, _, _) = setup_keys(CAROL_TPRV_STR, ALICE_BOB_PATH, &secp); + + let desc = descriptor!(wsh(c: andor( + pk(prvkey_alice), + pk_k(prvkey_bob), + pk_h(prvkey_carol), + ))) + .unwrap(); + + let (wallet_desc, keymap) = desc + .into_wallet_descriptor(&secp, Network::Testnet) + .unwrap(); + let signers_container = Arc::new(SignersContainer::from(keymap)); + + let policy = wallet_desc.extract_policy(&signers_container, BuildSatisfaction::None, &secp); + assert!(policy.is_ok()); + } } diff --git a/src/keys/mod.rs b/src/keys/mod.rs index 1fbeada7..15b53e15 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -753,6 +753,20 @@ pub fn make_pk, Ctx: ScriptContext>( Ok((minisc, key_map, valid_networks)) } +// Used internally by `bdk::fragment!` to build `pk_h()` fragments +#[doc(hidden)] +pub fn make_pkh, Ctx: ScriptContext>( + descriptor_key: Pk, + secp: &SecpCtx, +) -> Result<(Miniscript, KeyMap, ValidNetworks), DescriptorError> { + let (key, key_map, valid_networks) = descriptor_key.into_descriptor_key()?.extract(secp)?; + let minisc = Miniscript::from_ast(Terminal::PkH(key))?; + + minisc.check_minsicript()?; + + Ok((minisc, key_map, valid_networks)) +} + // Used internally by `bdk::fragment!` to build `multi()` fragments #[doc(hidden)] pub fn make_multi, Ctx: ScriptContext>(