Skip to content

LSPS2: Add TimeProvider trait for expiry checks in no-std and std builds #3746

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lightning-liquidity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ categories = ["cryptography::cryptocurrencies"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = ["std"]
default = ["std", "time"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disabling SystemTIme::now without disabling all of std: couldn't this be realized by just passing in another time provider than the std one, without requiring this flag?

std = ["lightning/std"]
time = []
backtrace = ["dep:backtrace"]

[dependencies]
Expand Down
22 changes: 22 additions & 0 deletions lightning-liquidity/src/lsps0/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use alloc::string::String;

use core::fmt::{self, Display};
use core::str::FromStr;
use core::time::Duration;

use crate::lsps0::msgs::{
LSPS0ListProtocolsRequest, LSPS0Message, LSPS0Request, LSPS0Response,
Expand Down Expand Up @@ -784,3 +785,24 @@ pub(crate) mod u32_fee_rate {
Ok(FeeRate::from_sat_per_kwu(fee_rate_sat_kwu as u64))
}
}

/// Trait defining a time provider
///
/// This trait is used to provide the current time service operations and to convert between timestamps and durations.
pub trait TimeProvider {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused why this is re-added here, as we're already adding it (in a different place) in #3662. Maybe it would be good to put this PR in draft until #3662 has been merged, or rebase it on top of #3662, as changes there will need to be consequentially accounted for here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is extracting some of the code from LSPS5 PR. My idea was to get this PR merged and then rebase LSPS5 on top of it, that way we would lose some commits from the LSPS5 PR and make it a bit smaller (same idea with the solution to this issue #3459 (PR coming soon), where I'm extracting some of the code written in the LSPS5 PR and putting it in a new PR, that way making the LSPS5 PR smaller)

/// Get the current time as a duration since the Unix epoch.
fn duration_since_epoch(&self) -> Duration;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this name is sort of standard in LDK, but to me something like unix_time would have been better. Duration is already the type, and epoch doesn't specify which epoch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, exactly because you'd expect unix_time to be a SystemTime or u64, but not a Duration. Plus, homogeneity is an important API feature, so keeping this in-line with the rest of internal APIs is a big plus, IMO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to change it now. As you say, keeping it consistent is a good API feature. For me as a developer though, this isn't the most descriptive name.

}

/// Default time provider using the system clock.
#[derive(Clone, Debug)]
#[cfg(feature = "time")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I re-read the PR description, but was still thinking why isn't this just std gated?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for not mentioning this in the PR description (I’ll update it shortly). This change comes from a discussion in this PR, specifically this comment from tnull:

Actually, now that we went this way, let's not feature gate this behind std, but rather a new time feature. Context is the following: on WASM, you generally have access to std, but not entirely. For example, time-dependent behaviors like SystemTime::now would just panic at runtime. However, when previously feature-gating on std, we good feedback from some WASM users that would like to keep using the non-time std features.
TLDR: would be nice to allow users to disable the SystemTime::now default without disabling the entirety of std. So let's introduce a time feature, as we did in other crates (cf. lightning-transaction-sync).

@tnull tagging Elias for review and input.

Copy link
Contributor

@joostjager joostjager Apr 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if those users run with std and just don't inject the panic'ing default std time provider and instead supply their own, aren't they good with the time flag?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if those users run with std and just don't inject the panic'ing default std time provider and instead supply their own, aren't they good with the time flag?

Yes, but we still shouldn't expose a 'default' API that would panic if used? That said, given that it requires std, we should probably feature-gate this on all(feature = "std", feature = "time"), or have time enable std.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but we still shouldn't expose a 'default' API that would panic if used?

If some platforms have an incomplete implementation of the std feature, is it the responsibility of this library to protect against hitting the missing part via a feature flag?

I also wouldn't make it a 'default' API, but just require a time provider to be supplied. Overall it seems to me that a time flag may be unnecessary.

pub struct DefaultTimeProvider;

#[cfg(feature = "time")]
impl TimeProvider for DefaultTimeProvider {
fn duration_since_epoch(&self) -> Duration {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch")
}
}