]> Untitled Git - bdk/commitdiff
refactor: improve docs, cleanup unnecessary types and improve code
authorVladimir Fomene <vladimirfomene@gmail.com>
Wed, 6 Sep 2023 06:47:45 +0000 (09:47 +0300)
committerVladimir Fomene <vladimirfomene@gmail.com>
Wed, 13 Sep 2023 10:57:58 +0000 (13:57 +0300)
crates/bdk/src/wallet/mod.rs
crates/chain/src/indexed_tx_graph.rs
crates/chain/src/keychain/txout_index.rs
crates/chain/src/lib.rs
crates/chain/src/spk_txout_index.rs
crates/electrum/src/electrum_ext.rs
crates/electrum/src/lib.rs
example-crates/example_electrum/src/main.rs
example-crates/wallet_electrum/src/main.rs
example-crates/wallet_esplora_async/src/main.rs
example-crates/wallet_esplora_blocking/src/main.rs

index a7fe4d42a6ad339df329f7af2b22373f566f2797..5a3918cf00c55446dda31cf4291ea80dfe66a8df 100644 (file)
@@ -25,7 +25,7 @@ use bdk_chain::{
     keychain::{self, KeychainTxOutIndex},
     local_chain::{self, CannotConnectError, CheckPoint, CheckPointIter, LocalChain},
     tx_graph::{CanonicalTx, TxGraph},
-    Anchor, Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut,
+    Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut,
     IndexedTxGraph, Persist, PersistBackend,
 };
 use bitcoin::consensus::encode::serialize;
@@ -95,73 +95,51 @@ pub struct Wallet<D = ()> {
     secp: SecpCtx,
 }
 
-/// A structure to update [`Wallet`].
+/// An update to [`Wallet`].
 ///
 /// It updates [`bdk_chain::keychain::KeychainTxOutIndex`], [`bdk_chain::TxGraph`] and [`local_chain::LocalChain`] atomically.
-#[derive(Debug, Clone)]
-pub struct WalletUpdate<K, A> {
+#[derive(Debug, Clone, Default)]
+pub struct Update {
     /// Contains the last active derivation indices per keychain (`K`), which is used to update the
     /// [`KeychainTxOutIndex`].
-    pub last_active_indices: BTreeMap<K, u32>,
+    pub last_active_indices: BTreeMap<KeychainKind, u32>,
 
-    /// Update for the [`TxGraph`].
-    pub graph: TxGraph<A>,
+    /// Update for the wallet's internal [`TxGraph`].
+    pub graph: TxGraph<ConfirmationTimeAnchor>,
 
-    /// Update for the [`LocalChain`].
+    /// Update for the wallet's internal [`LocalChain`].
     ///
     /// [`LocalChain`]: local_chain::LocalChain
     pub chain: Option<local_chain::Update>,
 }
 
-impl<K, A> Default for WalletUpdate<K, A> {
-    fn default() -> Self {
-        Self {
-            last_active_indices: BTreeMap::new(),
-            graph: TxGraph::default(),
-            chain: None,
-        }
-    }
-}
-
-/// A structure that records the corresponding changes as result of applying an [`WalletUpdate`].
-#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
-pub struct WalletChangeSet<K, A> {
+/// The changes made to a wallet by applying an [`Update`].
+#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Default)]
+pub struct ChangeSet {
     /// Changes to the [`LocalChain`].
     ///
     /// [`LocalChain`]: local_chain::LocalChain
     pub chain: local_chain::ChangeSet,
 
-    /// ChangeSet to [`IndexedTxGraph`].
+    /// Changes to [`IndexedTxGraph`].
     ///
     /// [`IndexedTxGraph`]: bdk_chain::indexed_tx_graph::IndexedTxGraph
-    #[serde(bound(
-        deserialize = "K: Ord + serde::Deserialize<'de>, A: Ord + serde::Deserialize<'de>",
-        serialize = "K: Ord + serde::Serialize, A: Ord + serde::Serialize",
-    ))]
-    pub index_tx_graph: indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>,
+    pub indexed_tx_graph:
+        indexed_tx_graph::ChangeSet<ConfirmationTimeAnchor, keychain::ChangeSet<KeychainKind>>,
 }
 
-impl<K, A> Default for WalletChangeSet<K, A> {
-    fn default() -> Self {
-        Self {
-            chain: Default::default(),
-            index_tx_graph: Default::default(),
-        }
-    }
-}
-
-impl<K: Ord, A: Anchor> Append for WalletChangeSet<K, A> {
+impl Append for ChangeSet {
     fn append(&mut self, other: Self) {
         Append::append(&mut self.chain, other.chain);
-        Append::append(&mut self.index_tx_graph, other.index_tx_graph);
+        Append::append(&mut self.indexed_tx_graph, other.indexed_tx_graph);
     }
 
     fn is_empty(&self) -> bool {
-        self.chain.is_empty() && self.index_tx_graph.is_empty()
+        self.chain.is_empty() && self.indexed_tx_graph.is_empty()
     }
 }
 
-impl<K, A> From<local_chain::ChangeSet> for WalletChangeSet<K, A> {
+impl From<local_chain::ChangeSet> for ChangeSet {
     fn from(chain: local_chain::ChangeSet) -> Self {
         Self {
             chain,
@@ -170,21 +148,22 @@ impl<K, A> From<local_chain::ChangeSet> for WalletChangeSet<K, A> {
     }
 }
 
-impl<K, A> From<indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>> for WalletChangeSet<K, A> {
-    fn from(index_tx_graph: indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>) -> Self {
+impl From<indexed_tx_graph::ChangeSet<ConfirmationTimeAnchor, keychain::ChangeSet<KeychainKind>>>
+    for ChangeSet
+{
+    fn from(
+        indexed_tx_graph: indexed_tx_graph::ChangeSet<
+            ConfirmationTimeAnchor,
+            keychain::ChangeSet<KeychainKind>,
+        >,
+    ) -> Self {
         Self {
-            index_tx_graph,
+            indexed_tx_graph,
             ..Default::default()
         }
     }
 }
 
-/// The update to a [`Wallet`] used in [`Wallet::apply_update`]. This is usually returned from blockchain data sources.
-pub type Update = WalletUpdate<KeychainKind, ConfirmationTimeAnchor>;
-
-/// The changeset produced internally by [`Wallet`] when mutated.
-pub type ChangeSet = WalletChangeSet<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)]
@@ -332,7 +311,7 @@ impl<D> Wallet<D> {
 
         let changeset = db.load_from_persistence().map_err(NewError::Persist)?;
         chain.apply_changeset(&changeset.chain);
-        indexed_graph.apply_changeset(changeset.index_tx_graph);
+        indexed_graph.apply_changeset(changeset.indexed_tx_graph);
 
         let persist = Persist::new(db);
 
index 4643a93ec9856f9effe9ede1ce147d1c6d737d1c..c9091eef959d4fdd55058b73830c3e2ae5ff2286 100644 (file)
@@ -6,7 +6,7 @@ use alloc::vec::Vec;
 use bitcoin::{OutPoint, Transaction, TxOut};
 
 use crate::{
-    keychain,
+    keychain, local_chain,
     tx_graph::{self, TxGraph},
     Anchor, Append,
 };
@@ -225,7 +225,16 @@ impl<A, K> From<keychain::ChangeSet<K>> for ChangeSet<A, keychain::ChangeSet<K>>
     }
 }
 
-/// Represents a structure that can index transaction data.
+impl<A, IA> From<ChangeSet<A, IA>> for (local_chain::ChangeSet, ChangeSet<A, IA>) {
+    fn from(indexed_changeset: ChangeSet<A, IA>) -> Self {
+        (local_chain::ChangeSet::default(), indexed_changeset)
+    }
+}
+
+/// Utilities for indexing transaction data.
+///
+/// Types which implement this trait can be used to construct an [`IndexedTxGraph`].
+/// This trait's methods should rarely be called directly.
 pub trait Indexer {
     /// The resultant "changeset" when new transaction data is indexed.
     type ChangeSet;
@@ -234,17 +243,6 @@ pub trait Indexer {
     fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet;
 
     /// Scans a transaction for relevant outpoints, which are stored and indexed internally.
-    ///
-    /// If the matched script pubkey is part of the lookahead, the last stored index is updated for
-    /// the script pubkey's keychain and the [`ChangeSet`] returned will reflect the
-    /// change.
-    ///
-    /// Typically, this method is used in two situations:
-    ///
-    /// 1. After loading transaction data from the disk, you may scan over all the txouts to restore all
-    /// your txouts.
-    /// 2. When getting new data from the chain, you usually scan it before incorporating it into
-    /// your chain state.
     fn index_tx(&mut self, tx: &Transaction) -> Self::ChangeSet;
 
     /// Apply changeset to itself.
index 5996d4d46d9b7158aac061b8a30cbfeff4fda01b..3d642edd4b9428339a10de8647e2142d25c93161 100644 (file)
@@ -91,11 +91,10 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
     type ChangeSet = super::ChangeSet<K>;
 
     fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet {
-        let mut changeset = super::ChangeSet::<K>::default();
-        for (keychain, index) in self.inner.index_txout(outpoint, txout) {
-            changeset.append(self.reveal_to_target(&keychain, index).1);
+        match self.inner.scan_txout(outpoint, txout).cloned() {
+            Some((keychain, index)) => self.reveal_to_target(&keychain, index).1,
+            None => super::ChangeSet::default(),
         }
-        changeset
     }
 
     fn index_tx(&mut self, tx: &bitcoin::Transaction) -> Self::ChangeSet {
@@ -175,8 +174,10 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
 
     /// Set the lookahead count for `keychain`.
     ///
-    /// The lookahead is the number of scripts to cache ahead of the last stored script index. This
-    /// is useful during a scan via [`Indexer::index_tx`] or [`Indexer::index_txout`].
+    /// The lookahead is the number of scripts to cache ahead of the last revealed script index. This
+    /// is useful to find outputs you own when processing block data that lie beyond the last revealed
+    /// index. In certain situations, such as when performing an initial scan of the blockchain during
+    /// wallet import, it may be uncertain or unknown what the last revealed index is.
     ///
     /// # Panics
     ///
index f38b7ee53dc1469cdb66af3f465c365d0b7a11c4..ed167ebf6c114851d6c3720357d48a931728c538 100644 (file)
@@ -100,11 +100,3 @@ pub mod collections {
 
 /// How many confirmations are needed f or a coinbase output to be spent.
 pub const COINBASE_MATURITY: u32 = 100;
-
-impl<A, IA> From<indexed_tx_graph::ChangeSet<A, IA>>
-    for (local_chain::ChangeSet, indexed_tx_graph::ChangeSet<A, IA>)
-{
-    fn from(indexed_changeset: indexed_tx_graph::ChangeSet<A, IA>) -> Self {
-        (local_chain::ChangeSet::default(), indexed_changeset)
-    }
-}
index 8bac74131bc72d89bb6fb0577cee785884bb7535..4047f8fcb82a53e323055299e3ba3241be154f0e 100644 (file)
@@ -53,35 +53,19 @@ impl<I> Default for SpkTxOutIndex<I> {
 }
 
 impl<I: Clone + Ord> Indexer for SpkTxOutIndex<I> {
-    type ChangeSet = BTreeSet<I>;
+    type ChangeSet = ();
 
     fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet {
-        let spk_i = self.spk_indices.get(&txout.script_pubkey);
-        let mut scanned_indices = BTreeSet::new();
-        if let Some(spk_i) = spk_i {
-            self.txouts.insert(outpoint, (spk_i.clone(), txout.clone()));
-            self.spk_txouts.insert((spk_i.clone(), outpoint));
-            self.unused.remove(spk_i);
-            scanned_indices.insert(spk_i.clone());
-        }
-        scanned_indices
+        self.scan_txout(outpoint, txout);
+        Default::default()
     }
 
     fn index_tx(&mut self, tx: &Transaction) -> Self::ChangeSet {
-        let mut scanned_indices = BTreeSet::new();
-
-        for (i, txout) in tx.output.iter().enumerate() {
-            let op = OutPoint::new(tx.txid(), i as u32);
-            let mut txout_indices = self.index_txout(op, txout);
-            scanned_indices.append(&mut txout_indices);
-        }
-
-        scanned_indices
+        self.scan(tx);
+        Default::default()
     }
 
-    fn initial_changeset(&self) -> Self::ChangeSet {
-        self.spks.keys().cloned().collect()
-    }
+    fn initial_changeset(&self) -> Self::ChangeSet {}
 
     fn apply_changeset(&mut self, _changeset: Self::ChangeSet) {
         // This applies nothing.
@@ -93,6 +77,38 @@ impl<I: Clone + Ord> Indexer for SpkTxOutIndex<I> {
 }
 
 impl<I: Clone + Ord> SpkTxOutIndex<I> {
+    /// Scans a transaction's outputs for matching script pubkeys.
+    ///
+    /// Typically, this is used in two situations:
+    ///
+    /// 1. After loading transaction data from the disk, you may scan over all the txouts to restore all
+    /// your txouts.
+    /// 2. When getting new data from the chain, you usually scan it before incorporating it into your chain state.
+    pub fn scan(&mut self, tx: &Transaction) -> BTreeSet<I> {
+        let mut scanned_indices = BTreeSet::new();
+        let txid = tx.txid();
+        for (i, txout) in tx.output.iter().enumerate() {
+            let op = OutPoint::new(txid, i as u32);
+            if let Some(spk_i) = self.scan_txout(op, txout) {
+                scanned_indices.insert(spk_i.clone());
+            }
+        }
+
+        scanned_indices
+    }
+
+    /// Scan a single `TxOut` for a matching script pubkey and returns the index that matches the
+    /// script pubkey (if any).
+    pub fn scan_txout(&mut self, op: OutPoint, txout: &TxOut) -> Option<&I> {
+        let spk_i = self.spk_indices.get(&txout.script_pubkey);
+        if let Some(spk_i) = spk_i {
+            self.txouts.insert(op, (spk_i.clone(), txout.clone()));
+            self.spk_txouts.insert((spk_i.clone(), op));
+            self.unused.remove(spk_i);
+        }
+        spk_i
+    }
+
     /// Get a reference to the set of indexed outpoints.
     pub fn outpoints(&self) -> &BTreeSet<(I, OutPoint)> {
         &self.spk_txouts
index b7435862720cde040b6fadf8f2adf3fa22166668..7ac16a046f733339d305647c43fc5b41c46e6068 100644 (file)
@@ -14,19 +14,19 @@ use std::{
 /// We assume that a block of this depth and deeper cannot be reorged.
 const ASSUME_FINAL_DEPTH: u32 = 8;
 
-/// Represents a [`TxGraph`] update fetched from an Electrum server, but excludes full transactions.
+/// Represents updates fetched from an Electrum server, but excludes full transactions.
 ///
 /// To provide a complete update to [`TxGraph`], you'll need to call [`Self::missing_full_txs`] to
-/// determine the full transactions missing from [`TxGraph`]. Then call [`Self::finalize`] to
+/// determine the full transactions missing from [`TxGraph`]. Then call [`Self::into_tx_graph`] to
 /// fetch the full transactions from Electrum and finalize the update.
 #[derive(Debug, Default, Clone)]
-pub struct IncompleteTxGraph<A>(HashMap<Txid, BTreeSet<A>>);
+pub struct RelevantTxids(HashMap<Txid, BTreeSet<ConfirmationHeightAnchor>>);
 
-impl<A: Anchor> IncompleteTxGraph<A> {
+impl RelevantTxids {
     /// Determine the full transactions that are missing from `graph`.
     ///
-    /// Refer to [`IncompleteTxGraph`] for more.
-    pub fn missing_full_txs<A2>(&self, graph: &TxGraph<A2>) -> Vec<Txid> {
+    /// Refer to [`RelevantTxids`] for more details.
+    pub fn missing_full_txs<A: Anchor>(&self, graph: &TxGraph<A>) -> Vec<Txid> {
         self.0
             .keys()
             .filter(move |&&txid| graph.as_ref().get_tx(txid).is_none())
@@ -36,15 +36,15 @@ impl<A: Anchor> IncompleteTxGraph<A> {
 
     /// Finalizes the [`TxGraph`] update by fetching `missing` txids from the `client`.
     ///
-    /// Refer to [`IncompleteTxGraph`] for more.
-    pub fn finalize(
+    /// Refer to [`RelevantTxids`] for more details.
+    pub fn into_tx_graph(
         self,
         client: &Client,
         seen_at: Option<u64>,
         missing: Vec<Txid>,
-    ) -> Result<TxGraph<A>, Error> {
+    ) -> Result<TxGraph<ConfirmationHeightAnchor>, Error> {
         let new_txs = client.batch_transaction_get(&missing)?;
-        let mut graph = TxGraph::<A>::new(new_txs);
+        let mut graph = TxGraph::<ConfirmationHeightAnchor>::new(new_txs);
         for (txid, anchors) in self.0 {
             if let Some(seen_at) = seen_at {
                 let _ = graph.insert_seen_at(txid, seen_at);
@@ -55,22 +55,20 @@ impl<A: Anchor> IncompleteTxGraph<A> {
         }
         Ok(graph)
     }
-}
 
-impl IncompleteTxGraph<ConfirmationHeightAnchor> {
-    /// Finalizes the [`IncompleteTxGraph`] with `new_txs` and anchors of type
+    /// Finalizes [`RelevantTxids`] with `new_txs` and anchors of type
     /// [`ConfirmationTimeAnchor`].
     ///
     /// **Note:** The confirmation time might not be precisely correct if there has been a reorg.
     /// Electrum's API intends that we use the merkle proof API, we should change `bdk_electrum` to
     /// use it.
-    pub fn finalize_with_confirmation_time(
+    pub fn into_confirmation_time_tx_graph(
         self,
         client: &Client,
         seen_at: Option<u64>,
         missing: Vec<Txid>,
     ) -> Result<TxGraph<ConfirmationTimeAnchor>, Error> {
-        let graph = self.finalize(client, seen_at, missing)?;
+        let graph = self.into_tx_graph(client, seen_at, missing)?;
 
         let relevant_heights = {
             let mut visited_heights = HashSet::new();
@@ -122,8 +120,20 @@ impl IncompleteTxGraph<ConfirmationHeightAnchor> {
     }
 }
 
+/// Combination of chain and transactions updates from electrum
+///
+/// We have to update the chain and the txids at the same time since we anchor the txids to
+/// the same chain tip that we check before and after we gather the txids.
+#[derive(Debug)]
+pub struct ElectrumUpdate {
+    /// Chain update
+    pub chain_update: local_chain::Update,
+    /// Transaction updates from electrum
+    pub relevant_txids: RelevantTxids,
+}
+
 /// Trait to extend [`Client`] functionality.
-pub trait ElectrumExt<A> {
+pub trait ElectrumExt {
     /// Scan the blockchain (via electrum) for the data specified and returns updates for
     /// [`bdk_chain`] data structures.
     ///
@@ -136,7 +146,6 @@ pub trait ElectrumExt<A> {
     /// The scan for each keychain stops after a gap of `stop_gap` script pubkeys with no associated
     /// transactions. `batch_size` specifies the max number of script pubkeys to request for in a
     /// single batch request.
-    #[allow(clippy::type_complexity)]
     fn scan<K: Ord + Clone>(
         &self,
         prev_tip: Option<CheckPoint>,
@@ -145,7 +154,7 @@ pub trait ElectrumExt<A> {
         outpoints: impl IntoIterator<Item = OutPoint>,
         stop_gap: usize,
         batch_size: usize,
-    ) -> Result<(local_chain::Update, IncompleteTxGraph<A>, BTreeMap<K, u32>), Error>;
+    ) -> Result<(ElectrumUpdate, BTreeMap<K, u32>), Error>;
 
     /// Convenience method to call [`scan`] without requiring a keychain.
     ///
@@ -157,13 +166,13 @@ pub trait ElectrumExt<A> {
         txids: impl IntoIterator<Item = Txid>,
         outpoints: impl IntoIterator<Item = OutPoint>,
         batch_size: usize,
-    ) -> Result<(local_chain::Update, IncompleteTxGraph<A>), Error> {
+    ) -> Result<ElectrumUpdate, Error> {
         let spk_iter = misc_spks
             .into_iter()
             .enumerate()
             .map(|(i, spk)| (i as u32, spk));
 
-        let (chain, graph, _) = self.scan(
+        let (electrum_update, _) = self.scan(
             prev_tip,
             [((), spk_iter)].into(),
             txids,
@@ -172,11 +181,11 @@ pub trait ElectrumExt<A> {
             batch_size,
         )?;
 
-        Ok((chain, graph))
+        Ok(electrum_update)
     }
 }
 
-impl ElectrumExt<ConfirmationHeightAnchor> for Client {
+impl ElectrumExt for Client {
     fn scan<K: Ord + Clone>(
         &self,
         prev_tip: Option<CheckPoint>,
@@ -185,14 +194,7 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
         outpoints: impl IntoIterator<Item = OutPoint>,
         stop_gap: usize,
         batch_size: usize,
-    ) -> Result<
-        (
-            local_chain::Update,
-            IncompleteTxGraph<ConfirmationHeightAnchor>,
-            BTreeMap<K, u32>,
-        ),
-        Error,
-    > {
+    ) -> Result<(ElectrumUpdate, BTreeMap<K, u32>), Error> {
         let mut request_spks = keychain_spks
             .into_iter()
             .map(|(k, s)| (k, s.into_iter()))
@@ -202,9 +204,9 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
         let txids = txids.into_iter().collect::<Vec<_>>();
         let outpoints = outpoints.into_iter().collect::<Vec<_>>();
 
-        let update = loop {
+        let (electrum_update, keychain_update) = loop {
             let (tip, _) = construct_update_tip(self, prev_tip.clone())?;
-            let mut graph_update = IncompleteTxGraph::<ConfirmationHeightAnchor>::default();
+            let mut relevant_txids = RelevantTxids::default();
             let cps = tip
                 .iter()
                 .take(10)
@@ -216,7 +218,7 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
                     scanned_spks.append(&mut populate_with_spks(
                         self,
                         &cps,
-                        &mut graph_update,
+                        &mut relevant_txids,
                         &mut scanned_spks
                             .iter()
                             .map(|(i, (spk, _))| (i.clone(), spk.clone())),
@@ -229,7 +231,7 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
                         populate_with_spks(
                             self,
                             &cps,
-                            &mut graph_update,
+                            &mut relevant_txids,
                             keychain_spks,
                             stop_gap,
                             batch_size,
@@ -240,12 +242,12 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
                 }
             }
 
-            populate_with_txids(self, &cps, &mut graph_update, &mut txids.iter().cloned())?;
+            populate_with_txids(self, &cps, &mut relevant_txids, &mut txids.iter().cloned())?;
 
             let _txs = populate_with_outpoints(
                 self,
                 &cps,
-                &mut graph_update,
+                &mut relevant_txids,
                 &mut outpoints.iter().cloned(),
             )?;
 
@@ -271,10 +273,16 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
                 })
                 .collect::<BTreeMap<_, _>>();
 
-            break (chain_update, graph_update, keychain_update);
+            break (
+                ElectrumUpdate {
+                    chain_update,
+                    relevant_txids,
+                },
+                keychain_update,
+            );
         };
 
-        Ok(update)
+        Ok((electrum_update, keychain_update))
     }
 }
 
@@ -398,7 +406,7 @@ fn determine_tx_anchor(
 fn populate_with_outpoints(
     client: &Client,
     cps: &BTreeMap<u32, CheckPoint>,
-    graph_update: &mut IncompleteTxGraph<ConfirmationHeightAnchor>,
+    relevant_txids: &mut RelevantTxids,
     outpoints: &mut impl Iterator<Item = OutPoint>,
 ) -> Result<HashMap<Txid, Transaction>, Error> {
     let mut full_txs = HashMap::new();
@@ -447,7 +455,7 @@ fn populate_with_outpoints(
             };
 
             let anchor = determine_tx_anchor(cps, res.height, res.tx_hash);
-            let tx_entry = graph_update.0.entry(res.tx_hash).or_default();
+            let tx_entry = relevant_txids.0.entry(res.tx_hash).or_default();
             if let Some(anchor) = anchor {
                 tx_entry.insert(anchor);
             }
@@ -459,7 +467,7 @@ fn populate_with_outpoints(
 fn populate_with_txids(
     client: &Client,
     cps: &BTreeMap<u32, CheckPoint>,
-    graph_update: &mut IncompleteTxGraph<ConfirmationHeightAnchor>,
+    relevant_txids: &mut RelevantTxids,
     txids: &mut impl Iterator<Item = Txid>,
 ) -> Result<(), Error> {
     for txid in txids {
@@ -484,7 +492,7 @@ fn populate_with_txids(
             None => continue,
         };
 
-        let tx_entry = graph_update.0.entry(txid).or_default();
+        let tx_entry = relevant_txids.0.entry(txid).or_default();
         if let Some(anchor) = anchor {
             tx_entry.insert(anchor);
         }
@@ -495,7 +503,7 @@ fn populate_with_txids(
 fn populate_with_spks<I: Ord + Clone>(
     client: &Client,
     cps: &BTreeMap<u32, CheckPoint>,
-    graph_update: &mut IncompleteTxGraph<ConfirmationHeightAnchor>,
+    relevant_txids: &mut RelevantTxids,
     spks: &mut impl Iterator<Item = (I, ScriptBuf)>,
     stop_gap: usize,
     batch_size: usize,
@@ -528,7 +536,7 @@ fn populate_with_spks<I: Ord + Clone>(
             }
 
             for tx in spk_history {
-                let tx_entry = graph_update.0.entry(tx.tx_hash).or_default();
+                let tx_entry = relevant_txids.0.entry(tx.tx_hash).or_default();
                 if let Some(anchor) = determine_tx_anchor(cps, tx.height, tx.tx_hash) {
                     tx_entry.insert(anchor);
                 }
index 0977262685431565fc801e26db79b52d9b5a72bf..1e4805379c63a319f9b27261b049582876d85d6a 100644 (file)
@@ -3,14 +3,14 @@
 //! The star of the show is the [`ElectrumExt::scan`] method, which scans for relevant blockchain
 //! data (via electrum) and outputs updates for [`bdk_chain`] structures as a tuple of form:
 //!
-//! ([`bdk_chain::local_chain::Update`], [`IncompleteTxGraph`], `keychain_update`)
+//! ([`bdk_chain::local_chain::Update`], [`RelevantTxids`], `keychain_update`)
 //!
-//! An [`IncompleteTxGraph`] only includes `txid`s and no full transactions. The caller is
+//! An [`RelevantTxids`] only includes `txid`s and no full transactions. The caller is
 //! responsible for obtaining full transactions before applying. This can be done with
 //! these steps:
 //!
 //! 1. Determine which full transactions are missing. The method [`missing_full_txs`] of
-//! [`IncompleteTxGraph`] can be used.
+//! [`RelevantTxids`] can be used.
 //!
 //! 2. Obtaining the full transactions. To do this via electrum, the method
 //! [`batch_transaction_get`] can be used.
@@ -18,7 +18,7 @@
 //! Refer to [`bdk_electrum_example`] for a complete example.
 //!
 //! [`ElectrumClient::scan`]: electrum_client::ElectrumClient::scan
-//! [`missing_full_txs`]: IncompleteTxGraph::missing_full_txs
+//! [`missing_full_txs`]: RelevantTxids::missing_full_txs
 //! [`batch_transaction_get`]: electrum_client::ElectrumApi::batch_transaction_get
 //! [`bdk_electrum_example`]: https://github.com/LLFourn/bdk_core_staging/tree/master/bdk_electrum_example
 
index 84501358cbbe4cba111a007635c62eeec20d60d3..a05e85c5741199ff1a8706aaa0e09aa54e4613a9 100644 (file)
@@ -13,7 +13,7 @@ use bdk_chain::{
 };
 use bdk_electrum::{
     electrum_client::{self, ElectrumApi},
-    ElectrumExt,
+    ElectrumExt, ElectrumUpdate,
 };
 use example_cli::{
     anyhow::{self, Context},
@@ -66,16 +66,16 @@ type ChangeSet = (
 );
 
 fn main() -> anyhow::Result<()> {
-    let (args, keymap, index, db, init_changeset) =
+    let (args, keymap, index, db, (disk_local_chain, disk_tx_graph)) =
         example_cli::init::<ElectrumCommands, ChangeSet>(DB_MAGIC, DB_PATH)?;
 
     let graph = Mutex::new({
         let mut graph = IndexedTxGraph::new(index);
-        graph.apply_changeset(init_changeset.1);
+        graph.apply_changeset(disk_tx_graph);
         graph
     });
 
-    let chain = Mutex::new(LocalChain::from_changeset(init_changeset.0));
+    let chain = Mutex::new(LocalChain::from_changeset(disk_local_chain));
 
     let electrum_url = match args.network {
         Network::Bitcoin => "ssl://electrum.blockstream.info:50002",
@@ -251,18 +251,24 @@ fn main() -> anyhow::Result<()> {
             // drop lock on graph and chain
             drop((graph, chain));
 
-            let (chain_update, graph_update) = client
+            let electrum_update = client
                 .scan_without_keychain(tip, spks, txids, outpoints, scan_options.batch_size)
                 .context("scanning the blockchain")?;
-            (chain_update, graph_update, BTreeMap::new())
+            (electrum_update, BTreeMap::new())
         }
     };
 
-    let (chain_update, incomplete_graph_update, keychain_update) = response;
+    let (
+        ElectrumUpdate {
+            chain_update,
+            relevant_txids,
+        },
+        keychain_update,
+    ) = response;
 
     let missing_txids = {
         let graph = &*graph.lock().unwrap();
-        incomplete_graph_update.missing_full_txs(graph.graph())
+        relevant_txids.missing_full_txs(graph.graph())
     };
 
     let now = std::time::UNIX_EPOCH
@@ -270,7 +276,7 @@ fn main() -> anyhow::Result<()> {
         .expect("must get time")
         .as_secs();
 
-    let graph_update = incomplete_graph_update.finalize(&client, Some(now), missing_txids)?;
+    let graph_update = relevant_txids.into_tx_graph(&client, Some(now), missing_txids)?;
 
     let db_changeset = {
         let mut chain = chain.lock().unwrap();
index f723d6655a68a728e74639320ddcee09d402a3ae..a6d7ca52069b2f09ea64a2fe1c2def86c3e99762 100644 (file)
@@ -7,11 +7,13 @@ use std::io::Write;
 use std::str::FromStr;
 
 use bdk::bitcoin::Address;
-use bdk::wallet::WalletUpdate;
+use bdk::wallet::Update;
 use bdk::SignOptions;
 use bdk::{bitcoin::Network, Wallet};
-use bdk_electrum::electrum_client::{self, ElectrumApi};
-use bdk_electrum::ElectrumExt;
+use bdk_electrum::{
+    electrum_client::{self, ElectrumApi},
+    ElectrumExt, ElectrumUpdate,
+};
 use bdk_file_store::Store;
 
 fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -53,16 +55,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
         })
         .collect();
 
-    let (chain_update, incomplete_graph_update, keychain_update) =
-        client.scan(prev_tip, keychain_spks, None, None, STOP_GAP, BATCH_SIZE)?;
+    let (
+        ElectrumUpdate {
+            chain_update,
+            relevant_txids,
+        },
+        keychain_update,
+    ) = client.scan(prev_tip, keychain_spks, None, None, STOP_GAP, BATCH_SIZE)?;
 
     println!();
 
-    let missing = incomplete_graph_update.missing_full_txs(wallet.as_ref());
-    let graph_update =
-        incomplete_graph_update.finalize_with_confirmation_time(&client, None, missing)?;
+    let missing = relevant_txids.missing_full_txs(wallet.as_ref());
+    let graph_update = relevant_txids.into_confirmation_time_tx_graph(&client, None, missing)?;
 
-    let wallet_update = WalletUpdate {
+    let wallet_update = Update {
         last_active_indices: keychain_update,
         graph: graph_update,
         chain: Some(chain_update),
index 49692b5cb2dafdb5591436f54f199ca10f6ecb6c..87a48b1bd6de9588bcc1239349e486082450134b 100644 (file)
@@ -2,7 +2,7 @@ use std::{io::Write, str::FromStr};
 
 use bdk::{
     bitcoin::{Address, Network},
-    wallet::{AddressIndex, WalletUpdate},
+    wallet::{AddressIndex, Update},
     SignOptions, Wallet,
 };
 use bdk_esplora::{esplora_client, EsploraAsyncExt};
@@ -58,7 +58,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
         .await?;
     let missing_heights = wallet.tx_graph().missing_heights(wallet.local_chain());
     let chain_update = client.update_local_chain(prev_tip, missing_heights).await?;
-    let update = WalletUpdate {
+    let update = Update {
         last_active_indices,
         graph: update_graph,
         chain: Some(chain_update),
index fb6e0e8778d997dbbf141ef6dced612d7e7ceec4..8034dabfc621a0bc10e7e725de630afcf0e16d1b 100644 (file)
@@ -7,7 +7,7 @@ use std::{io::Write, str::FromStr};
 
 use bdk::{
     bitcoin::{Address, Network},
-    wallet::{AddressIndex, WalletUpdate},
+    wallet::{AddressIndex, Update},
     SignOptions, Wallet,
 };
 use bdk_esplora::{esplora_client, EsploraExt};
@@ -57,7 +57,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
         client.update_tx_graph(keychain_spks, None, None, STOP_GAP, PARALLEL_REQUESTS)?;
     let missing_heights = wallet.tx_graph().missing_heights(wallet.local_chain());
     let chain_update = client.update_local_chain(prev_tip, missing_heights)?;
-    let update = WalletUpdate {
+    let update = Update {
         last_active_indices,
         graph: update_graph,
         chain: Some(chain_update),