Skip to content

Commit 6c9cc1f

Browse files
committed
test(dash-spv): fix Windows Instant underflow in rebroadcast test
Project `now` forward via a private `rebroadcast_if_due_at` helper instead of subtracting `REBROADCAST_INTERVAL` from `Instant::now()`. On Windows, `Instant` is backed by `QueryPerformanceCounter` measured from boot, so on a freshly provisioned runner with uptime below the interval the subtraction underflows and panics.
1 parent 821c4f8 commit 6c9cc1f

1 file changed

Lines changed: 17 additions & 9 deletions

File tree

dash-spv/src/sync/mempool/manager.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -446,14 +446,21 @@ impl<W: WalletInterface> MempoolManager<W> {
446446
/// Transactions whose last broadcast was more than `REBROADCAST_INTERVAL`
447447
/// ago are rebroadcast and their timestamp is reset.
448448
pub(super) async fn rebroadcast_if_due(&mut self, requests: &RequestSender) {
449+
self.rebroadcast_if_due_at(requests, Instant::now()).await
450+
}
451+
452+
/// `now`-injected variant of [`Self::rebroadcast_if_due`]. Tests project `now`
453+
/// forward instead of subtracting from `Instant::now()`, which underflows on
454+
/// Windows when the QPC-based monotonic clock has a small value at boot.
455+
async fn rebroadcast_if_due_at(&mut self, requests: &RequestSender, now: Instant) {
449456
let mut due: Vec<Transaction> = Vec::new();
450457
for (txid, last_broadcast) in &mut self.recent_sends {
451-
if last_broadcast.elapsed() < REBROADCAST_INTERVAL {
458+
if now.saturating_duration_since(*last_broadcast) < REBROADCAST_INTERVAL {
452459
continue;
453460
}
454461
if let Some(unconfirmed) = self.transactions.get(txid) {
455462
due.push(unconfirmed.transaction.clone());
456-
*last_broadcast = Instant::now();
463+
*last_broadcast = now;
457464
}
458465
}
459466

@@ -1646,16 +1653,16 @@ mod tests {
16461653
};
16471654
let txid = tx.txid();
16481655

1649-
// Add a transaction and mark its last broadcast as older than the interval
1656+
let t0 = Instant::now();
1657+
let later = t0 + REBROADCAST_INTERVAL + Duration::from_secs(1);
1658+
16501659
manager.transactions.insert(
16511660
txid,
16521661
UnconfirmedTransaction::new(tx, Amount::from_sat(0), false, true, Vec::new(), -100_000),
16531662
);
1654-
manager
1655-
.recent_sends
1656-
.insert(txid, Instant::now() - REBROADCAST_INTERVAL - Duration::from_secs(1));
1663+
manager.recent_sends.insert(txid, t0);
16571664

1658-
manager.rebroadcast_if_due(&requests).await;
1665+
manager.rebroadcast_if_due_at(&requests, later).await;
16591666

16601667
// Should have sent a BroadcastMessage for the transaction
16611668
let msg = rx.try_recv().expect("expected a rebroadcast message");
@@ -1665,8 +1672,9 @@ mod tests {
16651672
msg
16661673
);
16671674

1668-
// Timestamp should be reset, so a second call should not rebroadcast
1669-
manager.rebroadcast_if_due(&requests).await;
1675+
// Timestamp should be reset to `later`, so a second call at the same instant
1676+
// must not rebroadcast.
1677+
manager.rebroadcast_if_due_at(&requests, later).await;
16701678
assert!(rx.try_recv().is_err(), "should not rebroadcast immediately after reset");
16711679
}
16721680

0 commit comments

Comments
 (0)