Skip to content

Commit 6dd41b7

Browse files
committed
Prefactor: Introduce DateTime wrapper
This wrapper is more ergonomic to use in the local context and will be used as a serialization wrapper in following commits.
1 parent 71aab53 commit 6dd41b7

File tree

6 files changed

+75
-45
lines changed

6 files changed

+75
-45
lines changed

lightning-liquidity/src/lsps0/ser.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ use lightning::util::ser::WithoutLength;
2424

2525
use bitcoin::secp256k1::PublicKey;
2626

27-
use core::fmt;
27+
use core::fmt::{self, Display};
2828
use core::str::FromStr;
2929

30+
#[cfg(feature = "std")]
31+
use std::time::{SystemTime, UNIX_EPOCH};
32+
3033
use serde::de::{self, MapAccess, Visitor};
3134
use serde::ser::SerializeStruct;
3235
use serde::{Deserialize, Deserializer, Serialize};
@@ -186,6 +189,44 @@ impl wire::Type for RawLSPSMessage {
186189
#[serde(transparent)]
187190
pub struct LSPSRequestId(pub String);
188191

192+
/// A DateTime object repsenting datetimes as described in LSPS0 / bLIP-50.
193+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
194+
#[serde(transparent)]
195+
pub struct DateTime(chrono::DateTime<chrono::Utc>);
196+
197+
impl DateTime {
198+
/// Returns the DateTime as RFC3339 formatted string.
199+
pub fn to_rfc3339(&self) -> String {
200+
self.0.to_rfc3339()
201+
}
202+
203+
/// Returns if the given time is in the past.
204+
#[cfg(feature = "std")]
205+
pub fn is_past(&self) -> bool {
206+
let now_seconds_since_epoch = SystemTime::now()
207+
.duration_since(UNIX_EPOCH)
208+
.expect("system clock to be ahead of the unix epoch")
209+
.as_secs();
210+
let datetime_seconds_since_epoch =
211+
self.0.timestamp().try_into().expect("expiration to be ahead of unix epoch");
212+
now_seconds_since_epoch > datetime_seconds_since_epoch
213+
}
214+
}
215+
216+
impl FromStr for DateTime {
217+
type Err = ();
218+
fn from_str(s: &str) -> Result<Self, Self::Err> {
219+
let datetime = chrono::DateTime::parse_from_rfc3339(s).map_err(|_| ())?;
220+
Ok(Self(datetime.into()))
221+
}
222+
}
223+
224+
impl Display for DateTime {
225+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226+
write!(f, "{}", self.to_rfc3339())
227+
}
228+
}
229+
189230
/// An error returned in response to an JSON-RPC request.
190231
///
191232
/// Please refer to the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#error_object) for

lightning-liquidity/src/lsps1/msgs.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Message, request, and other primitive types used to implement bLIP-51 / LSPS1.
22
33
use crate::lsps0::ser::{
4-
string_amount, u32_fee_rate, unchecked_address, unchecked_address_option, LSPSMessage,
5-
LSPSRequestId, LSPSResponseError,
4+
string_amount, u32_fee_rate, unchecked_address, unchecked_address_option, DateTime,
5+
LSPSMessage, LSPSRequestId, LSPSResponseError,
66
};
77

88
use crate::prelude::String;
@@ -13,8 +13,6 @@ use lightning_invoice::Bolt11Invoice;
1313

1414
use serde::{Deserialize, Serialize};
1515

16-
use chrono::Utc;
17-
1816
use core::convert::TryFrom;
1917

2018
pub(crate) const LSPS1_GET_INFO_METHOD_NAME: &str = "lsps1.get_info";
@@ -127,7 +125,7 @@ pub struct LSPS1CreateOrderResponse {
127125
#[serde(flatten)]
128126
pub order: LSPS1OrderParams,
129127
/// The datetime when the order was created
130-
pub created_at: chrono::DateTime<Utc>,
128+
pub created_at: DateTime,
131129
/// The current status of the order.
132130
pub order_status: LSPS1OrderStatus,
133131
/// Contains details about how to pay for the order.
@@ -163,7 +161,7 @@ pub struct LSPS1Bolt11PaymentInfo {
163161
/// Indicates the current state of the payment.
164162
pub state: LSPS1PaymentState,
165163
/// The datetime when the payment option expires.
166-
pub expires_at: chrono::DateTime<Utc>,
164+
pub expires_at: DateTime,
167165
/// The total fee the LSP will charge to open this channel in satoshi.
168166
#[serde(with = "string_amount")]
169167
pub fee_total_sat: u64,
@@ -180,7 +178,7 @@ pub struct LSPS1OnchainPaymentInfo {
180178
/// Indicates the current state of the payment.
181179
pub state: LSPS1PaymentState,
182180
/// The datetime when the payment option expires.
183-
pub expires_at: chrono::DateTime<Utc>,
181+
pub expires_at: DateTime,
184182
/// The total fee the LSP will charge to open this channel in satoshi.
185183
#[serde(with = "string_amount")]
186184
pub fee_total_sat: u64,
@@ -237,11 +235,11 @@ pub struct LSPS1OnchainPayment {
237235
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
238236
pub struct LSPS1ChannelInfo {
239237
/// The datetime when the funding transaction has been published.
240-
pub funded_at: chrono::DateTime<Utc>,
238+
pub funded_at: DateTime,
241239
/// The outpoint of the funding transaction.
242240
pub funding_outpoint: OutPoint,
243241
/// The earliest datetime when the channel may be closed by the LSP.
244-
pub expires_at: chrono::DateTime<Utc>,
242+
pub expires_at: DateTime,
245243
}
246244

247245
/// A request made to an LSP to retrieve information about an previously made order.

lightning-liquidity/src/lsps2/msgs.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ use core::convert::TryFrom;
55
use bitcoin::hashes::hmac::{Hmac, HmacEngine};
66
use bitcoin::hashes::sha256::Hash as Sha256;
77
use bitcoin::hashes::{Hash, HashEngine};
8-
use chrono::Utc;
98
use serde::{Deserialize, Serialize};
109

1110
use lightning::util::scid_utils;
1211

1312
use crate::lsps0::ser::{
14-
string_amount, string_amount_option, LSPSMessage, LSPSRequestId, LSPSResponseError,
13+
string_amount, string_amount_option, DateTime, LSPSMessage, LSPSRequestId, LSPSResponseError,
1514
};
1615
use crate::prelude::{String, Vec};
1716
use crate::utils;
@@ -42,7 +41,7 @@ pub struct LSPS2RawOpeningFeeParams {
4241
/// A fee proportional to the size of the initial payment.
4342
pub proportional: u32,
4443
/// An [`ISO8601`](https://www.iso.org/iso-8601-date-and-time-format.html) formatted date for which these params are valid.
45-
pub valid_until: chrono::DateTime<Utc>,
44+
pub valid_until: DateTime,
4645
/// The number of blocks after confirmation that the LSP promises it will keep the channel alive without closing.
4746
pub min_lifetime: u32,
4847
/// The maximum number of blocks that the client is allowed to set its `to_self_delay` parameter.
@@ -93,7 +92,7 @@ pub struct LSPS2OpeningFeeParams {
9392
/// A fee proportional to the size of the initial payment.
9493
pub proportional: u32,
9594
/// An [`ISO8601`](https://www.iso.org/iso-8601-date-and-time-format.html) formatted date for which these params are valid.
96-
pub valid_until: chrono::DateTime<Utc>,
95+
pub valid_until: DateTime,
9796
/// The number of blocks after confirmation that the LSP promises it will keep the channel alive without closing.
9897
pub min_lifetime: u32,
9998
/// The maximum number of blocks that the client is allowed to set its `to_self_delay` parameter.
@@ -214,15 +213,17 @@ impl From<LSPS2Message> for LSPSMessage {
214213
#[cfg(test)]
215214
mod tests {
216215
use super::*;
216+
217217
use crate::alloc::string::ToString;
218218
use crate::lsps2::utils::is_valid_opening_fee_params;
219219

220+
use core::str::FromStr;
221+
220222
#[test]
221223
fn into_opening_fee_params_produces_valid_promise() {
222224
let min_fee_msat = 100;
223225
let proportional = 21;
224-
let valid_until: chrono::DateTime<Utc> =
225-
chrono::DateTime::parse_from_rfc3339("2035-05-20T08:30:45Z").unwrap().into();
226+
let valid_until = DateTime::from_str("2035-05-20T08:30:45Z").unwrap();
226227
let min_lifetime = 144;
227228
let max_client_to_self_delay = 128;
228229
let min_payment_size_msat = 1;
@@ -257,7 +258,7 @@ mod tests {
257258
fn changing_single_field_produced_invalid_params() {
258259
let min_fee_msat = 100;
259260
let proportional = 21;
260-
let valid_until = chrono::DateTime::parse_from_rfc3339("2035-05-20T08:30:45Z").unwrap();
261+
let valid_until = DateTime::from_str("2035-05-20T08:30:45Z").unwrap();
261262
let min_lifetime = 144;
262263
let max_client_to_self_delay = 128;
263264
let min_payment_size_msat = 1;
@@ -266,7 +267,7 @@ mod tests {
266267
let raw = LSPS2RawOpeningFeeParams {
267268
min_fee_msat,
268269
proportional,
269-
valid_until: valid_until.into(),
270+
valid_until,
270271
min_lifetime,
271272
max_client_to_self_delay,
272273
min_payment_size_msat,
@@ -284,7 +285,7 @@ mod tests {
284285
fn wrong_secret_produced_invalid_params() {
285286
let min_fee_msat = 100;
286287
let proportional = 21;
287-
let valid_until = chrono::DateTime::parse_from_rfc3339("2035-05-20T08:30:45Z").unwrap();
288+
let valid_until = DateTime::from_str("2035-05-20T08:30:45Z").unwrap();
288289
let min_lifetime = 144;
289290
let max_client_to_self_delay = 128;
290291
let min_payment_size_msat = 1;
@@ -293,7 +294,7 @@ mod tests {
293294
let raw = LSPS2RawOpeningFeeParams {
294295
min_fee_msat,
295296
proportional,
296-
valid_until: valid_until.into(),
297+
valid_until,
297298
min_lifetime,
298299
max_client_to_self_delay,
299300
min_payment_size_msat,
@@ -313,7 +314,7 @@ mod tests {
313314
fn expired_params_produces_invalid_params() {
314315
let min_fee_msat = 100;
315316
let proportional = 21;
316-
let valid_until = chrono::DateTime::parse_from_rfc3339("2023-05-20T08:30:45Z").unwrap();
317+
let valid_until = DateTime::from_str("2023-05-20T08:30:45Z").unwrap();
317318
let min_lifetime = 144;
318319
let max_client_to_self_delay = 128;
319320
let min_payment_size_msat = 1;
@@ -322,7 +323,7 @@ mod tests {
322323
let raw = LSPS2RawOpeningFeeParams {
323324
min_fee_msat,
324325
proportional,
325-
valid_until: valid_until.into(),
326+
valid_until,
326327
min_lifetime,
327328
max_client_to_self_delay,
328329
min_payment_size_msat,
@@ -339,7 +340,7 @@ mod tests {
339340
fn buy_request_serialization() {
340341
let min_fee_msat = 100;
341342
let proportional = 21;
342-
let valid_until = chrono::DateTime::parse_from_rfc3339("2023-05-20T08:30:45Z").unwrap();
343+
let valid_until = DateTime::from_str("2023-05-20T08:30:45Z").unwrap();
343344
let min_lifetime = 144;
344345
let max_client_to_self_delay = 128;
345346
let min_payment_size_msat = 1;
@@ -348,7 +349,7 @@ mod tests {
348349
let raw = LSPS2RawOpeningFeeParams {
349350
min_fee_msat,
350351
proportional,
351-
valid_until: valid_until.into(),
352+
valid_until,
352353
min_lifetime,
353354
max_client_to_self_delay,
354355
min_payment_size_msat,

lightning-liquidity/src/lsps2/service.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,12 +1419,14 @@ fn calculate_amount_to_forward_per_htlc(
14191419

14201420
#[cfg(test)]
14211421
mod tests {
1422-
14231422
use super::*;
1424-
use chrono::TimeZone;
1425-
use chrono::Utc;
1423+
1424+
use crate::lsps0::ser::DateTime;
1425+
14261426
use proptest::prelude::*;
14271427

1428+
use core::str::FromStr;
1429+
14281430
const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000;
14291431

14301432
fn arb_forward_amounts() -> impl Strategy<Value = (u64, u64, u64, u64)> {
@@ -1518,7 +1520,7 @@ mod tests {
15181520
let opening_fee_params = LSPS2OpeningFeeParams {
15191521
min_fee_msat: 10_000_000,
15201522
proportional: 10_000,
1521-
valid_until: Utc.timestamp_opt(3000, 0).unwrap(),
1523+
valid_until: DateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
15221524
min_lifetime: 4032,
15231525
max_client_to_self_delay: 2016,
15241526
min_payment_size_msat: 10_000_000,
@@ -1710,7 +1712,7 @@ mod tests {
17101712
let opening_fee_params = LSPS2OpeningFeeParams {
17111713
min_fee_msat: 10_000_000,
17121714
proportional: 10_000,
1713-
valid_until: Utc.timestamp_opt(3000, 0).unwrap(),
1715+
valid_until: DateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
17141716
min_lifetime: 4032,
17151717
max_client_to_self_delay: 2016,
17161718
min_payment_size_msat: 10_000_000,

lightning-liquidity/src/lsps2/utils.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine};
77
use bitcoin::hashes::sha256::Hash as Sha256;
88
use bitcoin::hashes::{Hash, HashEngine};
99

10-
#[cfg(feature = "std")]
11-
use std::time::{SystemTime, UNIX_EPOCH};
12-
1310
/// Determines if the given parameters are valid given the secret used to generate the promise.
1411
pub fn is_valid_opening_fee_params(
1512
fee_params: &LSPS2OpeningFeeParams, promise_secret: &[u8; 32],
@@ -35,16 +32,7 @@ pub fn is_valid_opening_fee_params(
3532
pub fn is_expired_opening_fee_params(fee_params: &LSPS2OpeningFeeParams) -> bool {
3633
#[cfg(feature = "std")]
3734
{
38-
let seconds_since_epoch = SystemTime::now()
39-
.duration_since(UNIX_EPOCH)
40-
.expect("system clock to be ahead of the unix epoch")
41-
.as_secs();
42-
let valid_until_seconds_since_epoch = fee_params
43-
.valid_until
44-
.timestamp()
45-
.try_into()
46-
.expect("expiration to be ahead of unix epoch");
47-
seconds_since_epoch > valid_until_seconds_since_epoch
35+
fee_params.valid_until.is_past()
4836
}
4937
#[cfg(not(feature = "std"))]
5038
{

lightning-liquidity/tests/lsps2_integration_tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod common;
55
use common::{create_service_and_client_nodes, get_lsps_message, Node};
66

77
use lightning_liquidity::events::LiquidityEvent;
8+
use lightning_liquidity::lsps0::ser::DateTime;
89
use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
910
use lightning_liquidity::lsps2::event::{LSPS2ClientEvent, LSPS2ServiceEvent};
1011
use lightning_liquidity::lsps2::msgs::LSPS2RawOpeningFeeParams;
@@ -24,8 +25,7 @@ use bitcoin::hashes::{sha256, Hash};
2425
use bitcoin::secp256k1::{PublicKey, Secp256k1};
2526
use bitcoin::Network;
2627

27-
use chrono::DateTime;
28-
28+
use std::str::FromStr;
2929
use std::time::Duration;
3030

3131
fn create_jit_invoice(
@@ -128,7 +128,7 @@ fn invoice_generation_flow() {
128128
let raw_opening_params = LSPS2RawOpeningFeeParams {
129129
min_fee_msat: 100,
130130
proportional: 21,
131-
valid_until: DateTime::parse_from_rfc3339("2035-05-20T08:30:45Z").unwrap().into(),
131+
valid_until: DateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
132132
min_lifetime: 144,
133133
max_client_to_self_delay: 128,
134134
min_payment_size_msat: 1,

0 commit comments

Comments
 (0)