/// Inserts the given `seen_at` for `txid` into [`TxGraph`].
///
- /// Note that [`TxGraph`] only keeps track of the latest `seen_at`. To batch
- /// update all unconfirmed transactions with the latest `seen_at`, see
- /// [`update_last_seen_unconfirmed`].
- ///
- /// [`update_last_seen_unconfirmed`]: Self::update_last_seen_unconfirmed
+ /// Note that [`TxGraph`] only keeps track of the latest `seen_at`.
pub fn insert_seen_at(&mut self, txid: Txid, seen_at: u64) -> ChangeSet<A> {
let mut changeset = ChangeSet::<A>::default();
let last_seen = self.last_seen.entry(txid).or_default();
changeset
}
- /// Update the last seen time for all unconfirmed transactions.
- ///
- /// This method updates the last seen unconfirmed time for this [`TxGraph`] by inserting
- /// the given `seen_at` for every transaction not yet anchored to a confirmed block,
- /// and returns the [`ChangeSet`] after applying all updates to `self`.
- ///
- /// This is useful for keeping track of the latest time a transaction was seen
- /// unconfirmed, which is important for evaluating transaction conflicts in the same
- /// [`TxGraph`]. For details of how [`TxGraph`] resolves conflicts, see the docs for
- /// [`try_get_chain_position`].
- ///
- /// A normal use of this method is to call it with the current system time. Although
- /// block headers contain a timestamp, using the header time would be less effective
- /// at tracking mempool transactions, because it can drift from actual clock time, plus
- /// we may want to update a transaction's last seen time repeatedly between blocks.
- ///
- /// # Example
- ///
- /// ```rust
- /// # use bdk_chain::example_utils::*;
- /// # use std::time::UNIX_EPOCH;
- /// # let tx = tx_from_hex(RAW_TX_1);
- /// # let mut tx_graph = bdk_chain::TxGraph::<()>::new([tx]);
- /// let now = std::time::SystemTime::now()
- /// .duration_since(UNIX_EPOCH)
- /// .expect("valid duration")
- /// .as_secs();
- /// let changeset = tx_graph.update_last_seen_unconfirmed(now);
- /// assert!(!changeset.last_seen.is_empty());
- /// ```
- ///
- /// Note that [`TxGraph`] only keeps track of the latest `seen_at`, so the given time must
- /// by strictly greater than what is currently stored for a transaction to have an effect.
- /// To insert a last seen time for a single txid, see [`insert_seen_at`].
- ///
- /// [`insert_seen_at`]: Self::insert_seen_at
- /// [`try_get_chain_position`]: Self::try_get_chain_position
- pub fn update_last_seen_unconfirmed(&mut self, seen_at: u64) -> ChangeSet<A> {
- let mut changeset = ChangeSet::default();
- let unanchored_txs: Vec<Txid> = self
- .txs
- .iter()
- .filter_map(
- |(&txid, (_, anchors))| {
- if anchors.is_empty() {
- Some(txid)
- } else {
- None
- }
- },
- )
- .collect();
-
- for txid in unanchored_txs {
- changeset.merge(self.insert_seen_at(txid, seen_at));
- }
- changeset
- }
-
/// Extends this graph with the given `update`.
///
/// The returned [`ChangeSet`] is the set difference between `update` and `self` (transactions that
}
}
-#[test]
-fn update_last_seen_unconfirmed() {
- let mut graph = TxGraph::<()>::default();
- let tx = new_tx(0);
- let txid = tx.compute_txid();
-
- // insert a new tx
- // initially we have a last_seen of None and no anchors
- let _ = graph.insert_tx(tx);
- let tx = graph.full_txs().next().unwrap();
- assert_eq!(tx.last_seen_unconfirmed, None);
- assert!(tx.anchors.is_empty());
-
- // higher timestamp should update last seen
- let changeset = graph.update_last_seen_unconfirmed(2);
- assert_eq!(changeset.last_seen.get(&txid).unwrap(), &2);
-
- // lower timestamp has no effect
- let changeset = graph.update_last_seen_unconfirmed(1);
- assert!(changeset.last_seen.is_empty());
-
- // once anchored, last seen is not updated
- let _ = graph.insert_anchor(txid, ());
- let changeset = graph.update_last_seen_unconfirmed(4);
- assert!(changeset.is_empty());
- assert_eq!(
- graph
- .full_txs()
- .next()
- .unwrap()
- .last_seen_unconfirmed
- .unwrap(),
- 2
- );
-}
-
#[test]
fn transactions_inserted_into_tx_graph_are_not_canonical_until_they_have_an_anchor_in_best_chain() {
let txs = vec![new_tx(0), new_tx(1)];