Skip to content

Commit e2bf973

Browse files
committed
Remove redundant duplicated keys check
This check is redundant since it's already performed by miniscript (see https://docs.rs/miniscript/7.0.0/miniscript/miniscript/analyzable/enum.AnalysisError.html#variant.RepeatedPubkeys) and it was incorrectly failing on tr descriptors that contain duplicated keys across different taproot leaves Fixes #760
1 parent c3faf05 commit e2bf973

File tree

3 files changed

+24
-25
lines changed

3 files changed

+24
-25
lines changed

src/descriptor/error.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ pub enum Error {
2020
InvalidDescriptorChecksum,
2121
/// The descriptor contains hardened derivation steps on public extended keys
2222
HardenedDerivationXpub,
23-
/// The descriptor contains multiple keys with the same BIP32 fingerprint
24-
DuplicatedKeys,
2523

2624
/// Error thrown while working with [`keys`](crate::keys)
2725
Key(crate::keys::KeyError),

src/descriptor/mod.rs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
//! This module contains generic utilities to work with descriptors, plus some re-exported types
1515
//! from [`miniscript`].
1616
17-
use std::collections::{BTreeMap, HashSet};
17+
use std::collections::BTreeMap;
1818
use std::ops::Deref;
1919

2020
use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource};
@@ -222,23 +222,9 @@ pub(crate) fn into_wallet_descriptor_checked<T: IntoWalletDescriptor>(
222222
return Err(DescriptorError::HardenedDerivationXpub);
223223
}
224224

225-
// Ensure that there are no duplicated keys
226-
let mut found_keys = HashSet::new();
227-
let descriptor_contains_duplicated_keys = descriptor.for_any_key(|k| {
228-
if let DescriptorPublicKey::XPub(xkey) = k.as_key() {
229-
let fingerprint = xkey.root_fingerprint(secp);
230-
if found_keys.contains(&fingerprint) {
231-
return true;
232-
}
233-
234-
found_keys.insert(fingerprint);
235-
}
236-
237-
false
238-
});
239-
if descriptor_contains_duplicated_keys {
240-
return Err(DescriptorError::DuplicatedKeys);
241-
}
225+
// Run miniscript's sanity check, which will look for duplicated keys and other potential
226+
// issues
227+
descriptor.sanity_check()?;
242228

243229
Ok((descriptor, keymap))
244230
}
@@ -923,14 +909,10 @@ mod test {
923909
DescriptorError::HardenedDerivationXpub
924910
));
925911

926-
let descriptor = "wsh(multi(2,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/*))";
912+
let descriptor = "wsh(multi(2,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*))";
927913
let result = into_wallet_descriptor_checked(descriptor, &secp, Network::Testnet);
928914

929915
assert!(result.is_err());
930-
assert!(matches!(
931-
result.unwrap_err(),
932-
DescriptorError::DuplicatedKeys
933-
));
934916
}
935917

936918
#[test]

src/wallet/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,10 @@ pub(crate) mod test {
20772077
"tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG,{pk(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})"
20782078
}
20792079

2080+
pub(crate) fn get_test_tr_dup_keys() -> &'static str {
2081+
"tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG,{pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})"
2082+
}
2083+
20802084
macro_rules! assert_fee_rate {
20812085
($psbt:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({
20822086
let psbt = $psbt.clone();
@@ -5554,4 +5558,19 @@ pub(crate) mod test {
55545558
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
55555559
assert!(finalized);
55565560
}
5561+
5562+
#[test]
5563+
fn test_taproot_load_descriptor_duplicated_keys() {
5564+
// Added after issue https://github.com/bitcoindevkit/bdk/issues/760
5565+
//
5566+
// Having the same key in multiple taproot leaves is safe and should be accepted by BDK
5567+
5568+
let (wallet, _, _) = get_funded_wallet(get_test_tr_dup_keys());
5569+
let addr = wallet.get_address(New).unwrap();
5570+
5571+
assert_eq!(
5572+
addr.to_string(),
5573+
"bcrt1pvysh4nmh85ysrkpwtrr8q8gdadhgdejpy6f9v424a8v9htjxjhyqw9c5s5"
5574+
);
5575+
}
55575576
}

0 commit comments

Comments
 (0)