]> Untitled Git - bdk/commitdiff
Remove redundant duplicated keys check
authorAlekos Filini <alekos.filini@gmail.com>
Sat, 24 Sep 2022 11:48:05 +0000 (13:48 +0200)
committerAlekos Filini <alekos.filini@gmail.com>
Sat, 24 Sep 2022 13:42:42 +0000 (15:42 +0200)
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

src/descriptor/error.rs
src/descriptor/mod.rs
src/wallet/mod.rs

index efbb14e3cb0ae1a5795951c997ed5f3f527b152f..72141dcbbbd8ad72a16e0316adcc0c5989797459 100644 (file)
@@ -20,8 +20,6 @@ pub enum Error {
     InvalidDescriptorChecksum,
     /// The descriptor contains hardened derivation steps on public extended keys
     HardenedDerivationXpub,
-    /// The descriptor contains multiple keys with the same BIP32 fingerprint
-    DuplicatedKeys,
 
     /// Error thrown while working with [`keys`](crate::keys)
     Key(crate::keys::KeyError),
index 68d1cbb031cac00b3934d8c49e560b30651d905d..802ccd19ca2ababa877b4e1552058581eac2763b 100644 (file)
@@ -14,7 +14,7 @@
 //! This module contains generic utilities to work with descriptors, plus some re-exported types
 //! from [`miniscript`].
 
-use std::collections::{BTreeMap, HashSet};
+use std::collections::BTreeMap;
 use std::ops::Deref;
 
 use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource};
@@ -222,23 +222,9 @@ pub(crate) fn into_wallet_descriptor_checked<T: IntoWalletDescriptor>(
         return Err(DescriptorError::HardenedDerivationXpub);
     }
 
-    // Ensure that there are no duplicated keys
-    let mut found_keys = HashSet::new();
-    let descriptor_contains_duplicated_keys = descriptor.for_any_key(|k| {
-        if let DescriptorPublicKey::XPub(xkey) = k.as_key() {
-            let fingerprint = xkey.root_fingerprint(secp);
-            if found_keys.contains(&fingerprint) {
-                return true;
-            }
-
-            found_keys.insert(fingerprint);
-        }
-
-        false
-    });
-    if descriptor_contains_duplicated_keys {
-        return Err(DescriptorError::DuplicatedKeys);
-    }
+    // Run miniscript's sanity check, which will look for duplicated keys and other potential
+    // issues
+    descriptor.sanity_check()?;
 
     Ok((descriptor, keymap))
 }
@@ -923,14 +909,10 @@ mod test {
             DescriptorError::HardenedDerivationXpub
         ));
 
-        let descriptor = "wsh(multi(2,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/*))";
+        let descriptor = "wsh(multi(2,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*))";
         let result = into_wallet_descriptor_checked(descriptor, &secp, Network::Testnet);
 
         assert!(result.is_err());
-        assert!(matches!(
-            result.unwrap_err(),
-            DescriptorError::DuplicatedKeys
-        ));
     }
 
     #[test]
index 5d757e12d6bcc6306ed7bb19d97fc9db525cb737..88fcecff74503812b6d99d26046ed77468f10f46 100644 (file)
@@ -2077,6 +2077,10 @@ pub(crate) mod test {
         "tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG,{pk(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})"
     }
 
+    pub(crate) fn get_test_tr_dup_keys() -> &'static str {
+        "tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG,{pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})"
+    }
+
     macro_rules! assert_fee_rate {
         ($psbt:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({
             let psbt = $psbt.clone();
@@ -5554,4 +5558,19 @@ pub(crate) mod test {
         let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
         assert!(finalized);
     }
+
+    #[test]
+    fn test_taproot_load_descriptor_duplicated_keys() {
+        // Added after issue https://github.com/bitcoindevkit/bdk/issues/760
+        //
+        // Having the same key in multiple taproot leaves is safe and should be accepted by BDK
+
+        let (wallet, _, _) = get_funded_wallet(get_test_tr_dup_keys());
+        let addr = wallet.get_address(New).unwrap();
+
+        assert_eq!(
+            addr.to_string(),
+            "bcrt1pvysh4nmh85ysrkpwtrr8q8gdadhgdejpy6f9v424a8v9htjxjhyqw9c5s5"
+        );
+    }
 }