]> Untitled Git - bdk/commitdiff
[bdk_chain_redesign] Better names, comments and generic bounds
author志宇 <hello@evanlinjin.me>
Wed, 5 Apr 2023 08:39:54 +0000 (16:39 +0800)
committer志宇 <hello@evanlinjin.me>
Wed, 5 Apr 2023 08:39:54 +0000 (16:39 +0800)
* Instead of implementing `ChainPosition` for `ObservedIn<BlockId>` to
  use `FullTxOut` methods (`is_spendable_at` and `is_mature`), we create
  alternative versions of those methods that require bounds with `Anchor`.
  This removes all `ObservedIn<A>: ChainPosition` bounds for methods of
  `IndexedTxGraph`.

* Various improvements to comments and names.

crates/chain/src/chain_data.rs
crates/chain/src/chain_graph.rs
crates/chain/src/indexed_tx_graph.rs
crates/chain/src/local_chain.rs
crates/chain/src/sparse_chain.rs
crates/chain/src/tx_graph.rs

index 6c1c2c3a68c95d044e68d89c6342dadceef7c9f2..85f9107c1209456ba0dc3490bba78cedfee05b4a 100644 (file)
@@ -6,49 +6,21 @@ use crate::{
 };
 
 /// Represents an observation of some chain data.
+///
+/// The generic `A` should be a [`BlockAnchor`] implementation.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, core::hash::Hash)]
-pub enum ObservedIn<A> {
-    /// The chain data is seen in a block identified by `A`.
-    Block(A),
+pub enum ObservedAs<A> {
+    /// The chain data is seen as confirmed, and in anchored by `A`.
+    Confirmed(A),
     /// The chain data is seen in mempool at this given timestamp.
-    /// TODO: Call this `Unconfirmed`.
-    Mempool(u64),
+    Unconfirmed(u64),
 }
 
-impl<A: Clone> ObservedIn<&A> {
-    pub fn into_owned(self) -> ObservedIn<A> {
+impl<A: Clone> ObservedAs<&A> {
+    pub fn cloned(self) -> ObservedAs<A> {
         match self {
-            ObservedIn::Block(a) => ObservedIn::Block(a.clone()),
-            ObservedIn::Mempool(last_seen) => ObservedIn::Mempool(last_seen),
-        }
-    }
-}
-
-impl ChainPosition for ObservedIn<BlockId> {
-    fn height(&self) -> TxHeight {
-        match self {
-            ObservedIn::Block(block_id) => TxHeight::Confirmed(block_id.height),
-            ObservedIn::Mempool(_) => TxHeight::Unconfirmed,
-        }
-    }
-
-    fn max_ord_of_height(height: TxHeight) -> Self {
-        match height {
-            TxHeight::Confirmed(height) => ObservedIn::Block(BlockId {
-                height,
-                hash: Hash::from_inner([u8::MAX; 32]),
-            }),
-            TxHeight::Unconfirmed => Self::Mempool(u64::MAX),
-        }
-    }
-
-    fn min_ord_of_height(height: TxHeight) -> Self {
-        match height {
-            TxHeight::Confirmed(height) => ObservedIn::Block(BlockId {
-                height,
-                hash: Hash::from_inner([u8::MIN; 32]),
-            }),
-            TxHeight::Unconfirmed => Self::Mempool(u64::MIN),
+            ObservedAs::Confirmed(a) => ObservedAs::Confirmed(a.clone()),
+            ObservedAs::Unconfirmed(last_seen) => ObservedAs::Unconfirmed(last_seen),
         }
     }
 }
@@ -217,20 +189,20 @@ impl From<(&u32, &BlockHash)> for BlockId {
 
 /// A `TxOut` with as much data as we can retrieve about it
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct FullTxOut<I> {
+pub struct FullTxOut<P> {
     /// The location of the `TxOut`.
     pub outpoint: OutPoint,
     /// The `TxOut`.
     pub txout: TxOut,
     /// The position of the transaction in `outpoint` in the overall chain.
-    pub chain_position: I,
+    pub chain_position: P,
     /// The txid and chain position of the transaction (if any) that has spent this output.
-    pub spent_by: Option<(I, Txid)>,
+    pub spent_by: Option<(P, Txid)>,
     /// Whether this output is on a coinbase transaction.
     pub is_on_coinbase: bool,
 }
 
-impl<I: ChainPosition> FullTxOut<I> {
+impl<P: ChainPosition> FullTxOut<P> {
     /// Whether the utxo is/was/will be spendable at `height`.
     ///
     /// It is spendable if it is not an immature coinbase output and no spending tx has been
@@ -269,15 +241,63 @@ impl<I: ChainPosition> FullTxOut<I> {
     }
 }
 
-impl<A: Clone> FullTxOut<ObservedIn<&A>> {
-    pub fn into_owned(self) -> FullTxOut<ObservedIn<A>> {
-        FullTxOut {
-            outpoint: self.outpoint,
-            txout: self.txout,
-            chain_position: self.chain_position.into_owned(),
-            spent_by: self.spent_by.map(|(o, txid)| (o.into_owned(), txid)),
-            is_on_coinbase: self.is_on_coinbase,
+impl<A: BlockAnchor> FullTxOut<ObservedAs<A>> {
+    /// Whether the `txout` is considered mature.
+    ///
+    /// This is the alternative version of [`is_mature`] which depends on `chain_position` being a
+    /// [`ObservedAs<A>`] where `A` implements [`BlockAnchor`].
+    ///
+    /// [`is_mature`]: Self::is_mature
+    pub fn is_observed_as_mature(&self, tip: u32) -> bool {
+        if !self.is_on_coinbase {
+            return false;
         }
+
+        let tx_height = match &self.chain_position {
+            ObservedAs::Confirmed(anchor) => anchor.anchor_block().height,
+            ObservedAs::Unconfirmed(_) => {
+                debug_assert!(false, "coinbase tx can never be unconfirmed");
+                return false;
+            }
+        };
+
+        let age = tip.saturating_sub(tx_height);
+        if age + 1 < COINBASE_MATURITY {
+            return false;
+        }
+
+        true
+    }
+
+    /// Whether the utxo is/was/will be spendable with chain `tip`.
+    ///
+    /// This is the alternative version of [`is_spendable_at`] which depends on `chain_position`
+    /// being a [`ObservedAs<A>`] where `A` implements [`BlockAnchor`].
+    ///
+    /// [`is_spendable_at`]: Self::is_spendable_at
+    pub fn is_observed_as_spendable(&self, tip: u32) -> bool {
+        if !self.is_observed_as_mature(tip) {
+            return false;
+        }
+
+        match &self.chain_position {
+            ObservedAs::Confirmed(anchor) => {
+                if anchor.anchor_block().height > tip {
+                    return false;
+                }
+            }
+            // [TODO] Why are unconfirmed txs always considered unspendable here?
+            ObservedAs::Unconfirmed(_) => return false,
+        };
+
+        // if the spending tx is confirmed within tip height, the txout is no longer spendable
+        if let Some((ObservedAs::Confirmed(spending_anchor), _)) = &self.spent_by {
+            if spending_anchor.anchor_block().height <= tip {
+                return false;
+            }
+        }
+
+        true
     }
 }
 
index 8c954f8dadfbc0dcb24dace797aaa94d6e64076c..0e3e3439e461c28283865c41b6174efba95962b4 100644 (file)
@@ -151,7 +151,7 @@ where
                         let _ = inflated_chain
                             .insert_tx(*txid, pos.clone())
                             .expect("must insert since this was already in update");
-                        let _ = inflated_graph.insert_tx(tx.clone());
+                        let _ = inflated_graph.insert_tx(tx);
                     }
                 }
                 None => {
@@ -212,8 +212,8 @@ where
     /// the unconfirmed transaction list within the [`SparseChain`].
     pub fn get_tx_in_chain(&self, txid: Txid) -> Option<(&P, &Transaction)> {
         let position = self.chain.tx_position(txid)?;
-        let tx = self.graph.get_tx(txid).expect("must exist");
-        Some((position, tx))
+        let full_tx = self.graph.get_tx(txid).expect("must exist");
+        Some((position, full_tx))
     }
 
     /// Determines the changes required to insert a transaction into the inner [`ChainGraph`] and
index a3996c132b4ca6a4ee6ff3fecac56c881f2a6058..e2d71af1cc8d655b2ddd54dc3789ed1e46e15bc9 100644 (file)
@@ -4,16 +4,15 @@ use bitcoin::{OutPoint, Script, Transaction, TxOut};
 
 use crate::{
     keychain::Balance,
-    sparse_chain::ChainPosition,
     tx_graph::{Additions, TxGraph, TxNode},
-    BlockAnchor, ChainOracle, FullTxOut, ObservedIn, TxIndex,
+    BlockAnchor, ChainOracle, FullTxOut, ObservedAs, TxIndex,
 };
 
 /// An outwards-facing view of a transaction that is part of the *best chain*'s history.
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub struct TxInChain<'a, T, A> {
+pub struct CanonicalTx<'a, T, A> {
     /// Where the transaction is observed (in a block or in mempool).
-    pub observed_in: ObservedIn<&'a A>,
+    pub observed_as: ObservedAs<&'a A>,
     /// The transaction with anchors and last seen timestamp.
     pub tx: TxNode<'a, T, A>,
 }
@@ -140,19 +139,23 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
         &mut self,
         outpoint: OutPoint,
         txout: &TxOut,
-        observation: ObservedIn<A>,
+        observation: ObservedAs<A>,
     ) -> IndexedAdditions<A, I::Additions> {
         let last_height = match &observation {
-            ObservedIn::Block(anchor) => self.insert_height_internal(anchor.anchor_block().height),
-            ObservedIn::Mempool(_) => None,
+            ObservedAs::Confirmed(anchor) => {
+                self.insert_height_internal(anchor.anchor_block().height)
+            }
+            ObservedAs::Unconfirmed(_) => None,
         };
 
         IndexedAdditions {
             graph_additions: {
                 let mut graph_additions = self.graph.insert_txout(outpoint, txout.clone());
                 graph_additions.append(match observation {
-                    ObservedIn::Block(anchor) => self.graph.insert_anchor(outpoint.txid, anchor),
-                    ObservedIn::Mempool(seen_at) => {
+                    ObservedAs::Confirmed(anchor) => {
+                        self.graph.insert_anchor(outpoint.txid, anchor)
+                    }
+                    ObservedAs::Unconfirmed(seen_at) => {
                         self.graph.insert_seen_at(outpoint.txid, seen_at)
                     }
                 });
@@ -166,21 +169,23 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn insert_tx(
         &mut self,
         tx: &Transaction,
-        observation: ObservedIn<A>,
+        observation: ObservedAs<A>,
     ) -> IndexedAdditions<A, I::Additions> {
         let txid = tx.txid();
 
         let last_height = match &observation {
-            ObservedIn::Block(anchor) => self.insert_height_internal(anchor.anchor_block().height),
-            ObservedIn::Mempool(_) => None,
+            ObservedAs::Confirmed(anchor) => {
+                self.insert_height_internal(anchor.anchor_block().height)
+            }
+            ObservedAs::Unconfirmed(_) => None,
         };
 
         IndexedAdditions {
             graph_additions: {
                 let mut graph_additions = self.graph.insert_tx(tx.clone());
                 graph_additions.append(match observation {
-                    ObservedIn::Block(anchor) => self.graph.insert_anchor(txid, anchor),
-                    ObservedIn::Mempool(seen_at) => self.graph.insert_seen_at(txid, seen_at),
+                    ObservedAs::Confirmed(anchor) => self.graph.insert_anchor(txid, anchor),
+                    ObservedAs::Unconfirmed(seen_at) => self.graph.insert_seen_at(txid, seen_at),
                 });
                 graph_additions
             },
@@ -192,7 +197,7 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn filter_and_insert_txs<'t, T>(
         &mut self,
         txs: T,
-        observation: ObservedIn<A>,
+        observation: ObservedAs<A>,
     ) -> IndexedAdditions<A, I::Additions>
     where
         T: Iterator<Item = &'t Transaction>,
@@ -220,7 +225,7 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn try_list_chain_txs<'a, C>(
         &'a self,
         chain: C,
-    ) -> impl Iterator<Item = Result<TxInChain<'a, Transaction, A>, C::Error>>
+    ) -> impl Iterator<Item = Result<CanonicalTx<'a, Transaction, A>, C::Error>>
     where
         C: ChainOracle + 'a,
     {
@@ -230,7 +235,12 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
             .filter_map(move |tx| {
                 self.graph
                     .try_get_chain_position(&chain, tx.txid)
-                    .map(|v| v.map(|observed_in| TxInChain { observed_in, tx }))
+                    .map(|v| {
+                        v.map(|observed_in| CanonicalTx {
+                            observed_as: observed_in,
+                            tx,
+                        })
+                    })
                     .transpose()
             })
     }
@@ -238,7 +248,7 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn list_chain_txs<'a, C>(
         &'a self,
         chain: C,
-    ) -> impl Iterator<Item = TxInChain<'a, Transaction, A>>
+    ) -> impl Iterator<Item = CanonicalTx<'a, Transaction, A>>
     where
         C: ChainOracle<Error = Infallible> + 'a,
     {
@@ -249,10 +259,9 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn try_list_chain_txouts<'a, C>(
         &'a self,
         chain: C,
-    ) -> impl Iterator<Item = Result<FullTxOut<ObservedIn<A>>, C::Error>> + 'a
+    ) -> impl Iterator<Item = Result<FullTxOut<ObservedAs<A>>, C::Error>> + 'a
     where
         C: ChainOracle + 'a,
-        ObservedIn<A>: ChainPosition,
     {
         self.graph
             .all_txouts()
@@ -263,13 +272,13 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
                 let is_on_coinbase = graph_tx.is_coin_base();
 
                 let chain_position = match self.graph.try_get_chain_position(&chain, op.txid) {
-                    Ok(Some(observed_at)) => observed_at.into_owned(),
+                    Ok(Some(observed_at)) => observed_at.cloned(),
                     Ok(None) => return None,
                     Err(err) => return Some(Err(err)),
                 };
 
                 let spent_by = match self.graph.try_get_spend_in_chain(&chain, op) {
-                    Ok(Some((obs, txid))) => Some((obs.into_owned(), txid)),
+                    Ok(Some((obs, txid))) => Some((obs.cloned(), txid)),
                     Ok(None) => None,
                     Err(err) => return Some(Err(err)),
                 };
@@ -289,10 +298,9 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn list_chain_txouts<'a, C>(
         &'a self,
         chain: C,
-    ) -> impl Iterator<Item = FullTxOut<ObservedIn<A>>> + 'a
+    ) -> impl Iterator<Item = FullTxOut<ObservedAs<A>>> + 'a
     where
         C: ChainOracle<Error = Infallible> + 'a,
-        ObservedIn<A>: ChainPosition,
     {
         self.try_list_chain_txouts(chain)
             .map(|r| r.expect("error in infallible"))
@@ -302,10 +310,9 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn try_list_chain_utxos<'a, C>(
         &'a self,
         chain: C,
-    ) -> impl Iterator<Item = Result<FullTxOut<ObservedIn<A>>, C::Error>> + 'a
+    ) -> impl Iterator<Item = Result<FullTxOut<ObservedAs<A>>, C::Error>> + 'a
     where
         C: ChainOracle + 'a,
-        ObservedIn<A>: ChainPosition,
     {
         self.try_list_chain_txouts(chain)
             .filter(|r| !matches!(r, Ok(txo) if txo.spent_by.is_none()))
@@ -314,10 +321,9 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn list_chain_utxos<'a, C>(
         &'a self,
         chain: C,
-    ) -> impl Iterator<Item = FullTxOut<ObservedIn<A>>> + 'a
+    ) -> impl Iterator<Item = FullTxOut<ObservedAs<A>>> + 'a
     where
         C: ChainOracle<Error = Infallible> + 'a,
-        ObservedIn<A>: ChainPosition,
     {
         self.try_list_chain_utxos(chain)
             .map(|r| r.expect("error is infallible"))
@@ -331,7 +337,6 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     ) -> Result<Balance, C::Error>
     where
         C: ChainOracle,
-        ObservedIn<A>: ChainPosition + Clone,
         F: FnMut(&Script) -> bool,
     {
         let mut immature = 0;
@@ -343,16 +348,16 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
             let txout = res?;
 
             match &txout.chain_position {
-                ObservedIn::Block(_) => {
+                ObservedAs::Confirmed(_) => {
                     if txout.is_on_coinbase {
-                        if txout.is_mature(tip) {
+                        if txout.is_observed_as_mature(tip) {
                             confirmed += txout.txout.value;
                         } else {
                             immature += txout.txout.value;
                         }
                     }
                 }
-                ObservedIn::Mempool(_) => {
+                ObservedAs::Unconfirmed(_) => {
                     if should_trust(&txout.txout.script_pubkey) {
                         trusted_pending += txout.txout.value;
                     } else {
@@ -373,7 +378,6 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn balance<C, F>(&self, chain: C, tip: u32, should_trust: F) -> Balance
     where
         C: ChainOracle<Error = Infallible>,
-        ObservedIn<A>: ChainPosition + Clone,
         F: FnMut(&Script) -> bool,
     {
         self.try_balance(chain, tip, should_trust)
@@ -383,12 +387,11 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn try_balance_at<C>(&self, chain: C, height: u32) -> Result<u64, C::Error>
     where
         C: ChainOracle,
-        ObservedIn<A>: ChainPosition + Clone,
     {
         let mut sum = 0;
         for txo_res in self.try_list_chain_txouts(chain) {
             let txo = txo_res?;
-            if txo.is_spendable_at(height) {
+            if txo.is_observed_as_spendable(height) {
                 sum += txo.txout.value;
             }
         }
@@ -398,7 +401,6 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
     pub fn balance_at<C>(&self, chain: C, height: u32) -> u64
     where
         C: ChainOracle<Error = Infallible>,
-        ObservedIn<A>: ChainPosition + Clone,
     {
         self.try_balance_at(chain, height)
             .expect("error is infallible")
index a1ca921b98b4ee58c7bb5a60fc29bd4e22914c42..fb7d008d169935d18700b62a529dbecd30d898ee 100644 (file)
@@ -123,7 +123,7 @@ impl LocalChain {
 
     /// Updates [`LocalChain`] with an update [`LocalChain`].
     ///
-    /// This is equivilant to calling [`determine_changeset`] and [`apply_changeset`] in sequence.
+    /// This is equivalent to calling [`determine_changeset`] and [`apply_changeset`] in sequence.
     ///
     /// [`determine_changeset`]: Self::determine_changeset
     /// [`apply_changeset`]: Self::apply_changeset
index 7f0b67e50d8f5e1da6f47911e5ca6295efddd51f..b615f4aac464869d8b1a9b62944714bffbf47674 100644 (file)
@@ -457,7 +457,7 @@ impl<P: core::fmt::Debug> core::fmt::Display for UpdateError<P> {
 #[cfg(feature = "std")]
 impl<P: core::fmt::Debug> std::error::Error for UpdateError<P> {}
 
-impl<P: ChainPosition> ChainOracle for SparseChain<P> {
+impl<P> ChainOracle for SparseChain<P> {
     type Error = Infallible;
 
     fn get_tip_in_best_chain(&self) -> Result<Option<BlockId>, Self::Error> {
@@ -473,7 +473,7 @@ impl<P: ChainPosition> ChainOracle for SparseChain<P> {
     }
 }
 
-impl<P: ChainPosition> SparseChain<P> {
+impl<P> SparseChain<P> {
     /// Creates a new chain from a list of block hashes and heights. The caller must guarantee they
     /// are in the same chain.
     pub fn from_checkpoints<C>(checkpoints: C) -> Self
@@ -504,13 +504,6 @@ impl<P: ChainPosition> SparseChain<P> {
             .map(|&hash| BlockId { height, hash })
     }
 
-    /// Return the [`ChainPosition`] of a `txid`.
-    ///
-    /// This returns [`None`] if the transaction does not exist.
-    pub fn tx_position(&self, txid: Txid) -> Option<&P> {
-        self.txid_to_pos.get(&txid)
-    }
-
     /// Return a [`BTreeMap`] of all checkpoints (block hashes by height).
     pub fn checkpoints(&self) -> &BTreeMap<u32, BlockHash> {
         &self.checkpoints
@@ -526,6 +519,47 @@ impl<P: ChainPosition> SparseChain<P> {
             .map(|(&height, &hash)| BlockId { height, hash })
     }
 
+    /// Returns the value set as the checkpoint limit.
+    ///
+    /// Refer to [`set_checkpoint_limit`].
+    ///
+    /// [`set_checkpoint_limit`]: Self::set_checkpoint_limit
+    pub fn checkpoint_limit(&self) -> Option<usize> {
+        self.checkpoint_limit
+    }
+
+    /// Set the checkpoint limit.
+    ///
+    /// The checkpoint limit restricts the number of checkpoints that can be stored in [`Self`].
+    /// Oldest checkpoints are pruned first.
+    pub fn set_checkpoint_limit(&mut self, limit: Option<usize>) {
+        self.checkpoint_limit = limit;
+        self.prune_checkpoints();
+    }
+
+    fn prune_checkpoints(&mut self) -> Option<BTreeMap<u32, BlockHash>> {
+        let limit = self.checkpoint_limit?;
+
+        // find the last height to be pruned
+        let last_height = *self.checkpoints.keys().rev().nth(limit)?;
+        // first height to be kept
+        let keep_height = last_height + 1;
+
+        let mut split = self.checkpoints.split_off(&keep_height);
+        core::mem::swap(&mut self.checkpoints, &mut split);
+
+        Some(split)
+    }
+}
+
+impl<P: ChainPosition> SparseChain<P> {
+    /// Return the [`ChainPosition`] of a `txid`.
+    ///
+    /// This returns [`None`] if the transaction does not exist.
+    pub fn tx_position(&self, txid: Txid) -> Option<&P> {
+        self.txid_to_pos.get(&txid)
+    }
+
     /// Preview changes of updating [`Self`] with another chain that connects to it.
     ///
     /// If the `update` wishes to introduce confirmed transactions, it must contain a checkpoint
@@ -936,24 +970,6 @@ impl<P: ChainPosition> SparseChain<P> {
         })
     }
 
-    /// Returns the value set as the checkpoint limit.
-    ///
-    /// Refer to [`set_checkpoint_limit`].
-    ///
-    /// [`set_checkpoint_limit`]: Self::set_checkpoint_limit
-    pub fn checkpoint_limit(&self) -> Option<usize> {
-        self.checkpoint_limit
-    }
-
-    /// Set the checkpoint limit.
-    ///
-    /// The checkpoint limit restricts the number of checkpoints that can be stored in [`Self`].
-    /// Oldest checkpoints are pruned first.
-    pub fn set_checkpoint_limit(&mut self, limit: Option<usize>) {
-        self.checkpoint_limit = limit;
-        self.prune_checkpoints();
-    }
-
     /// Return [`Txid`]s that would be added to the sparse chain if this `changeset` was applied.
     pub fn changeset_additions<'a>(
         &'a self,
@@ -969,20 +985,6 @@ impl<P: ChainPosition> SparseChain<P> {
             .map(|(&txid, _)| txid)
     }
 
-    fn prune_checkpoints(&mut self) -> Option<BTreeMap<u32, BlockHash>> {
-        let limit = self.checkpoint_limit?;
-
-        // find the last height to be pruned
-        let last_height = *self.checkpoints.keys().rev().nth(limit)?;
-        // first height to be kept
-        let keep_height = last_height + 1;
-
-        let mut split = self.checkpoints.split_off(&keep_height);
-        core::mem::swap(&mut self.checkpoints, &mut split);
-
-        Some(split)
-    }
-
     /// Finds the transaction in the chain that spends `outpoint`.
     ///
     /// [`TxGraph`] is used to provide the spend relationships.
index 893060ae3447b45a207928a2929ea12c25d356a9..620a2dc3d0ed9f9e1b5672c28d41b05864596a96 100644 (file)
@@ -55,7 +55,7 @@
 //! assert!(additions.is_empty());
 //! ```
 
-use crate::{collections::*, BlockAnchor, ChainOracle, ForEachTxOut, ObservedIn};
+use crate::{collections::*, BlockAnchor, ChainOracle, ForEachTxOut, ObservedAs};
 use alloc::vec::Vec;
 use bitcoin::{OutPoint, Transaction, TxOut, Txid};
 use core::{
@@ -91,10 +91,7 @@ impl<A> Default for TxGraph<A> {
     }
 }
 
-// pub type InChainTx<'a, T, A> = (ObservedIn<&'a A>, TxInGraph<'a, T, A>);
-// pub type InChainTxOut<'a, I, A> = (&'a I, FullTxOut<ObservedIn<&'a A>>);
-
-/// An outward-facing view of a transaction node that resides in a [`TxGraph`].
+/// An outward-facing representation of a (transaction) node in the [`TxGraph`].
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub struct TxNode<'a, T, A> {
     /// Txid of the transaction.
@@ -601,7 +598,7 @@ impl<A: BlockAnchor> TxGraph<A> {
         &self,
         chain: C,
         txid: Txid,
-    ) -> Result<Option<ObservedIn<&A>>, C::Error>
+    ) -> Result<Option<ObservedAs<&A>>, C::Error>
     where
         C: ChainOracle,
     {
@@ -614,7 +611,7 @@ impl<A: BlockAnchor> TxGraph<A> {
 
         for anchor in anchors {
             if chain.is_block_in_best_chain(anchor.anchor_block())? {
-                return Ok(Some(ObservedIn::Block(anchor)));
+                return Ok(Some(ObservedAs::Confirmed(anchor)));
             }
         }
 
@@ -643,10 +640,10 @@ impl<A: BlockAnchor> TxGraph<A> {
             }
         }
 
-        Ok(Some(ObservedIn::Mempool(last_seen)))
+        Ok(Some(ObservedAs::Unconfirmed(last_seen)))
     }
 
-    pub fn get_chain_position<C>(&self, chain: C, txid: Txid) -> Option<ObservedIn<&A>>
+    pub fn get_chain_position<C>(&self, chain: C, txid: Txid) -> Option<ObservedAs<&A>>
     where
         C: ChainOracle<Error = Infallible>,
     {
@@ -658,7 +655,7 @@ impl<A: BlockAnchor> TxGraph<A> {
         &self,
         chain: C,
         outpoint: OutPoint,
-    ) -> Result<Option<(ObservedIn<&A>, Txid)>, C::Error>
+    ) -> Result<Option<(ObservedAs<&A>, Txid)>, C::Error>
     where
         C: ChainOracle,
     {
@@ -678,7 +675,7 @@ impl<A: BlockAnchor> TxGraph<A> {
         Ok(None)
     }
 
-    pub fn get_chain_spend<C>(&self, chain: C, outpoint: OutPoint) -> Option<(ObservedIn<&A>, Txid)>
+    pub fn get_chain_spend<C>(&self, chain: C, outpoint: OutPoint) -> Option<(ObservedAs<&A>, Txid)>
     where
         C: ChainOracle<Error = Infallible>,
     {