[wallet_redesign] Clean up and document address methods

This commit is contained in:
志宇 2023-05-29 13:20:12 +08:00
parent a7668a2f3e
commit cff92111d5
No known key found for this signature in database
GPG Key ID: F6345C9837C2BDE8
2 changed files with 44 additions and 30 deletions

View File

@ -22,9 +22,9 @@ use serde::{Deserialize, Serialize};
/// Types of keychains /// Types of keychains
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum KeychainKind { pub enum KeychainKind {
/// External /// External keychain, used for deriving recipient addresses.
External = 0, External = 0,
/// Internal, usually used for change outputs /// Internal keychain, used for deriving change addresses.
Internal = 1, Internal = 1,
} }

View File

@ -273,7 +273,8 @@ impl<D> Wallet<D> {
where where
D: PersistBackend<ChangeSet>, 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. /// Return a derived address using the internal (change) descriptor.
@ -287,50 +288,63 @@ impl<D> Wallet<D> {
where where
D: PersistBackend<ChangeSet>, 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 where
D: PersistBackend<ChangeSet>, D: PersistBackend<ChangeSet>,
{ {
let keychain = self.map_keychain(keychain); let keychain = self.map_keychain(keychain);
let txout_index = &mut self.indexed_graph.index; let txout_index = &mut self.indexed_graph.index;
let (index, spk) = match address_index { let (index, spk, additions) = match address_index {
AddressIndex::New => { AddressIndex::New => {
let ((index, spk), index_additions) = txout_index.reveal_next_spk(&keychain); let ((index, spk), index_additions) = txout_index.reveal_next_spk(&keychain);
let spk = spk.clone(); (index, spk.clone(), Some(index_additions))
self.persist
.stage(ChangeSet::from(IndexedAdditions::from(index_additions)));
self.persist.commit().expect("TODO");
(index, spk)
} }
AddressIndex::LastUnused => { AddressIndex::LastUnused => {
let index = txout_index.last_revealed_index(&keychain); let ((index, spk), index_additions) = txout_index.next_unused_spk(&keychain);
match index { (index, spk.clone(), Some(index_additions))
Some(index) if !txout_index.is_used(&(keychain, index)) => ( }
index, AddressIndex::Peek(index) => {
txout_index let (index, spk) = txout_index
.spk_at_index(&(keychain, index)) .spks_of_keychain(&keychain)
.expect("must exist") .take(index as usize + 1)
.clone(), .last()
), .unwrap();
_ => return self._get_address(AddressIndex::New, keychain), (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, index,
address: Address::from_script(&spk, self.network) address: Address::from_script(&spk, self.network)
.expect("descriptor must have address form"), .expect("descriptor must have address form"),
keychain, keychain,
} })
} }
/// Return whether or not a `script` is part of this wallet (either internal or external) /// Return whether or not a `script` is part of this wallet (either internal or external)