Skip to content

Commit cbeb36c

Browse files
committed
lsps0: Fix LSPSDateTime::duration_since to saturate at zero on clock skew
Replace abs_diff with a saturating subtraction so that duration_since returns Duration::ZERO when the reference timestamp is in the apparent future (e.g. due to clock skew or monotonicity violations). Callers using the result as an age — prune_terminal_orders (LSPS1), prune_terminal_channels (LSPS2), and the stale-webhook and cooldown checks (LSPS5) — no longer risk spuriously large values triggering premature pruning or incorrect cooldown expiry. Two unit tests are added to document the contract.
1 parent f73b81a commit cbeb36c

1 file changed

Lines changed: 23 additions & 3 deletions

File tree

  • lightning-liquidity/src/lsps0

lightning-liquidity/src/lsps0/ser.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,14 @@ impl LSPSDateTime {
256256
now_seconds_since_epoch > datetime_seconds_since_epoch
257257
}
258258

259-
/// Returns the absolute difference between two datetimes as a `Duration`.
259+
/// Returns how long ago `other` occurred relative to `self`, saturating at zero.
260+
///
261+
/// Returns [`Duration::ZERO`] when `self <= other` (e.g. clock skew pushed `other` into
262+
/// the apparent future), so callers treating the result as an age never get a spuriously
263+
/// large value.
260264
pub fn duration_since(&self, other: &Self) -> Duration {
261-
let diff_secs = self.0.timestamp().abs_diff(other.0.timestamp());
262-
Duration::from_secs(diff_secs)
265+
let diff_secs = self.0.timestamp().saturating_sub(other.0.timestamp());
266+
Duration::from_secs(diff_secs.max(0) as u64)
263267
}
264268

265269
/// Returns the time in seconds since the unix epoch.
@@ -981,4 +985,20 @@ mod tests {
981985
let decoded_datetime: LSPSDateTime = Readable::read(&mut Cursor::new(buf)).unwrap();
982986
assert_eq!(expected_datetime, decoded_datetime);
983987
}
988+
989+
#[test]
990+
fn datetime_duration_since_normal() {
991+
let earlier = LSPSDateTime::from_str("2024-01-01T00:00:00Z").unwrap();
992+
let later = LSPSDateTime::from_str("2024-01-01T01:00:00Z").unwrap();
993+
assert_eq!(later.duration_since(&earlier), Duration::from_secs(3600));
994+
}
995+
996+
#[test]
997+
fn datetime_duration_since_clock_skew_saturates_to_zero() {
998+
// When `other` is in the apparent future relative to `self` (clock skew),
999+
// duration_since must return Duration::ZERO rather than an erroneously large value.
1000+
let earlier = LSPSDateTime::from_str("2024-01-01T00:00:00Z").unwrap();
1001+
let later = LSPSDateTime::from_str("2024-01-01T01:00:00Z").unwrap();
1002+
assert_eq!(earlier.duration_since(&later), Duration::ZERO);
1003+
}
9841004
}

0 commit comments

Comments
 (0)