diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index d0388554c..62dddf633 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -179,6 +179,75 @@ impl Terminal { }; Ok(frag) } + + /// Substitutes raw public keys hashes with the public keys as provided by map. + pub fn substitute_raw_pkh(&self, pk_map: &BTreeMap) -> Terminal { + match self { + Terminal::RawPkH(ref p) => match pk_map.get(p) { + Some(pk) => Terminal::PkH(pk.clone()).into(), + None => Terminal::RawPkH(*p).into(), + }, + Terminal::PkK(..) + | Terminal::PkH(..) + | Terminal::Multi(..) + | Terminal::MultiA(..) + | Terminal::After(..) + | Terminal::Older(..) + | Terminal::Sha256(..) + | Terminal::Hash256(..) + | Terminal::Ripemd160(..) + | Terminal::Hash160(..) + | Terminal::True + | Terminal::False => self.clone().into(), + Terminal::Alt(ref sub) => Terminal::Alt(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::Swap(ref sub) => Terminal::Swap(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::Check(ref sub) => Terminal::Check(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::DupIf(ref sub) => Terminal::DupIf(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::Verify(ref sub) => Terminal::Verify(Arc::new(sub.substitute_raw_pkh(pk_map))), + Terminal::NonZero(ref sub) => { + Terminal::NonZero(Arc::new(sub.substitute_raw_pkh(pk_map))) + } + Terminal::ZeroNotEqual(ref sub) => { + Terminal::ZeroNotEqual(Arc::new(sub.substitute_raw_pkh(pk_map))) + } + Terminal::AndV(ref left, ref right) => Terminal::AndV( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::AndB(ref left, ref right) => Terminal::AndB( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::AndOr(ref a, ref b, ref c) => Terminal::AndOr( + Arc::new(a.substitute_raw_pkh(pk_map)), + Arc::new(b.substitute_raw_pkh(pk_map)), + Arc::new(c.substitute_raw_pkh(pk_map)), + ), + Terminal::OrB(ref left, ref right) => Terminal::OrB( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::OrD(ref left, ref right) => Terminal::OrD( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::OrC(ref left, ref right) => Terminal::OrC( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::OrI(ref left, ref right) => Terminal::OrI( + Arc::new(left.substitute_raw_pkh(pk_map)), + Arc::new(right.substitute_raw_pkh(pk_map)), + ), + Terminal::Thresh(k, ref subs) => { + let subs: Vec>> = subs + .iter() + .map(|s| Arc::new(s.substitute_raw_pkh(pk_map))) + .collect(); + Terminal::Thresh(*k, subs) + } + } + } } impl ForEachKey for Terminal { diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index c73a7bd4e..c31199d6b 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -16,6 +16,7 @@ use core::marker::PhantomData; use core::{fmt, hash, str}; +use bitcoin::hashes::hash160; use bitcoin::script; use bitcoin::taproot::{LeafVersion, TapLeafHash}; @@ -334,6 +335,11 @@ impl Miniscript { let inner = self.node.real_translate_pk(t)?; Miniscript::from_ast(inner).map_err(TranslateErr::OuterError) } + + /// Substitutes raw public keys hashes with the public keys as provided by map. + pub fn substitute_raw_pkh(&self, pk_map: &BTreeMap) -> Miniscript { + Miniscript::from_ast(self.node.substitute_raw_pkh(pk_map)).expect("type check failed") + } } impl_block_str!( diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index c0bf447c9..28902cc36 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -8,6 +8,7 @@ //! `https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki` //! +use bitcoin::hashes::hash160; use bitcoin::key::XOnlyPublicKey; use bitcoin::secp256k1::{self, Secp256k1}; use bitcoin::sighash::Prevouts; @@ -122,6 +123,22 @@ pub(super) fn prevouts(psbt: &Psbt) -> Result, super::Error // we want to move the script is probably already created // and we want to satisfy it in any way possible. fn get_descriptor(psbt: &Psbt, index: usize) -> Result, InputError> { + // Create a HashMap + let mut hash_map: BTreeMap = BTreeMap::new(); + let psbt_inputs = &psbt.inputs; + for psbt_input in psbt_inputs { + // Use BIP32 Derviation to get set of all possible keys. + let public_keys = psbt_input.bip32_derivation.keys(); + for key in public_keys { + // Convert bitcoin::secp256k1::PublicKey into just bitcoin::PublicKey + let bitcoin_key = bitcoin::PublicKey::new(*key); + // Convert PubKeyHash into Hash::hash160 + let hash = bitcoin_key.pubkey_hash().to_raw_hash(); + // Insert pair in HashMap + hash_map.insert(hash, bitcoin_key); + } + } + // Figure out Scriptpubkey let script_pubkey = get_scriptpubkey(psbt, index)?; let inp = &psbt.inputs[index]; @@ -178,7 +195,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In witness_script, &ExtParams::allow_all(), )?; - Ok(Descriptor::new_wsh(ms)?) + Ok(Descriptor::new_wsh(ms.substitute_raw_pkh(&hash_map))?) } else { Err(InputError::MissingWitnessScript) } @@ -205,7 +222,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In witness_script, &ExtParams::allow_all(), )?; - Ok(Descriptor::new_sh_wsh(ms)?) + Ok(Descriptor::new_sh_wsh(ms.substitute_raw_pkh(&hash_map))?) } else { Err(InputError::MissingWitnessScript) } @@ -249,7 +266,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In &script_pubkey, &ExtParams::allow_all(), )?; - Ok(Descriptor::new_bare(ms)?) + Ok(Descriptor::new_bare(ms.substitute_raw_pkh(&hash_map))?) } }