]> Untitled Git - bdk/commitdiff
[wallet_redesign] Clean up and document address methods
author志宇 <hello@evanlinjin.me>
Mon, 29 May 2023 05:20:12 +0000 (13:20 +0800)
committer志宇 <hello@evanlinjin.me>
Sat, 3 Jun 2023 19:32:19 +0000 (03:32 +0800)
crates/bdk/src/types.rs
crates/bdk/src/wallet/mod.rs

index 870734d6b7f03aa76440702f26f337f1daaadedc..e21bef90660c41dc6a8bb4734f8474628f437544 100644 (file)
@@ -22,9 +22,9 @@ use serde::{Deserialize, Serialize};
 /// Types of keychains
 #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub enum KeychainKind {
-    /// External
+    /// External keychain, used for deriving recipient addresses.
     External = 0,
-    /// Internal, usually used for change outputs
+    /// Internal keychain, used for deriving change addresses.
     Internal = 1,
 }
 
index 33546ce020aaac74614b4a17f94cfe090a49262a..4bee9be81ede2fa76fcd741f564c2d5f52025020 100644 (file)
@@ -273,7 +273,8 @@ impl<D> Wallet<D> {
     where
         D: PersistBackend<ChangeSet>,
     {
-        self._get_address(address_index, KeychainKind::External)
+        self._get_address(KeychainKind::External, address_index)
+            .expect("persistence backend must not fail")
     }
 
     /// Return a derived address using the internal (change) descriptor.
@@ -287,50 +288,63 @@ impl<D> Wallet<D> {
     where
         D: PersistBackend<ChangeSet>,
     {
-        self._get_address(address_index, KeychainKind::Internal)
+        self._get_address(KeychainKind::Internal, address_index)
+            .expect("persistence backend must not fail")
     }
 
-    fn _get_address(&mut self, address_index: AddressIndex, keychain: KeychainKind) -> AddressInfo
+    /// Return a derived address using the specified `keychain` (external/internal).
+    ///
+    /// If `keychain` is [`KeychainKind::External`], external addresses will be derived (used for
+    /// receiving funds).
+    ///
+    /// If `keychain` is [`KeychainKind::Internal`], internal addresses will be derived (used for
+    /// creating change outputs). If the wallet does not have an internal keychain, it will use the
+    /// external keychain to derive change outputs.
+    ///
+    /// See [`AddressIndex`] for available address index selection strategies. If none of the keys
+    /// in the descriptor are derivable (i.e. does not end with /*) then the same address will
+    /// always be returned for any [`AddressIndex`].
+    fn _get_address(
+        &mut self,
+        keychain: KeychainKind,
+        address_index: AddressIndex,
+    ) -> Result<AddressInfo, D::WriteError>
     where
         D: PersistBackend<ChangeSet>,
     {
         let keychain = self.map_keychain(keychain);
         let txout_index = &mut self.indexed_graph.index;
-        let (index, spk) = match address_index {
+        let (index, spk, additions) = match address_index {
             AddressIndex::New => {
                 let ((index, spk), index_additions) = txout_index.reveal_next_spk(&keychain);
-                let spk = spk.clone();
-
-                self.persist
-                    .stage(ChangeSet::from(IndexedAdditions::from(index_additions)));
-                self.persist.commit().expect("TODO");
-                (index, spk)
+                (index, spk.clone(), Some(index_additions))
             }
             AddressIndex::LastUnused => {
-                let index = txout_index.last_revealed_index(&keychain);
-                match index {
-                    Some(index) if !txout_index.is_used(&(keychain, index)) => (
-                        index,
-                        txout_index
-                            .spk_at_index(&(keychain, index))
-                            .expect("must exist")
-                            .clone(),
-                    ),
-                    _ => return self._get_address(AddressIndex::New, keychain),
-                }
+                let ((index, spk), index_additions) = txout_index.next_unused_spk(&keychain);
+                (index, spk.clone(), Some(index_additions))
+            }
+            AddressIndex::Peek(index) => {
+                let (index, spk) = txout_index
+                    .spks_of_keychain(&keychain)
+                    .take(index as usize + 1)
+                    .last()
+                    .unwrap();
+                (index, spk, None)
             }
-            AddressIndex::Peek(index) => txout_index
-                .spks_of_keychain(&keychain)
-                .take(index as usize + 1)
-                .last()
-                .unwrap(),
         };
-        AddressInfo {
+
+        if let Some(additions) = additions {
+            self.persist
+                .stage(ChangeSet::from(IndexedAdditions::from(additions)));
+            self.persist.commit()?;
+        }
+
+        Ok(AddressInfo {
             index,
             address: Address::from_script(&spk, self.network)
                 .expect("descriptor must have address form"),
             keychain,
-        }
+        })
     }
 
     /// Return whether or not a `script` is part of this wallet (either internal or external)