Skip to content

Commit 2cc42cc

Browse files
committed
Fix tap_key_origins when there are pkh(..) terms
1 parent bfa7697 commit 2cc42cc

File tree

2 files changed

+69
-31
lines changed

2 files changed

+69
-31
lines changed

integration_test/src/test_desc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ pub fn test_desc_satisfy(cl: &Client, testdata: &TestData, desc: &str) -> Witnes
109109
script_pubkey: addr.script_pubkey(),
110110
});
111111
let mut input = psbt::Input::default();
112+
input.update_with_descriptor_unchecked(&desc).unwrap();
112113
input.witness_utxo = Some(witness_utxo.clone());
113114
psbt.inputs.push(input);
114115
psbt.outputs.push(psbt::Output::default());
115-
psbt.update_inp_with_descriptor(0, &desc, true, false).unwrap();
116116

117117
// --------------------------------------------
118118
// Sign the transactions with all keys

src/psbt/mod.rs

+68-30
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,15 @@ use bitcoin::{EcdsaSigHashType, Script};
3333
use bitcoin::util::taproot::{self, ControlBlock, LeafVersion, TapLeafHash};
3434
use descriptor;
3535
use interpreter;
36+
use miniscript::iter::PkPkh;
3637
use miniscript::limits::SEQUENCE_LOCKTIME_DISABLE_FLAG;
3738
use miniscript::satisfy::{After, Older};
3839
use Preimage32;
3940
use Satisfier;
40-
use {Descriptor, DescriptorPublicKey, DescriptorTrait, MiniscriptKey, ToPublicKey, TranslatePk2};
41+
use {
42+
Descriptor, DescriptorPublicKey, DescriptorTrait, MiniscriptKey, ToPublicKey, TranslatePk,
43+
TranslatePk2,
44+
};
4145

4246
mod finalizer;
4347

@@ -872,6 +876,12 @@ pub trait PsbtInputExt {
872876
/// Note that his method doesn't check that the `witness_utxo` or `non_witness_utxo` is
873877
/// consistent with the descriptor. To do that see [`update_input_with_descriptor`].
874878
///
879+
/// ## Return value
880+
///
881+
/// For convenience, this returns the concrete descriptor that is computed internally to fill
882+
/// out the PSBT input fields. If you are checking the validity of `witness_utxo` or
883+
/// `non_witness_utxo` yourself you should check the `script_pubkey` against it.
884+
///
875885
/// [`update_input_with_descriptor`]: PsbtExt::update_input_with_descriptor
876886
fn update_with_descriptor_unchecked(
877887
&mut self,
@@ -889,48 +899,75 @@ impl PsbtInputExt for psbt::Input {
889899

890900
let derived = if let Descriptor::Tr(_) = &descriptor {
891901
// have to use a RefCell because we can't pass FnMut to translate_pk2
892-
let tap_key_origins = RefCell::new(BTreeMap::new());
893-
let derived = descriptor.translate_pk2(|xpk| {
894-
let derived = xpk.derive_public_key(&secp)?;
895-
tap_key_origins.borrow_mut().insert(
896-
derived.to_x_only_pubkey(),
902+
let mut hash_lookup = BTreeMap::new();
903+
let derived = descriptor.translate_pk(
904+
|xpk| xpk.derive_public_key(&secp),
905+
|xpk| {
906+
let xonly = xpk.derive_public_key(&secp)?.to_x_only_pubkey();
907+
let hash = xonly.to_pubkeyhash();
908+
hash_lookup.insert(hash, xonly);
909+
Ok(hash)
910+
},
911+
)?;
912+
913+
// NOTE: they will both always be Tr
914+
if let (Descriptor::Tr(tr_derived), Descriptor::Tr(tr_xpk)) = (&derived, descriptor) {
915+
let spend_info = tr_derived.spend_info();
916+
let ik_derived = spend_info.internal_key();
917+
let ik_xpk = tr_xpk.internal_key();
918+
self.tap_internal_key = Some(ik_derived);
919+
self.tap_merkle_root = spend_info.merkle_root();
920+
self.tap_key_origins.insert(
921+
ik_derived,
897922
(
898-
vec![/* we'll populate this in the next loop */],
899-
(xpk.master_fingerprint(), xpk.full_derivation_path()),
923+
vec![],
924+
(ik_xpk.master_fingerprint(), ik_xpk.full_derivation_path()),
900925
),
901926
);
902-
Ok(derived)
903-
})?;
904927

905-
let mut tap_key_origins = tap_key_origins.into_inner();
906-
907-
// NOTE: the derived descriptor will always be Tr
908-
if let Descriptor::Tr(tr) = &derived {
909-
let spend_info = tr.spend_info();
910-
for (_depth, ms) in tr.iter_scripts() {
911-
let leaf_script = (ms.encode(), LeafVersion::TapScript);
928+
for ((_depth_der, ms_derived), (_depth, ms)) in
929+
tr_derived.iter_scripts().zip(tr_xpk.iter_scripts())
930+
{
931+
debug_assert_eq!(_depth_der, _depth);
932+
let leaf_script = (ms_derived.encode(), LeafVersion::TapScript);
912933
let tapleaf_hash = TapLeafHash::from_script(&leaf_script.0, leaf_script.1);
913934
let control_block = spend_info
914935
.control_block(&leaf_script)
915936
.expect("Control block must exist in script map for every known leaf");
916937
self.tap_scripts.insert(control_block, leaf_script);
917938

918-
for pk in ms.iter_pk() {
919-
if let Some((tapleaf_hashes, _)) =
920-
tap_key_origins.get_mut(&pk.to_x_only_pubkey())
921-
{
922-
// To avoid duplication when the same key is in the same leaf more than
923-
// once. (even though I think this is usually not allowed)
924-
if tapleaf_hashes.last() != Some(&tapleaf_hash) {
925-
tapleaf_hashes.push(tapleaf_hash)
939+
for (pk_pkh_derived, pk_pkh_xpk) in
940+
ms_derived.iter_pk_pkh().zip(ms.iter_pk_pkh())
941+
{
942+
let (xonly, xpk) = match (pk_pkh_derived, pk_pkh_xpk) {
943+
(PkPkh::PlainPubkey(pk), PkPkh::PlainPubkey(xpk)) => {
944+
(pk.to_x_only_pubkey(), xpk)
926945
}
927-
}
946+
(PkPkh::HashedPubkey(hash), PkPkh::HashedPubkey(xpk)) => (
947+
hash_lookup
948+
.get(&hash)
949+
.expect("translate_pk inserted an entry for every hash")
950+
.clone(),
951+
xpk,
952+
),
953+
_ => unreachable!("the iterators work in the same order"),
954+
};
955+
956+
self.tap_key_origins
957+
.entry(xonly)
958+
.and_modify(|(tapleaf_hashes, _)| {
959+
if tapleaf_hashes.last() != Some(&tapleaf_hash) {
960+
tapleaf_hashes.push(tapleaf_hash);
961+
}
962+
})
963+
.or_insert_with(|| {
964+
(
965+
vec![tapleaf_hash],
966+
(xpk.master_fingerprint(), xpk.full_derivation_path()),
967+
)
968+
});
928969
}
929970
}
930-
931-
self.tap_internal_key = Some(spend_info.internal_key());
932-
self.tap_merkle_root = spend_info.merkle_root();
933-
self.tap_key_origins = tap_key_origins;
934971
}
935972

936973
derived
@@ -944,6 +981,7 @@ impl PsbtInputExt for psbt::Input {
944981
);
945982
Ok(derived)
946983
})?;
984+
947985
self.bip32_derivation = bip32_derivation.into_inner();
948986

949987
match &derived {

0 commit comments

Comments
 (0)