From 189b070f626d9223271895473c04b31695ff3e35 Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 29 Jun 2023 00:00:00 +0000 Subject: [PATCH] Use `MonotonicTime` as `Instant` shifted by 10 years forward Such implementation allows `MonotonicTime` to go backward up to 10 years on all platforms. On some platforms (e.g. iOS) `Instant` is represented as `u64` of nanoseconds since the boot of the system. Obviously such implementation does not allow to go backward before the time of the boot. Co-authored-by: Andrei Co-authored-by: Jeffrey Czyz --- lightning/src/ln/outbound_payment.rs | 4 +-- lightning/src/routing/scoring.rs | 2 +- lightning/src/util/time.rs | 40 +++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 2ac24baa5..546dc6c5b 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -239,7 +239,7 @@ impl Retry { }, #[cfg(all(not(feature = "no-std"), not(test)))] (Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) => - *max_duration >= std::time::Instant::now().duration_since(*first_attempted_at), + *max_duration >= crate::util::time::MonotonicTime::now().duration_since(*first_attempted_at), #[cfg(all(not(feature = "no-std"), test))] (Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) => *max_duration >= SinceEpoch::now().duration_since(*first_attempted_at), @@ -274,7 +274,7 @@ pub(crate) struct PaymentAttemptsUsingTime { } #[cfg(not(any(feature = "no-std", test)))] -type ConfiguredTime = std::time::Instant; +type ConfiguredTime = crate::util::time::MonotonicTime; #[cfg(feature = "no-std")] type ConfiguredTime = crate::util::time::Eternity; #[cfg(all(not(feature = "no-std"), test))] diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index ee9c3d0c4..eca5ee605 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -325,7 +325,7 @@ impl ReadableArgs for FixedPenaltyScorer { } #[cfg(not(feature = "no-std"))] -type ConfiguredTime = std::time::Instant; +type ConfiguredTime = crate::util::time::MonotonicTime; #[cfg(feature = "no-std")] use crate::util::time::Eternity; #[cfg(feature = "no-std")] diff --git a/lightning/src/util/time.rs b/lightning/src/util/time.rs index f450dc2c3..0d969e747 100644 --- a/lightning/src/util/time.rs +++ b/lightning/src/util/time.rs @@ -58,10 +58,20 @@ impl Sub for Eternity { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg(not(feature = "no-std"))] +pub struct MonotonicTime(std::time::Instant); + +/// The amount of time to shift `Instant` forward to prevent overflow when subtracting a `Duration` +/// from `Instant::now` on some operating systems (e.g., iOS representing `Instance` as `u64`). +#[cfg(not(feature = "no-std"))] +const SHIFT: Duration = Duration::from_secs(10 * 365 * 24 * 60 * 60); // 10 years. + #[cfg(not(feature = "no-std"))] -impl Time for std::time::Instant { +impl Time for MonotonicTime { fn now() -> Self { - std::time::Instant::now() + let instant = std::time::Instant::now().checked_add(SHIFT).expect("Overflow on MonotonicTime instantiation"); + Self(instant) } fn duration_since(&self, earlier: Self) -> Duration { @@ -70,15 +80,26 @@ impl Time for std::time::Instant { // clocks" that go backwards in practice (likely relatively ancient kernels/etc). Thus, we // manually check for time going backwards here and return a duration of zero in that case. let now = Self::now(); - if now > earlier { now - earlier } else { Duration::from_secs(0) } + if now.0 > earlier.0 { now.0 - earlier.0 } else { Duration::from_secs(0) } } fn duration_since_epoch() -> Duration { use std::time::SystemTime; SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap() } + fn elapsed(&self) -> Duration { - std::time::Instant::elapsed(self) + Self::now().0 - self.0 + } +} + +#[cfg(not(feature = "no-std"))] +impl Sub for MonotonicTime { + type Output = Self; + + fn sub(self, other: Duration) -> Self { + let instant = self.0.checked_sub(other).expect("MonotonicTime is not supposed to go backward futher than 10 years"); + Self(instant) } } @@ -154,4 +175,15 @@ pub mod tests { assert_eq!(now.elapsed(), Duration::from_secs(0)); assert_eq!(later - elapsed, now); } + + #[test] + #[cfg(not(feature = "no-std"))] + fn monotonic_time_subtracts() { + let now = super::MonotonicTime::now(); + assert!(now.elapsed() < Duration::from_secs(10)); + + let ten_years = Duration::from_secs(10 * 365 * 24 * 60 * 60); + let past = now - ten_years; + assert!(past.elapsed() >= ten_years); + } } -- 2.39.5