Introduce keychain::LocalChangeSet

This corresponds to `keychain::KeychainChangeSet` but for the redesigned
structures with `LocalChain`.

This structure is now used in `Wallet` as well as the examples.
This commit is contained in:
志宇
2023-05-13 23:28:03 +08:00
parent a78967e51b
commit 50425e979b
5 changed files with 142 additions and 167 deletions

View File

@@ -22,11 +22,11 @@ use alloc::{
pub use bdk_chain::keychain::Balance;
use bdk_chain::{
indexed_tx_graph::{IndexedAdditions, IndexedTxGraph},
keychain::{DerivationAdditions, KeychainTxOutIndex, LocalUpdate},
keychain::{KeychainTxOutIndex, LocalChangeSet, LocalUpdate},
local_chain::{self, LocalChain, UpdateNotConnectedError},
tx_graph::{CanonicalTx, TxGraph},
Anchor, Append, BlockId, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut, ObservedAs,
Persist, PersistBackend,
Append, BlockId, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut, ObservedAs, Persist,
PersistBackend,
};
use bitcoin::consensus::encode::serialize;
use bitcoin::secp256k1::Secp256k1;
@@ -96,67 +96,8 @@ pub struct Wallet<D = ()> {
/// The update to a [`Wallet`] used in [`Wallet::apply_update`]. This is usually returned from blockchain data sources.
pub type Update = LocalUpdate<KeychainKind, ConfirmationTimeAnchor>;
/// The changeset produced internally by applying an update.
#[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
#[serde(bound(
deserialize = "A: Ord + serde::Deserialize<'de>, K: Ord + serde::Deserialize<'de>",
serialize = "A: Ord + serde::Serialize, K: Ord + serde::Serialize"
))]
pub struct ChangeSet<K = KeychainKind, A = ConfirmationTimeAnchor> {
pub chain_changeset: local_chain::ChangeSet,
pub indexed_additions: IndexedAdditions<A, DerivationAdditions<K>>,
}
impl<K, A> Default for ChangeSet<K, A> {
fn default() -> Self {
Self {
chain_changeset: Default::default(),
indexed_additions: Default::default(),
}
}
}
impl<K: Ord, A: Anchor> Append for ChangeSet<K, A> {
fn append(&mut self, other: Self) {
Append::append(&mut self.chain_changeset, other.chain_changeset);
Append::append(&mut self.indexed_additions, other.indexed_additions);
}
fn is_empty(&self) -> bool {
self.chain_changeset.is_empty() && self.indexed_additions.is_empty()
}
}
impl<K, A> From<IndexedAdditions<A, DerivationAdditions<K>>> for ChangeSet<K, A> {
fn from(indexed_additions: IndexedAdditions<A, DerivationAdditions<K>>) -> Self {
Self {
indexed_additions,
..Default::default()
}
}
}
impl<K, A> From<DerivationAdditions<K>> for ChangeSet<K, A> {
fn from(index_additions: DerivationAdditions<K>) -> Self {
Self {
indexed_additions: IndexedAdditions {
index_additions,
..Default::default()
},
..Default::default()
}
}
}
impl<K, A> From<local_chain::ChangeSet> for ChangeSet<K, A> {
fn from(chain_changeset: local_chain::ChangeSet) -> Self {
Self {
chain_changeset,
..Default::default()
}
}
}
// /// The changeset produced internally by applying an update.
pub(crate) type ChangeSet = LocalChangeSet<KeychainKind, ConfirmationTimeAnchor>;
/// The address index selection strategy to use to derived an address from the wallet's external
/// descriptor. See [`Wallet::get_address`]. If you're unsure which one to use use `WalletIndex::New`.
#[derive(Debug)]
@@ -356,10 +297,11 @@ impl<D> Wallet<D> {
let txout_index = &mut self.indexed_graph.index;
let (index, spk) = match address_index {
AddressIndex::New => {
let ((index, spk), changeset) = txout_index.reveal_next_spk(&keychain);
let ((index, spk), index_additions) = txout_index.reveal_next_spk(&keychain);
let spk = spk.clone();
self.persist.stage(changeset.into());
self.persist
.stage(ChangeSet::from(IndexedAdditions::from(index_additions)));
self.persist.commit().expect("TODO");
(index, spk)
}
@@ -931,11 +873,12 @@ impl<D> Wallet<D> {
Some(ref drain_recipient) => drain_recipient.clone(),
None => {
let change_keychain = self.map_keychain(KeychainKind::Internal);
let ((index, spk), changeset) =
let ((index, spk), index_additions) =
self.indexed_graph.index.next_unused_spk(&change_keychain);
let spk = spk.clone();
self.indexed_graph.index.mark_used(&change_keychain, index);
self.persist.stage(changeset.into());
self.persist
.stage(ChangeSet::from(IndexedAdditions::from(index_additions)));
self.persist.commit().expect("TODO");
spk
}
@@ -1751,11 +1694,11 @@ impl<D> Wallet<D> {
D: PersistBackend<ChangeSet>,
{
let mut changeset: ChangeSet = self.chain.apply_update(update.chain)?.into();
let (_, derivation_additions) = self
let (_, index_additions) = self
.indexed_graph
.index
.reveal_to_target_multi(&update.keychain);
changeset.append(derivation_additions.into());
changeset.append(ChangeSet::from(IndexedAdditions::from(index_additions)));
changeset.append(self.indexed_graph.apply_update(update.graph).into());
let changed = !changeset.is_empty();

View File

@@ -2,6 +2,7 @@ use alloc::vec::Vec;
use bitcoin::{OutPoint, Transaction, TxOut};
use crate::{
keychain::DerivationAdditions,
tx_graph::{Additions, TxGraph},
Anchor, Append,
};
@@ -212,6 +213,15 @@ impl<A, IA: Default> From<Additions<A>> for IndexedAdditions<A, IA> {
}
}
impl<A, K> From<DerivationAdditions<K>> for IndexedAdditions<A, DerivationAdditions<K>> {
fn from(index_additions: DerivationAdditions<K>) -> Self {
Self {
graph_additions: Default::default(),
index_additions,
}
}
}
/// Represents a structure that can index transaction data.
pub trait Indexer {
/// The resultant "additions" when new transaction data is indexed.

View File

@@ -18,10 +18,11 @@
use crate::{
chain_graph::{self, ChainGraph},
collections::BTreeMap,
local_chain::LocalChain,
indexed_tx_graph::IndexedAdditions,
local_chain::{self, LocalChain},
sparse_chain::ChainPosition,
tx_graph::TxGraph,
Append, ForEachTxOut,
Anchor, Append, ForEachTxOut,
};
#[cfg(feature = "miniscript")]
@@ -125,6 +126,67 @@ impl<K, A> Default for LocalUpdate<K, A> {
}
}
/// A structure that records the corresponding changes as result of applying an [`LocalUpdate`].
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
crate = "serde_crate",
bound(
deserialize = "K: Ord + serde::Deserialize<'de>, A: Ord + serde::Deserialize<'de>",
serialize = "K: Ord + serde::Serialize, A: Ord + serde::Serialize",
)
)
)]
pub struct LocalChangeSet<K, A> {
/// Changes to the [`LocalChain`].
pub chain_changeset: local_chain::ChangeSet,
/// Additions to [`IndexedTxGraph`].
///
/// [`IndexedTxGraph`]: crate::indexed_tx_graph::IndexedTxGraph
pub indexed_additions: IndexedAdditions<A, DerivationAdditions<K>>,
}
impl<K, A> Default for LocalChangeSet<K, A> {
fn default() -> Self {
Self {
chain_changeset: Default::default(),
indexed_additions: Default::default(),
}
}
}
impl<K: Ord, A: Anchor> Append for LocalChangeSet<K, A> {
fn append(&mut self, other: Self) {
Append::append(&mut self.chain_changeset, other.chain_changeset);
Append::append(&mut self.indexed_additions, other.indexed_additions);
}
fn is_empty(&self) -> bool {
self.chain_changeset.is_empty() && self.indexed_additions.is_empty()
}
}
impl<K, A> From<local_chain::ChangeSet> for LocalChangeSet<K, A> {
fn from(chain_changeset: local_chain::ChangeSet) -> Self {
Self {
chain_changeset,
..Default::default()
}
}
}
impl<K, A> From<IndexedAdditions<A, DerivationAdditions<K>>> for LocalChangeSet<K, A> {
fn from(indexed_additions: IndexedAdditions<A, DerivationAdditions<K>>) -> Self {
Self {
indexed_additions,
..Default::default()
}
}
}
#[derive(Clone, Debug, PartialEq)]
/// An update that includes the last active indexes of each keychain.
pub struct KeychainScan<K, P> {