ref(tx_graph): Change last_seen to HashMap<Txid, u64>
This commit is contained in:
parent
6204d2c766
commit
af75817d4b
@ -109,10 +109,11 @@ use core::{
|
|||||||
/// [module-level documentation]: crate::tx_graph
|
/// [module-level documentation]: crate::tx_graph
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct TxGraph<A = ()> {
|
pub struct TxGraph<A = ()> {
|
||||||
// all transactions that the graph is aware of in format: `(tx_node, tx_anchors, tx_last_seen)`
|
// all transactions that the graph is aware of in format: `(tx_node, tx_anchors)`
|
||||||
txs: HashMap<Txid, (TxNodeInternal, BTreeSet<A>, Option<u64>)>,
|
txs: HashMap<Txid, (TxNodeInternal, BTreeSet<A>)>,
|
||||||
spends: BTreeMap<OutPoint, HashSet<Txid>>,
|
spends: BTreeMap<OutPoint, HashSet<Txid>>,
|
||||||
anchors: BTreeSet<(A, Txid)>,
|
anchors: BTreeSet<(A, Txid)>,
|
||||||
|
last_seen: HashMap<Txid, u64>,
|
||||||
|
|
||||||
// This atrocity exists so that `TxGraph::outspends()` can return a reference.
|
// This atrocity exists so that `TxGraph::outspends()` can return a reference.
|
||||||
// FIXME: This can be removed once `HashSet::new` is a const fn.
|
// FIXME: This can be removed once `HashSet::new` is a const fn.
|
||||||
@ -125,6 +126,7 @@ impl<A> Default for TxGraph<A> {
|
|||||||
txs: Default::default(),
|
txs: Default::default(),
|
||||||
spends: Default::default(),
|
spends: Default::default(),
|
||||||
anchors: Default::default(),
|
anchors: Default::default(),
|
||||||
|
last_seen: Default::default(),
|
||||||
empty_outspends: Default::default(),
|
empty_outspends: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,7 +212,7 @@ impl<A> TxGraph<A> {
|
|||||||
///
|
///
|
||||||
/// This includes txouts of both full transactions as well as floating transactions.
|
/// This includes txouts of both full transactions as well as floating transactions.
|
||||||
pub fn all_txouts(&self) -> impl Iterator<Item = (OutPoint, &TxOut)> {
|
pub fn all_txouts(&self) -> impl Iterator<Item = (OutPoint, &TxOut)> {
|
||||||
self.txs.iter().flat_map(|(txid, (tx, _, _))| match tx {
|
self.txs.iter().flat_map(|(txid, (tx, _))| match tx {
|
||||||
TxNodeInternal::Whole(tx) => tx
|
TxNodeInternal::Whole(tx) => tx
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.output
|
.output
|
||||||
@ -232,7 +234,7 @@ impl<A> TxGraph<A> {
|
|||||||
pub fn floating_txouts(&self) -> impl Iterator<Item = (OutPoint, &TxOut)> {
|
pub fn floating_txouts(&self) -> impl Iterator<Item = (OutPoint, &TxOut)> {
|
||||||
self.txs
|
self.txs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(txid, (tx_node, _, _))| match tx_node {
|
.filter_map(|(txid, (tx_node, _))| match tx_node {
|
||||||
TxNodeInternal::Whole(_) => None,
|
TxNodeInternal::Whole(_) => None,
|
||||||
TxNodeInternal::Partial(txouts) => Some(
|
TxNodeInternal::Partial(txouts) => Some(
|
||||||
txouts
|
txouts
|
||||||
@ -247,12 +249,12 @@ impl<A> TxGraph<A> {
|
|||||||
pub fn full_txs(&self) -> impl Iterator<Item = TxNode<'_, Arc<Transaction>, A>> {
|
pub fn full_txs(&self) -> impl Iterator<Item = TxNode<'_, Arc<Transaction>, A>> {
|
||||||
self.txs
|
self.txs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(&txid, (tx, anchors, last_seen))| match tx {
|
.filter_map(|(&txid, (tx, anchors))| match tx {
|
||||||
TxNodeInternal::Whole(tx) => Some(TxNode {
|
TxNodeInternal::Whole(tx) => Some(TxNode {
|
||||||
txid,
|
txid,
|
||||||
tx: tx.clone(),
|
tx: tx.clone(),
|
||||||
anchors,
|
anchors,
|
||||||
last_seen_unconfirmed: *last_seen,
|
last_seen_unconfirmed: self.last_seen.get(&txid).copied(),
|
||||||
}),
|
}),
|
||||||
TxNodeInternal::Partial(_) => None,
|
TxNodeInternal::Partial(_) => None,
|
||||||
})
|
})
|
||||||
@ -283,11 +285,11 @@ impl<A> TxGraph<A> {
|
|||||||
/// Get a transaction node by txid. This only returns `Some` for full transactions.
|
/// Get a transaction node by txid. This only returns `Some` for full transactions.
|
||||||
pub fn get_tx_node(&self, txid: Txid) -> Option<TxNode<'_, Arc<Transaction>, A>> {
|
pub fn get_tx_node(&self, txid: Txid) -> Option<TxNode<'_, Arc<Transaction>, A>> {
|
||||||
match &self.txs.get(&txid)? {
|
match &self.txs.get(&txid)? {
|
||||||
(TxNodeInternal::Whole(tx), anchors, last_seen) => Some(TxNode {
|
(TxNodeInternal::Whole(tx), anchors) => Some(TxNode {
|
||||||
txid,
|
txid,
|
||||||
tx: tx.clone(),
|
tx: tx.clone(),
|
||||||
anchors,
|
anchors,
|
||||||
last_seen_unconfirmed: *last_seen,
|
last_seen_unconfirmed: self.last_seen.get(&txid).copied(),
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -517,7 +519,6 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
(
|
(
|
||||||
TxNodeInternal::Partial([(outpoint.vout, txout)].into()),
|
TxNodeInternal::Partial([(outpoint.vout, txout)].into()),
|
||||||
BTreeSet::new(),
|
BTreeSet::new(),
|
||||||
None,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
self.apply_update(update)
|
self.apply_update(update)
|
||||||
@ -531,7 +532,7 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
let mut update = Self::default();
|
let mut update = Self::default();
|
||||||
update.txs.insert(
|
update.txs.insert(
|
||||||
tx.compute_txid(),
|
tx.compute_txid(),
|
||||||
(TxNodeInternal::Whole(tx), BTreeSet::new(), None),
|
(TxNodeInternal::Whole(tx), BTreeSet::new()),
|
||||||
);
|
);
|
||||||
self.apply_update(update)
|
self.apply_update(update)
|
||||||
}
|
}
|
||||||
@ -572,8 +573,7 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
/// [`update_last_seen_unconfirmed`]: Self::update_last_seen_unconfirmed
|
/// [`update_last_seen_unconfirmed`]: Self::update_last_seen_unconfirmed
|
||||||
pub fn insert_seen_at(&mut self, txid: Txid, seen_at: u64) -> ChangeSet<A> {
|
pub fn insert_seen_at(&mut self, txid: Txid, seen_at: u64) -> ChangeSet<A> {
|
||||||
let mut update = Self::default();
|
let mut update = Self::default();
|
||||||
let (_, _, update_last_seen) = update.txs.entry(txid).or_default();
|
update.last_seen.insert(txid, seen_at);
|
||||||
*update_last_seen = Some(seen_at);
|
|
||||||
self.apply_update(update)
|
self.apply_update(update)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,7 +620,7 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
.txs
|
.txs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(
|
.filter_map(
|
||||||
|(&txid, (_, anchors, _))| {
|
|(&txid, (_, anchors))| {
|
||||||
if anchors.is_empty() {
|
if anchors.is_empty() {
|
||||||
Some(txid)
|
Some(txid)
|
||||||
} else {
|
} else {
|
||||||
@ -669,10 +669,10 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
match self.txs.get_mut(&txid) {
|
match self.txs.get_mut(&txid) {
|
||||||
Some((tx_node @ TxNodeInternal::Partial(_), _, _)) => {
|
Some((tx_node @ TxNodeInternal::Partial(_), _)) => {
|
||||||
*tx_node = TxNodeInternal::Whole(wrapped_tx.clone());
|
*tx_node = TxNodeInternal::Whole(wrapped_tx.clone());
|
||||||
}
|
}
|
||||||
Some((TxNodeInternal::Whole(tx), _, _)) => {
|
Some((TxNodeInternal::Whole(tx), _)) => {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
tx.as_ref().compute_txid(),
|
tx.as_ref().compute_txid(),
|
||||||
txid,
|
txid,
|
||||||
@ -680,10 +680,8 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.txs.insert(
|
self.txs
|
||||||
txid,
|
.insert(txid, (TxNodeInternal::Whole(wrapped_tx), BTreeSet::new()));
|
||||||
(TxNodeInternal::Whole(wrapped_tx), BTreeSet::new(), None),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -692,9 +690,8 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
let tx_entry = self.txs.entry(outpoint.txid).or_default();
|
let tx_entry = self.txs.entry(outpoint.txid).or_default();
|
||||||
|
|
||||||
match tx_entry {
|
match tx_entry {
|
||||||
(TxNodeInternal::Whole(_), _, _) => { /* do nothing since we already have full tx */
|
(TxNodeInternal::Whole(_), _) => { /* do nothing since we already have full tx */ }
|
||||||
}
|
(TxNodeInternal::Partial(txouts), _) => {
|
||||||
(TxNodeInternal::Partial(txouts), _, _) => {
|
|
||||||
txouts.insert(outpoint.vout, txout);
|
txouts.insert(outpoint.vout, txout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -702,15 +699,15 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
|
|
||||||
for (anchor, txid) in changeset.anchors {
|
for (anchor, txid) in changeset.anchors {
|
||||||
if self.anchors.insert((anchor.clone(), txid)) {
|
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);
|
anchors.insert(anchor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (txid, new_last_seen) in changeset.last_seen {
|
for (txid, new_last_seen) in changeset.last_seen {
|
||||||
let (_, _, last_seen) = self.txs.entry(txid).or_default();
|
let last_seen = self.last_seen.entry(txid).or_default();
|
||||||
if Some(new_last_seen) > *last_seen {
|
if new_last_seen > *last_seen {
|
||||||
*last_seen = Some(new_last_seen);
|
*last_seen = new_last_seen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -722,11 +719,10 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
pub(crate) fn determine_changeset(&self, update: TxGraph<A>) -> ChangeSet<A> {
|
pub(crate) fn determine_changeset(&self, update: TxGraph<A>) -> ChangeSet<A> {
|
||||||
let mut changeset = ChangeSet::<A>::default();
|
let mut changeset = ChangeSet::<A>::default();
|
||||||
|
|
||||||
for (&txid, (update_tx_node, _, update_last_seen)) in &update.txs {
|
for (&txid, (update_tx_node, _)) in &update.txs {
|
||||||
let prev_last_seen = match (self.txs.get(&txid), update_tx_node) {
|
match (self.txs.get(&txid), update_tx_node) {
|
||||||
(None, TxNodeInternal::Whole(update_tx)) => {
|
(None, TxNodeInternal::Whole(update_tx)) => {
|
||||||
changeset.txs.insert(update_tx.clone());
|
changeset.txs.insert(update_tx.clone());
|
||||||
None
|
|
||||||
}
|
}
|
||||||
(None, TxNodeInternal::Partial(update_txos)) => {
|
(None, TxNodeInternal::Partial(update_txos)) => {
|
||||||
changeset.txouts.extend(
|
changeset.txouts.extend(
|
||||||
@ -734,18 +730,13 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(&vout, txo)| (OutPoint::new(txid, vout), txo.clone())),
|
.map(|(&vout, txo)| (OutPoint::new(txid, vout), txo.clone())),
|
||||||
);
|
);
|
||||||
None
|
|
||||||
}
|
}
|
||||||
(Some((TxNodeInternal::Whole(_), _, last_seen)), _) => *last_seen,
|
(Some((TxNodeInternal::Whole(_), _)), _) => {}
|
||||||
(
|
(Some((TxNodeInternal::Partial(_), _)), TxNodeInternal::Whole(update_tx)) => {
|
||||||
Some((TxNodeInternal::Partial(_), _, last_seen)),
|
|
||||||
TxNodeInternal::Whole(update_tx),
|
|
||||||
) => {
|
|
||||||
changeset.txs.insert(update_tx.clone());
|
changeset.txs.insert(update_tx.clone());
|
||||||
*last_seen
|
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
Some((TxNodeInternal::Partial(txos), _, last_seen)),
|
Some((TxNodeInternal::Partial(txos), _)),
|
||||||
TxNodeInternal::Partial(update_txos),
|
TxNodeInternal::Partial(update_txos),
|
||||||
) => {
|
) => {
|
||||||
changeset.txouts.extend(
|
changeset.txouts.extend(
|
||||||
@ -754,15 +745,14 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
.filter(|(vout, _)| !txos.contains_key(*vout))
|
.filter(|(vout, _)| !txos.contains_key(*vout))
|
||||||
.map(|(&vout, txo)| (OutPoint::new(txid, vout), txo.clone())),
|
.map(|(&vout, txo)| (OutPoint::new(txid, vout), txo.clone())),
|
||||||
);
|
);
|
||||||
*last_seen
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if *update_last_seen > prev_last_seen {
|
for (txid, update_last_seen) in update.last_seen {
|
||||||
changeset.last_seen.insert(
|
let prev_last_seen = self.last_seen.get(&txid).copied();
|
||||||
txid,
|
if Some(update_last_seen) > prev_last_seen {
|
||||||
update_last_seen.expect("checked is greater, so we must have a last_seen"),
|
changeset.last_seen.insert(txid, update_last_seen);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -802,7 +792,7 @@ impl<A: Anchor> TxGraph<A> {
|
|||||||
chain_tip: BlockId,
|
chain_tip: BlockId,
|
||||||
txid: Txid,
|
txid: Txid,
|
||||||
) -> Result<Option<ChainPosition<&A>>, C::Error> {
|
) -> Result<Option<ChainPosition<&A>>, 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,
|
Some(v) => v,
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
};
|
};
|
||||||
@ -816,7 +806,7 @@ impl<A: Anchor> TxGraph<A> {
|
|||||||
|
|
||||||
// If no anchors are in best chain and we don't have a last_seen, we can return
|
// 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.
|
// 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,
|
Some(t) => *t,
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user