From af75817d4bedbb5e148812d1073fd0729a23358b Mon Sep 17 00:00:00 2001 From: valued mammal Date: Sun, 30 Jun 2024 10:53:35 -0400 Subject: [PATCH] ref(tx_graph): Change last_seen to `HashMap` --- crates/chain/src/tx_graph.rs | 82 ++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs index 199c85ea..b79aa434 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -109,10 +109,11 @@ use core::{ /// [module-level documentation]: crate::tx_graph #[derive(Clone, Debug, PartialEq)] pub struct TxGraph { - // all transactions that the graph is aware of in format: `(tx_node, tx_anchors, tx_last_seen)` - txs: HashMap, Option)>, + // all transactions that the graph is aware of in format: `(tx_node, tx_anchors)` + txs: HashMap)>, spends: BTreeMap>, anchors: BTreeSet<(A, Txid)>, + last_seen: HashMap, // This atrocity exists so that `TxGraph::outspends()` can return a reference. // FIXME: This can be removed once `HashSet::new` is a const fn. @@ -125,6 +126,7 @@ impl Default for TxGraph { txs: Default::default(), spends: Default::default(), anchors: Default::default(), + last_seen: Default::default(), empty_outspends: Default::default(), } } @@ -210,7 +212,7 @@ impl TxGraph { /// /// This includes txouts of both full transactions as well as floating transactions. pub fn all_txouts(&self) -> impl Iterator { - self.txs.iter().flat_map(|(txid, (tx, _, _))| match tx { + self.txs.iter().flat_map(|(txid, (tx, _))| match tx { TxNodeInternal::Whole(tx) => tx .as_ref() .output @@ -232,7 +234,7 @@ impl TxGraph { pub fn floating_txouts(&self) -> impl Iterator { self.txs .iter() - .filter_map(|(txid, (tx_node, _, _))| match tx_node { + .filter_map(|(txid, (tx_node, _))| match tx_node { TxNodeInternal::Whole(_) => None, TxNodeInternal::Partial(txouts) => Some( txouts @@ -247,12 +249,12 @@ impl TxGraph { pub fn full_txs(&self) -> impl Iterator, A>> { self.txs .iter() - .filter_map(|(&txid, (tx, anchors, last_seen))| match tx { + .filter_map(|(&txid, (tx, anchors))| match tx { TxNodeInternal::Whole(tx) => Some(TxNode { txid, tx: tx.clone(), anchors, - last_seen_unconfirmed: *last_seen, + last_seen_unconfirmed: self.last_seen.get(&txid).copied(), }), TxNodeInternal::Partial(_) => None, }) @@ -283,11 +285,11 @@ impl TxGraph { /// Get a transaction node by txid. This only returns `Some` for full transactions. pub fn get_tx_node(&self, txid: Txid) -> Option, A>> { match &self.txs.get(&txid)? { - (TxNodeInternal::Whole(tx), anchors, last_seen) => Some(TxNode { + (TxNodeInternal::Whole(tx), anchors) => Some(TxNode { txid, tx: tx.clone(), anchors, - last_seen_unconfirmed: *last_seen, + last_seen_unconfirmed: self.last_seen.get(&txid).copied(), }), _ => None, } @@ -517,7 +519,6 @@ impl TxGraph { ( TxNodeInternal::Partial([(outpoint.vout, txout)].into()), BTreeSet::new(), - None, ), ); self.apply_update(update) @@ -531,7 +532,7 @@ impl TxGraph { let mut update = Self::default(); update.txs.insert( tx.compute_txid(), - (TxNodeInternal::Whole(tx), BTreeSet::new(), None), + (TxNodeInternal::Whole(tx), BTreeSet::new()), ); self.apply_update(update) } @@ -572,8 +573,7 @@ impl TxGraph { /// [`update_last_seen_unconfirmed`]: Self::update_last_seen_unconfirmed pub fn insert_seen_at(&mut self, txid: Txid, seen_at: u64) -> ChangeSet { let mut update = Self::default(); - let (_, _, update_last_seen) = update.txs.entry(txid).or_default(); - *update_last_seen = Some(seen_at); + update.last_seen.insert(txid, seen_at); self.apply_update(update) } @@ -620,7 +620,7 @@ impl TxGraph { .txs .iter() .filter_map( - |(&txid, (_, anchors, _))| { + |(&txid, (_, anchors))| { if anchors.is_empty() { Some(txid) } else { @@ -669,10 +669,10 @@ impl TxGraph { }); match self.txs.get_mut(&txid) { - Some((tx_node @ TxNodeInternal::Partial(_), _, _)) => { + Some((tx_node @ TxNodeInternal::Partial(_), _)) => { *tx_node = TxNodeInternal::Whole(wrapped_tx.clone()); } - Some((TxNodeInternal::Whole(tx), _, _)) => { + Some((TxNodeInternal::Whole(tx), _)) => { debug_assert_eq!( tx.as_ref().compute_txid(), txid, @@ -680,10 +680,8 @@ impl TxGraph { ); } None => { - self.txs.insert( - txid, - (TxNodeInternal::Whole(wrapped_tx), BTreeSet::new(), None), - ); + self.txs + .insert(txid, (TxNodeInternal::Whole(wrapped_tx), BTreeSet::new())); } } } @@ -692,9 +690,8 @@ impl TxGraph { let tx_entry = self.txs.entry(outpoint.txid).or_default(); match tx_entry { - (TxNodeInternal::Whole(_), _, _) => { /* do nothing since we already have full tx */ - } - (TxNodeInternal::Partial(txouts), _, _) => { + (TxNodeInternal::Whole(_), _) => { /* do nothing since we already have full tx */ } + (TxNodeInternal::Partial(txouts), _) => { txouts.insert(outpoint.vout, txout); } } @@ -702,15 +699,15 @@ impl TxGraph { for (anchor, txid) in changeset.anchors { if self.anchors.insert((anchor.clone(), txid)) { - let (_, anchors, _) = self.txs.entry(txid).or_default(); + let (_, anchors) = self.txs.entry(txid).or_default(); anchors.insert(anchor); } } for (txid, new_last_seen) in changeset.last_seen { - let (_, _, last_seen) = self.txs.entry(txid).or_default(); - if Some(new_last_seen) > *last_seen { - *last_seen = Some(new_last_seen); + let last_seen = self.last_seen.entry(txid).or_default(); + if new_last_seen > *last_seen { + *last_seen = new_last_seen; } } } @@ -722,11 +719,10 @@ impl TxGraph { pub(crate) fn determine_changeset(&self, update: TxGraph) -> ChangeSet { let mut changeset = ChangeSet::::default(); - for (&txid, (update_tx_node, _, update_last_seen)) in &update.txs { - let prev_last_seen = match (self.txs.get(&txid), update_tx_node) { + for (&txid, (update_tx_node, _)) in &update.txs { + match (self.txs.get(&txid), update_tx_node) { (None, TxNodeInternal::Whole(update_tx)) => { changeset.txs.insert(update_tx.clone()); - None } (None, TxNodeInternal::Partial(update_txos)) => { changeset.txouts.extend( @@ -734,18 +730,13 @@ impl TxGraph { .iter() .map(|(&vout, txo)| (OutPoint::new(txid, vout), txo.clone())), ); - None } - (Some((TxNodeInternal::Whole(_), _, last_seen)), _) => *last_seen, - ( - Some((TxNodeInternal::Partial(_), _, last_seen)), - TxNodeInternal::Whole(update_tx), - ) => { + (Some((TxNodeInternal::Whole(_), _)), _) => {} + (Some((TxNodeInternal::Partial(_), _)), TxNodeInternal::Whole(update_tx)) => { changeset.txs.insert(update_tx.clone()); - *last_seen } ( - Some((TxNodeInternal::Partial(txos), _, last_seen)), + Some((TxNodeInternal::Partial(txos), _)), TxNodeInternal::Partial(update_txos), ) => { changeset.txouts.extend( @@ -754,15 +745,14 @@ impl TxGraph { .filter(|(vout, _)| !txos.contains_key(*vout)) .map(|(&vout, txo)| (OutPoint::new(txid, vout), txo.clone())), ); - *last_seen } - }; + } + } - if *update_last_seen > prev_last_seen { - changeset.last_seen.insert( - txid, - update_last_seen.expect("checked is greater, so we must have a last_seen"), - ); + for (txid, update_last_seen) in update.last_seen { + let prev_last_seen = self.last_seen.get(&txid).copied(); + if Some(update_last_seen) > prev_last_seen { + changeset.last_seen.insert(txid, update_last_seen); } } @@ -802,7 +792,7 @@ impl TxGraph { chain_tip: BlockId, txid: Txid, ) -> Result>, C::Error> { - let (tx_node, anchors, last_seen) = match self.txs.get(&txid) { + let (tx_node, anchors) = match self.txs.get(&txid) { Some(v) => v, None => return Ok(None), }; @@ -816,7 +806,7 @@ impl TxGraph { // If no anchors are in best chain and we don't have a last_seen, we can return // early because by definition the tx doesn't have a chain position. - let last_seen = match last_seen { + let last_seen = match self.last_seen.get(&txid) { Some(t) => *t, None => return Ok(None), };