]> Untitled Git - bdk/commitdiff
[descriptor] Ensure that there are no duplicated keys
authorAlekos Filini <alekos.filini@gmail.com>
Tue, 23 Feb 2021 14:57:43 +0000 (15:57 +0100)
committerAlekos Filini <alekos.filini@gmail.com>
Fri, 26 Feb 2021 08:46:38 +0000 (09:46 +0100)
src/descriptor/error.rs
src/descriptor/mod.rs

index 64605061573c6bf91b4516d242f5ae4cf1c3cf91..185552f726757ec4186889427e318c8a7940f8c9 100644 (file)
@@ -33,6 +33,8 @@ 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 ee4f06294a9fc907f3e4ea69f63483d780befefa..350426dcb6fce5a45e4c4f3ea83ba054e1d5c8c0 100644 (file)
@@ -27,7 +27,7 @@
 //! This module contains generic utilities to work with descriptors, plus some re-exported types
 //! from [`miniscript`].
 
-use std::collections::{BTreeMap, HashMap};
+use std::collections::{BTreeMap, HashMap, HashSet};
 use std::ops::Deref;
 
 use bitcoin::util::bip32::{
@@ -225,6 +225,24 @@ 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);
+    }
+
     Ok((descriptor, keymap))
 }
 
@@ -783,5 +801,14 @@ mod test {
             result.unwrap_err(),
             DescriptorError::HardenedDerivationXpub
         ));
+
+        let descriptor = "wsh(multi(2,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/*))";
+        let result = into_wallet_descriptor_checked(descriptor, &secp, Network::Testnet);
+
+        assert!(result.is_err());
+        assert!(matches!(
+            result.unwrap_err(),
+            DescriptorError::DuplicatedKeys
+        ));
     }
 }