Skip to content

Commit e955442

Browse files
committed
Seal scoring::Time and only use Instant or Eternity publicly
`scoring::Time` exists in part to make testing the passage of time in `Scorer` practical. To allow no-std users to provide a time source it was exposed as a trait as well. However, it seems somewhat unlikely that a no-std user is going to have a use for providing their own time source (otherwise they wouldn't be a no-std user), and likely they won't have a graph in memory either. `scoring::Time` as currently written is also exceptionally hard to write C bindings for - the C bindings trait mappings relies on the ability to construct trait implementations at runtime with function pointers (i.e. `dyn Trait`s). `scoring::Time`, on the other hand, is a supertrait of `core::ops::Sub` which requires a `sub` method which takes a type parameter and returns a type parameter. Both of which aren't practical in bindings, especially given the `Sub::Output` associated type is not bound by any trait bounds at all (implying we cannot simply map the `sub` function to return an opaque trait object). Thus, for simplicity, we here simply seal `scoring::Time` and make it effectively-private, ensuring the bindings don't need to bother with it.
1 parent 2b5e7b0 commit e955442

File tree

2 files changed

+84
-74
lines changed

2 files changed

+84
-74
lines changed

lightning/src/routing/scoring.rs

Lines changed: 82 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,8 @@
4646
//!
4747
//! # Note
4848
//!
49-
//! If persisting [`Scorer`], it must be restored using the same [`Time`] parameterization. Using a
50-
//! different type results in undefined behavior. Specifically, persisting when built with feature
51-
//! `no-std` and restoring without it, or vice versa, uses different types and thus is undefined.
49+
//! Persisting when built with feature `no-std` and restoring without it, or vice versa, uses
50+
//! different types and thus is undefined.
5251
//!
5352
//! [`find_route`]: crate::routing::router::find_route
5453
@@ -59,9 +58,10 @@ use util::ser::{Readable, Writeable, Writer};
5958

6059
use prelude::*;
6160
use core::cell::{RefCell, RefMut};
62-
use core::ops::{DerefMut, Sub};
61+
use core::ops::DerefMut;
6362
use core::time::Duration;
64-
use io::{self, Read}; use sync::{Mutex, MutexGuard};
63+
use io::{self, Read};
64+
use sync::{Mutex, MutexGuard};
6565

6666
/// We define Score ever-so-slightly differently based on whether we are being build for C bindings
6767
/// or not. For users, `LockableScore` must somehow be writeable to disk. For Rust users, this is
@@ -185,23 +185,25 @@ impl<'a, S: Writeable> Writeable for MutexGuard<'a, S> {
185185
/// See [module-level documentation] for usage.
186186
///
187187
/// [module-level documentation]: crate::routing::scoring
188-
pub type Scorer = ScorerUsingTime::<DefaultTime>;
189-
190-
/// Time used by [`Scorer`].
191188
#[cfg(not(feature = "no-std"))]
192-
pub type DefaultTime = std::time::Instant;
193-
194-
/// Time used by [`Scorer`].
189+
pub type Scorer = ScorerUsingTime::<std::time::Instant>;
195190
#[cfg(feature = "no-std")]
196-
pub type DefaultTime = Eternity;
191+
pub type Scorer = ScorerUsingTime::<time::Eternity>;
197192

198-
/// [`Score`] implementation parameterized by [`Time`].
193+
// Note that ideally we'd hide ScorerUsingTime from public view by sealing it as well, but rustdoc
194+
// doesn't handle this well - instead exposing a `Scorer` which has no trait implementation(s) or
195+
// methods at all.
196+
197+
/// [`Score`] implementation.
199198
///
200199
/// See [`Scorer`] for details.
201200
///
202201
/// # Note
203202
///
204-
/// Mixing [`Time`] types between serialization and deserialization results in undefined behavior.
203+
/// Mixing the `no-std` feature between serialization and deserialization results in undefined
204+
/// behavior.
205+
///
206+
/// (C-not exported) generally all users should use the [`Scorer`] type alias.
205207
pub struct ScorerUsingTime<T: Time> {
206208
params: ScoringParameters,
207209
// TODO: Remove entries of closed channels.
@@ -247,8 +249,8 @@ pub struct ScoringParameters {
247249
///
248250
/// # Note
249251
///
250-
/// When time is an [`Eternity`], as is default when enabling feature `no-std`, it will never
251-
/// elapse. Therefore, this penalty will never decay.
252+
/// When built with the `no-std` feature, time will never elapse. Therefore, this penalty will
253+
/// never decay.
252254
///
253255
/// [`failure_penalty_msat`]: Self::failure_penalty_msat
254256
pub failure_penalty_half_life: Duration,
@@ -273,20 +275,6 @@ struct ChannelFailure<T: Time> {
273275
last_failed: T,
274276
}
275277

276-
/// A measurement of time.
277-
pub trait Time: Sub<Duration, Output = Self> where Self: Sized {
278-
/// Returns an instance corresponding to the current moment.
279-
fn now() -> Self;
280-
281-
/// Returns the amount of time elapsed since `self` was created.
282-
fn elapsed(&self) -> Duration;
283-
284-
/// Returns the amount of time passed since the beginning of [`Time`].
285-
///
286-
/// Used during (de-)serialization.
287-
fn duration_since_epoch() -> Duration;
288-
}
289-
290278
impl<T: Time> ScorerUsingTime<T> {
291279
/// Creates a new scorer using the given scoring parameters.
292280
pub fn new(params: ScoringParameters) -> Self {
@@ -383,48 +371,6 @@ impl<T: Time> Score for ScorerUsingTime<T> {
383371
}
384372
}
385373

386-
#[cfg(not(feature = "no-std"))]
387-
impl Time for std::time::Instant {
388-
fn now() -> Self {
389-
std::time::Instant::now()
390-
}
391-
392-
fn duration_since_epoch() -> Duration {
393-
use std::time::SystemTime;
394-
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
395-
}
396-
397-
fn elapsed(&self) -> Duration {
398-
std::time::Instant::elapsed(self)
399-
}
400-
}
401-
402-
/// A state in which time has no meaning.
403-
#[derive(Debug, PartialEq, Eq)]
404-
pub struct Eternity;
405-
406-
impl Time for Eternity {
407-
fn now() -> Self {
408-
Self
409-
}
410-
411-
fn duration_since_epoch() -> Duration {
412-
Duration::from_secs(0)
413-
}
414-
415-
fn elapsed(&self) -> Duration {
416-
Duration::from_secs(0)
417-
}
418-
}
419-
420-
impl Sub<Duration> for Eternity {
421-
type Output = Self;
422-
423-
fn sub(self, _other: Duration) -> Self {
424-
self
425-
}
426-
}
427-
428374
impl<T: Time> Writeable for ScorerUsingTime<T> {
429375
#[inline]
430376
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
@@ -475,9 +421,72 @@ impl<T: Time> Readable for ChannelFailure<T> {
475421
}
476422
}
477423

424+
pub(crate) mod time {
425+
use core::ops::Sub;
426+
use core::time::Duration;
427+
/// A measurement of time.
428+
pub trait Time: Sub<Duration, Output = Self> where Self: Sized {
429+
/// Returns an instance corresponding to the current moment.
430+
fn now() -> Self;
431+
432+
/// Returns the amount of time elapsed since `self` was created.
433+
fn elapsed(&self) -> Duration;
434+
435+
/// Returns the amount of time passed since the beginning of [`Time`].
436+
///
437+
/// Used during (de-)serialization.
438+
fn duration_since_epoch() -> Duration;
439+
}
440+
441+
/// A state in which time has no meaning.
442+
#[derive(Debug, PartialEq, Eq)]
443+
pub struct Eternity;
444+
445+
#[cfg(not(feature = "no-std"))]
446+
impl Time for std::time::Instant {
447+
fn now() -> Self {
448+
std::time::Instant::now()
449+
}
450+
451+
fn duration_since_epoch() -> Duration {
452+
use std::time::SystemTime;
453+
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
454+
}
455+
456+
fn elapsed(&self) -> Duration {
457+
std::time::Instant::elapsed(self)
458+
}
459+
}
460+
461+
impl Time for Eternity {
462+
fn now() -> Self {
463+
Self
464+
}
465+
466+
fn duration_since_epoch() -> Duration {
467+
Duration::from_secs(0)
468+
}
469+
470+
fn elapsed(&self) -> Duration {
471+
Duration::from_secs(0)
472+
}
473+
}
474+
475+
impl Sub<Duration> for Eternity {
476+
type Output = Self;
477+
478+
fn sub(self, _other: Duration) -> Self {
479+
self
480+
}
481+
}
482+
}
483+
484+
pub(crate) use self::time::Time;
485+
478486
#[cfg(test)]
479487
mod tests {
480-
use super::{Eternity, ScoringParameters, ScorerUsingTime, Time};
488+
use super::{ScoringParameters, ScorerUsingTime, Time};
489+
use super::time::Eternity;
481490

482491
use routing::scoring::Score;
483492
use routing::network_graph::NodeId;

lightning/src/util/test_utils.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use ln::features::{ChannelFeatures, InitFeatures};
2121
use ln::msgs;
2222
use ln::msgs::OptionalField;
2323
use ln::script::ShutdownScript;
24-
use routing::scoring::{Eternity, ScorerUsingTime};
24+
use routing::scoring::ScorerUsingTime;
25+
use routing::scoring::time::Eternity;
2526
use util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
2627
use util::events;
2728
use util::logger::{Logger, Level, Record};

0 commit comments

Comments
 (0)