@@ -96,6 +96,16 @@ impl<A: Ord> Ord for ChainPosition<A> {
9696 fn cmp ( & self , other : & Self ) -> core:: cmp:: Ordering {
9797 use core:: cmp:: Ordering ;
9898
99+ /// Compares options where `None` is greater than `Some` (sorts last).
100+ fn cmp_none_last < T : Ord > ( t1 : & Option < T > , t2 : & Option < T > ) -> Ordering {
101+ match ( t1, t2) {
102+ ( None , None ) => Ordering :: Equal ,
103+ ( None , Some ( _) ) => Ordering :: Greater ,
104+ ( Some ( _) , None ) => Ordering :: Less ,
105+ ( Some ( t1) , Some ( t2) ) => t1. cmp ( t2) ,
106+ }
107+ }
108+
99109 match ( self , other) {
100110 // Both confirmed: compare by anchor first
101111 (
@@ -110,16 +120,8 @@ impl<A: Ord> Ord for ChainPosition<A> {
110120 ) => {
111121 // First compare anchors
112122 match a1. cmp ( a2) {
113- Ordering :: Equal => {
114- // Same anchor: transitive before direct (may be earlier)
115- match ( t1, t2) {
116- ( None , None ) => Ordering :: Equal ,
117- ( None , Some ( _) ) => Ordering :: Greater , // Direct comes after transitive
118- ( Some ( _) , None ) => Ordering :: Less , // Transitive comes before direct
119- // Both transitive: txid tiebreaker
120- ( Some ( tx1) , Some ( tx2) ) => tx1. cmp ( tx2) ,
121- }
122- }
123+ // Same anchor: transitive before direct, tiebreak with txid
124+ Ordering :: Equal => cmp_none_last ( t1, t2) ,
123125 other => other,
124126 }
125127 }
@@ -136,14 +138,10 @@ impl<A: Ord> Ord for ChainPosition<A> {
136138 } ,
137139 ) => {
138140 // Never-in-mempool (None, None) ordered last
139- match ( f1. or ( * l1) , f2. or ( * l2) ) {
140- ( None , None ) => Ordering :: Equal ,
141- ( None , Some ( _) ) => Ordering :: Greater , // Never-seen after seen
142- ( Some ( _) , None ) => Ordering :: Less , // Seen before never-seen
143- ( Some ( _) , Some ( _) ) => {
144- // Both seen: compare first_seen, then last_seen
145- f1. cmp ( f2) . then_with ( || l1. cmp ( l2) )
146- }
141+ // Compare by first_seen, tie-break with last_seen
142+ match cmp_none_last ( f1, f2) {
143+ Ordering :: Equal => cmp_none_last ( l1, l2) ,
144+ other => other,
147145 }
148146 }
149147
@@ -308,6 +306,10 @@ mod test {
308306 first_seen : Some ( 20 ) ,
309307 last_seen : Some ( 20 ) ,
310308 } ;
309+ let unconf_seen_early_and_late = ChainPosition :: < ConfirmationBlockTime > :: Unconfirmed {
310+ first_seen : Some ( 10 ) ,
311+ last_seen : Some ( 20 ) ,
312+ } ;
311313 let unconf_never_seen = ChainPosition :: < ConfirmationBlockTime > :: Unconfirmed {
312314 first_seen : None ,
313315 last_seen : None ,
@@ -335,11 +337,16 @@ mod test {
335337 "transitive confirmation comes before direct at same height"
336338 ) ;
337339
338- // Test ordering within unconfirmed: earlier first_seen comes first
340+ // Test ordering within unconfirmed: earlier first_seen comes first, tie_break with
341+ // last_seen
339342 assert ! (
340343 unconf_seen_early < unconf_seen_late,
341344 "earlier first_seen comes first"
342345 ) ;
346+ assert ! (
347+ unconf_seen_early < unconf_seen_early_and_late,
348+ "if first_seen is equal, tiebreak with last_seen"
349+ ) ;
343350
344351 // Test ordering: never seen in mempool comes last
345352 assert ! (
@@ -360,17 +367,19 @@ mod test {
360367 unconf_seen_early,
361368 conf_deep,
362369 conf_deep_transitive,
370+ unconf_seen_early_and_late,
363371 ] ;
364372 positions. sort ( ) ;
365373 assert_eq ! (
366374 positions,
367375 vec![
368- conf_deep_transitive, // Most confirmed (potentially)
369- conf_deep, // Deep confirmation
370- conf_shallow, // Shallow confirmation
371- unconf_seen_early, // Unconfirmed, seen early
372- unconf_seen_late, // Unconfirmed, seen late
373- unconf_never_seen, // Never in mempool
376+ conf_deep_transitive, // Most confirmed (potentially)
377+ conf_deep, // Deep confirmation
378+ conf_shallow, // Shallow confirmation
379+ unconf_seen_early, // Unconfirmed, seen early
380+ unconf_seen_early_and_late, // Unconfirmed, seen early and late
381+ unconf_seen_late, // Unconfirmed, seen late
382+ unconf_never_seen, // Never in mempool
374383 ]
375384 ) ;
376385 }
0 commit comments