Skip to content

Commit c3e960f

Browse files
evanlinjinoleonardolima
authored andcommitted
fix(chain): correct unconfirmed ChainPosition last_seen tiebreaker
1 parent be93147 commit c3e960f

1 file changed

Lines changed: 34 additions & 25 deletions

File tree

crates/chain/src/chain_data.rs

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)