@@ -145,6 +145,7 @@ pub struct TxGraph<A = ConfirmationBlockTime> {
145145 spends : BTreeMap < OutPoint , HashSet < Txid > > ,
146146 anchors : HashMap < Txid , BTreeSet < A > > ,
147147 last_seen : HashMap < Txid , u64 > ,
148+ last_missing : HashMap < Txid , u64 > ,
148149
149150 txs_by_highest_conf_heights : BTreeSet < ( u32 , Txid ) > ,
150151 txs_by_last_seen : BTreeSet < ( u64 , Txid ) > ,
@@ -162,6 +163,7 @@ impl<A> Default for TxGraph<A> {
162163 spends : Default :: default ( ) ,
163164 anchors : Default :: default ( ) ,
164165 last_seen : Default :: default ( ) ,
166+ last_missing : Default :: default ( ) ,
165167 txs_by_highest_conf_heights : Default :: default ( ) ,
166168 txs_by_last_seen : Default :: default ( ) ,
167169 empty_outspends : Default :: default ( ) ,
@@ -715,6 +717,30 @@ impl<A: Anchor> TxGraph<A> {
715717 changeset
716718 }
717719
720+ /// Inserts the given `missing_at` for `txid`
721+ pub fn insert_missing_at ( & mut self , txid : Txid , missing_at : u64 ) -> ChangeSet < A > {
722+ let is_changed = match self . last_missing . entry ( txid) {
723+ hash_map:: Entry :: Occupied ( mut e) => {
724+ let last_missing = e. get_mut ( ) ;
725+ let change = * last_missing < missing_at;
726+ if change {
727+ * last_missing = missing_at;
728+ }
729+ change
730+ }
731+ hash_map:: Entry :: Vacant ( e) => {
732+ e. insert ( missing_at) ;
733+ true
734+ }
735+ } ;
736+
737+ let mut changeset = ChangeSet :: < A > :: default ( ) ;
738+ if is_changed {
739+ changeset. last_missing . insert ( txid, missing_at) ;
740+ }
741+ changeset
742+ }
743+
718744 /// Extends this graph with the given `update`.
719745 ///
720746 /// The returned [`ChangeSet`] is the set difference between `update` and `self` (transactions that
@@ -765,6 +791,14 @@ impl<A: Anchor> TxGraph<A> {
765791 changeset. merge ( self . insert_seen_at ( txid, seen_at) ) ;
766792 }
767793 }
794+ for txid in update. missing {
795+ // We want the `missing_at` value to override the `last_seen` value of the transaction.
796+ // If there is no `last_seen`, there is no need for the `missing_at` value since the
797+ // transaction will not be canonical anyway.
798+ if let Some ( & missing_at) = self . last_seen . get ( & txid) {
799+ changeset. merge ( self . insert_missing_at ( txid, missing_at) ) ;
800+ }
801+ }
768802 changeset
769803 }
770804
@@ -782,6 +816,7 @@ impl<A: Anchor> TxGraph<A> {
782816 . flat_map ( |( txid, anchors) | anchors. iter ( ) . map ( |a| ( a. clone ( ) , * txid) ) )
783817 . collect ( ) ,
784818 last_seen : self . last_seen . iter ( ) . map ( |( & k, & v) | ( k, v) ) . collect ( ) ,
819+ last_missing : self . last_missing . iter ( ) . map ( |( & k, & v) | ( k, v) ) . collect ( ) ,
785820 }
786821 }
787822
@@ -799,6 +834,9 @@ impl<A: Anchor> TxGraph<A> {
799834 for ( txid, seen_at) in changeset. last_seen {
800835 let _ = self . insert_seen_at ( txid, seen_at) ;
801836 }
837+ for ( txid, missing_at) in changeset. last_missing {
838+ let _ = self . insert_missing_at ( txid, missing_at) ;
839+ }
802840 }
803841}
804842
@@ -969,9 +1007,14 @@ impl<A: Anchor> TxGraph<A> {
9691007
9701008 /// List txids by descending last-seen order.
9711009 ///
972- /// Transactions without last-seens are excluded.
973- pub fn txids_by_descending_last_seen ( & self ) -> impl ExactSizeIterator < Item = ( u64 , Txid ) > + ' _ {
974- self . txs_by_last_seen . iter ( ) . copied ( ) . rev ( )
1010+ /// Transactions without last-seens are excluded. Transactions with a last-missing timestamp
1011+ /// equal or higher than it's last-seen timestamp are excluded.
1012+ pub fn txids_by_descending_last_seen ( & self ) -> impl Iterator < Item = ( u64 , Txid ) > + ' _ {
1013+ self . txs_by_last_seen
1014+ . iter ( )
1015+ . copied ( )
1016+ . rev ( )
1017+ . filter ( |( last_seen, txid) | !matches ! ( self . last_missing. get( txid) , Some ( last_missing) if last_missing >= last_seen) )
9751018 }
9761019
9771020 /// Returns a [`CanonicalIter`].
@@ -1139,6 +1182,8 @@ pub struct ChangeSet<A = ()> {
11391182 pub anchors : BTreeSet < ( A , Txid ) > ,
11401183 /// Added last-seen unix timestamps of transactions.
11411184 pub last_seen : BTreeMap < Txid , u64 > ,
1185+ /// Added timestamps of when a transaction is last missing from the mempool.
1186+ pub last_missing : BTreeMap < Txid , u64 > ,
11421187}
11431188
11441189impl < A > Default for ChangeSet < A > {
@@ -1148,6 +1193,7 @@ impl<A> Default for ChangeSet<A> {
11481193 txouts : Default :: default ( ) ,
11491194 anchors : Default :: default ( ) ,
11501195 last_seen : Default :: default ( ) ,
1196+ last_missing : Default :: default ( ) ,
11511197 }
11521198 }
11531199}
@@ -1202,13 +1248,22 @@ impl<A: Ord> Merge for ChangeSet<A> {
12021248 . filter ( |( txid, update_ls) | self . last_seen . get ( txid) < Some ( update_ls) )
12031249 . collect :: < Vec < _ > > ( ) ,
12041250 ) ;
1251+ // last_missing timestamps should only increase
1252+ self . last_missing . extend (
1253+ other
1254+ . last_missing
1255+ . into_iter ( )
1256+ . filter ( |( txid, update_lm) | self . last_missing . get ( txid) < Some ( update_lm) )
1257+ . collect :: < Vec < _ > > ( ) ,
1258+ ) ;
12051259 }
12061260
12071261 fn is_empty ( & self ) -> bool {
12081262 self . txs . is_empty ( )
12091263 && self . txouts . is_empty ( )
12101264 && self . anchors . is_empty ( )
12111265 && self . last_seen . is_empty ( )
1266+ && self . last_missing . is_empty ( )
12121267 }
12131268}
12141269
@@ -1228,6 +1283,7 @@ impl<A: Ord> ChangeSet<A> {
12281283 self . anchors . into_iter ( ) . map ( |( a, txid) | ( f ( a) , txid) ) ,
12291284 ) ,
12301285 last_seen : self . last_seen ,
1286+ last_missing : self . last_missing ,
12311287 }
12321288 }
12331289}
0 commit comments