mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-22 06:31:57 +01:00
Introduce LSPSDateTime
wrapper
This wrapper is more ergonomic to use in the local context and will be used as a serialization wrapper in following commits.
This commit is contained in:
parent
8526b9fca3
commit
690fcb1545
7 changed files with 83 additions and 50 deletions
|
@ -24,9 +24,12 @@ use lightning::util::ser::WithoutLength;
|
|||
|
||||
use bitcoin::secp256k1::PublicKey;
|
||||
|
||||
use core::fmt;
|
||||
use core::fmt::{self, Display};
|
||||
use core::str::FromStr;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use serde::de::{self, MapAccess, Visitor};
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
@ -186,6 +189,44 @@ impl wire::Type for RawLSPSMessage {
|
|||
#[serde(transparent)]
|
||||
pub struct LSPSRequestId(pub String);
|
||||
|
||||
/// An object representing datetimes as described in bLIP-50 / LSPS0.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct LSPSDateTime(chrono::DateTime<chrono::Utc>);
|
||||
|
||||
impl LSPSDateTime {
|
||||
/// Returns the LSPSDateTime as RFC3339 formatted string.
|
||||
pub fn to_rfc3339(&self) -> String {
|
||||
self.0.to_rfc3339()
|
||||
}
|
||||
|
||||
/// Returns if the given time is in the past.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn is_past(&self) -> bool {
|
||||
let now_seconds_since_epoch = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("system clock to be ahead of the unix epoch")
|
||||
.as_secs();
|
||||
let datetime_seconds_since_epoch =
|
||||
self.0.timestamp().try_into().expect("expiration to be ahead of unix epoch");
|
||||
now_seconds_since_epoch > datetime_seconds_since_epoch
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for LSPSDateTime {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let datetime = chrono::DateTime::parse_from_rfc3339(s).map_err(|_| ())?;
|
||||
Ok(Self(datetime.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LSPSDateTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_rfc3339())
|
||||
}
|
||||
}
|
||||
|
||||
/// An error returned in response to an JSON-RPC request.
|
||||
///
|
||||
/// Please refer to the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification#error_object) for
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//! Message, request, and other primitive types used to implement bLIP-51 / LSPS1.
|
||||
|
||||
use crate::lsps0::ser::{
|
||||
string_amount, u32_fee_rate, unchecked_address, unchecked_address_option, LSPSMessage,
|
||||
LSPSRequestId, LSPSResponseError,
|
||||
string_amount, u32_fee_rate, unchecked_address, unchecked_address_option, LSPSDateTime,
|
||||
LSPSMessage, LSPSRequestId, LSPSResponseError,
|
||||
};
|
||||
|
||||
use crate::prelude::String;
|
||||
|
@ -13,8 +13,6 @@ use lightning_invoice::Bolt11Invoice;
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use chrono::Utc;
|
||||
|
||||
use core::convert::TryFrom;
|
||||
|
||||
pub(crate) const LSPS1_GET_INFO_METHOD_NAME: &str = "lsps1.get_info";
|
||||
|
@ -127,7 +125,7 @@ pub struct LSPS1CreateOrderResponse {
|
|||
#[serde(flatten)]
|
||||
pub order: LSPS1OrderParams,
|
||||
/// The datetime when the order was created
|
||||
pub created_at: chrono::DateTime<Utc>,
|
||||
pub created_at: LSPSDateTime,
|
||||
/// The current state of the order.
|
||||
pub order_state: LSPS1OrderState,
|
||||
/// Contains details about how to pay for the order.
|
||||
|
@ -163,7 +161,7 @@ pub struct LSPS1Bolt11PaymentInfo {
|
|||
/// Indicates the current state of the payment.
|
||||
pub state: LSPS1PaymentState,
|
||||
/// The datetime when the payment option expires.
|
||||
pub expires_at: chrono::DateTime<Utc>,
|
||||
pub expires_at: LSPSDateTime,
|
||||
/// The total fee the LSP will charge to open this channel in satoshi.
|
||||
#[serde(with = "string_amount")]
|
||||
pub fee_total_sat: u64,
|
||||
|
@ -180,7 +178,7 @@ pub struct LSPS1OnchainPaymentInfo {
|
|||
/// Indicates the current state of the payment.
|
||||
pub state: LSPS1PaymentState,
|
||||
/// The datetime when the payment option expires.
|
||||
pub expires_at: chrono::DateTime<Utc>,
|
||||
pub expires_at: LSPSDateTime,
|
||||
/// The total fee the LSP will charge to open this channel in satoshi.
|
||||
#[serde(with = "string_amount")]
|
||||
pub fee_total_sat: u64,
|
||||
|
@ -237,11 +235,11 @@ pub struct LSPS1OnchainPayment {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct LSPS1ChannelInfo {
|
||||
/// The datetime when the funding transaction has been published.
|
||||
pub funded_at: chrono::DateTime<Utc>,
|
||||
pub funded_at: LSPSDateTime,
|
||||
/// The outpoint of the funding transaction.
|
||||
pub funding_outpoint: OutPoint,
|
||||
/// The earliest datetime when the channel may be closed by the LSP.
|
||||
pub expires_at: chrono::DateTime<Utc>,
|
||||
pub expires_at: LSPSDateTime,
|
||||
}
|
||||
|
||||
/// A request made to an LSP to retrieve information about an previously made order.
|
||||
|
|
|
@ -19,7 +19,9 @@ use super::msgs::{
|
|||
use crate::message_queue::MessageQueue;
|
||||
|
||||
use crate::events::EventQueue;
|
||||
use crate::lsps0::ser::{LSPSProtocolMessageHandler, LSPSRequestId, LSPSResponseError};
|
||||
use crate::lsps0::ser::{
|
||||
LSPSDateTime, LSPSProtocolMessageHandler, LSPSRequestId, LSPSResponseError,
|
||||
};
|
||||
use crate::prelude::{new_hash_map, HashMap, String};
|
||||
use crate::sync::{Arc, Mutex, RwLock};
|
||||
use crate::utils;
|
||||
|
@ -73,7 +75,7 @@ impl OutboundRequestState {
|
|||
|
||||
struct OutboundLSPS1Config {
|
||||
order: LSPS1OrderParams,
|
||||
created_at: chrono::DateTime<Utc>,
|
||||
created_at: LSPSDateTime,
|
||||
payment: LSPS1PaymentInfo,
|
||||
}
|
||||
|
||||
|
@ -84,7 +86,7 @@ struct OutboundCRChannel {
|
|||
|
||||
impl OutboundCRChannel {
|
||||
fn new(
|
||||
order: LSPS1OrderParams, created_at: chrono::DateTime<Utc>, order_id: LSPS1OrderId,
|
||||
order: LSPS1OrderParams, created_at: LSPSDateTime, order_id: LSPS1OrderId,
|
||||
payment: LSPS1PaymentInfo,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -237,7 +239,7 @@ where
|
|||
/// [`LSPS1ServiceEvent::RequestForPaymentDetails`]: crate::lsps1::event::LSPS1ServiceEvent::RequestForPaymentDetails
|
||||
pub fn send_payment_details(
|
||||
&self, request_id: LSPSRequestId, counterparty_node_id: &PublicKey,
|
||||
payment: LSPS1PaymentInfo, created_at: chrono::DateTime<Utc>,
|
||||
payment: LSPS1PaymentInfo, created_at: LSPSDateTime,
|
||||
) -> Result<(), APIError> {
|
||||
let (result, response) = {
|
||||
let outer_state_lock = self.per_peer_state.read().unwrap();
|
||||
|
@ -380,7 +382,7 @@ where
|
|||
order_id,
|
||||
order: config.order.clone(),
|
||||
order_state,
|
||||
created_at: config.created_at,
|
||||
created_at: config.created_at.clone(),
|
||||
payment: config.payment.clone(),
|
||||
channel,
|
||||
});
|
||||
|
|
|
@ -5,13 +5,13 @@ use core::convert::TryFrom;
|
|||
use bitcoin::hashes::hmac::{Hmac, HmacEngine};
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::{Hash, HashEngine};
|
||||
use chrono::Utc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use lightning::util::scid_utils;
|
||||
|
||||
use crate::lsps0::ser::{
|
||||
string_amount, string_amount_option, LSPSMessage, LSPSRequestId, LSPSResponseError,
|
||||
string_amount, string_amount_option, LSPSDateTime, LSPSMessage, LSPSRequestId,
|
||||
LSPSResponseError,
|
||||
};
|
||||
use crate::prelude::{String, Vec};
|
||||
use crate::utils;
|
||||
|
@ -42,7 +42,7 @@ pub struct LSPS2RawOpeningFeeParams {
|
|||
/// A fee proportional to the size of the initial payment.
|
||||
pub proportional: u32,
|
||||
/// An [`ISO8601`](https://www.iso.org/iso-8601-date-and-time-format.html) formatted date for which these params are valid.
|
||||
pub valid_until: chrono::DateTime<Utc>,
|
||||
pub valid_until: LSPSDateTime,
|
||||
/// The number of blocks after confirmation that the LSP promises it will keep the channel alive without closing.
|
||||
pub min_lifetime: u32,
|
||||
/// The maximum number of blocks that the client is allowed to set its `to_self_delay` parameter.
|
||||
|
@ -93,7 +93,7 @@ pub struct LSPS2OpeningFeeParams {
|
|||
/// A fee proportional to the size of the initial payment.
|
||||
pub proportional: u32,
|
||||
/// An [`ISO8601`](https://www.iso.org/iso-8601-date-and-time-format.html) formatted date for which these params are valid.
|
||||
pub valid_until: chrono::DateTime<Utc>,
|
||||
pub valid_until: LSPSDateTime,
|
||||
/// The number of blocks after confirmation that the LSP promises it will keep the channel alive without closing.
|
||||
pub min_lifetime: u32,
|
||||
/// The maximum number of blocks that the client is allowed to set its `to_self_delay` parameter.
|
||||
|
@ -214,15 +214,17 @@ impl From<LSPS2Message> for LSPSMessage {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::alloc::string::ToString;
|
||||
use crate::lsps2::utils::is_valid_opening_fee_params;
|
||||
|
||||
use core::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn into_opening_fee_params_produces_valid_promise() {
|
||||
let min_fee_msat = 100;
|
||||
let proportional = 21;
|
||||
let valid_until: chrono::DateTime<Utc> =
|
||||
chrono::DateTime::parse_from_rfc3339("2035-05-20T08:30:45Z").unwrap().into();
|
||||
let valid_until = LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap();
|
||||
let min_lifetime = 144;
|
||||
let max_client_to_self_delay = 128;
|
||||
let min_payment_size_msat = 1;
|
||||
|
@ -257,7 +259,7 @@ mod tests {
|
|||
fn changing_single_field_produced_invalid_params() {
|
||||
let min_fee_msat = 100;
|
||||
let proportional = 21;
|
||||
let valid_until = chrono::DateTime::parse_from_rfc3339("2035-05-20T08:30:45Z").unwrap();
|
||||
let valid_until = LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap();
|
||||
let min_lifetime = 144;
|
||||
let max_client_to_self_delay = 128;
|
||||
let min_payment_size_msat = 1;
|
||||
|
@ -266,7 +268,7 @@ mod tests {
|
|||
let raw = LSPS2RawOpeningFeeParams {
|
||||
min_fee_msat,
|
||||
proportional,
|
||||
valid_until: valid_until.into(),
|
||||
valid_until,
|
||||
min_lifetime,
|
||||
max_client_to_self_delay,
|
||||
min_payment_size_msat,
|
||||
|
@ -284,7 +286,7 @@ mod tests {
|
|||
fn wrong_secret_produced_invalid_params() {
|
||||
let min_fee_msat = 100;
|
||||
let proportional = 21;
|
||||
let valid_until = chrono::DateTime::parse_from_rfc3339("2035-05-20T08:30:45Z").unwrap();
|
||||
let valid_until = LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap();
|
||||
let min_lifetime = 144;
|
||||
let max_client_to_self_delay = 128;
|
||||
let min_payment_size_msat = 1;
|
||||
|
@ -293,7 +295,7 @@ mod tests {
|
|||
let raw = LSPS2RawOpeningFeeParams {
|
||||
min_fee_msat,
|
||||
proportional,
|
||||
valid_until: valid_until.into(),
|
||||
valid_until,
|
||||
min_lifetime,
|
||||
max_client_to_self_delay,
|
||||
min_payment_size_msat,
|
||||
|
@ -313,7 +315,7 @@ mod tests {
|
|||
fn expired_params_produces_invalid_params() {
|
||||
let min_fee_msat = 100;
|
||||
let proportional = 21;
|
||||
let valid_until = chrono::DateTime::parse_from_rfc3339("2023-05-20T08:30:45Z").unwrap();
|
||||
let valid_until = LSPSDateTime::from_str("2023-05-20T08:30:45Z").unwrap();
|
||||
let min_lifetime = 144;
|
||||
let max_client_to_self_delay = 128;
|
||||
let min_payment_size_msat = 1;
|
||||
|
@ -322,7 +324,7 @@ mod tests {
|
|||
let raw = LSPS2RawOpeningFeeParams {
|
||||
min_fee_msat,
|
||||
proportional,
|
||||
valid_until: valid_until.into(),
|
||||
valid_until,
|
||||
min_lifetime,
|
||||
max_client_to_self_delay,
|
||||
min_payment_size_msat,
|
||||
|
@ -339,7 +341,7 @@ mod tests {
|
|||
fn buy_request_serialization() {
|
||||
let min_fee_msat = 100;
|
||||
let proportional = 21;
|
||||
let valid_until = chrono::DateTime::parse_from_rfc3339("2023-05-20T08:30:45Z").unwrap();
|
||||
let valid_until = LSPSDateTime::from_str("2023-05-20T08:30:45Z").unwrap();
|
||||
let min_lifetime = 144;
|
||||
let max_client_to_self_delay = 128;
|
||||
let min_payment_size_msat = 1;
|
||||
|
@ -348,7 +350,7 @@ mod tests {
|
|||
let raw = LSPS2RawOpeningFeeParams {
|
||||
min_fee_msat,
|
||||
proportional,
|
||||
valid_until: valid_until.into(),
|
||||
valid_until,
|
||||
min_lifetime,
|
||||
max_client_to_self_delay,
|
||||
min_payment_size_msat,
|
||||
|
|
|
@ -1419,12 +1419,14 @@ fn calculate_amount_to_forward_per_htlc(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use chrono::TimeZone;
|
||||
use chrono::Utc;
|
||||
|
||||
use crate::lsps0::ser::LSPSDateTime;
|
||||
|
||||
use proptest::prelude::*;
|
||||
|
||||
use core::str::FromStr;
|
||||
|
||||
const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000;
|
||||
|
||||
fn arb_forward_amounts() -> impl Strategy<Value = (u64, u64, u64, u64)> {
|
||||
|
@ -1518,7 +1520,7 @@ mod tests {
|
|||
let opening_fee_params = LSPS2OpeningFeeParams {
|
||||
min_fee_msat: 10_000_000,
|
||||
proportional: 10_000,
|
||||
valid_until: Utc.timestamp_opt(3000, 0).unwrap(),
|
||||
valid_until: LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
|
||||
min_lifetime: 4032,
|
||||
max_client_to_self_delay: 2016,
|
||||
min_payment_size_msat: 10_000_000,
|
||||
|
@ -1710,7 +1712,7 @@ mod tests {
|
|||
let opening_fee_params = LSPS2OpeningFeeParams {
|
||||
min_fee_msat: 10_000_000,
|
||||
proportional: 10_000,
|
||||
valid_until: Utc.timestamp_opt(3000, 0).unwrap(),
|
||||
valid_until: LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
|
||||
min_lifetime: 4032,
|
||||
max_client_to_self_delay: 2016,
|
||||
min_payment_size_msat: 10_000_000,
|
||||
|
|
|
@ -7,9 +7,6 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine};
|
|||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::{Hash, HashEngine};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
/// Determines if the given parameters are valid given the secret used to generate the promise.
|
||||
pub fn is_valid_opening_fee_params(
|
||||
fee_params: &LSPS2OpeningFeeParams, promise_secret: &[u8; 32],
|
||||
|
@ -35,16 +32,7 @@ pub fn is_valid_opening_fee_params(
|
|||
pub fn is_expired_opening_fee_params(fee_params: &LSPS2OpeningFeeParams) -> bool {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
let seconds_since_epoch = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("system clock to be ahead of the unix epoch")
|
||||
.as_secs();
|
||||
let valid_until_seconds_since_epoch = fee_params
|
||||
.valid_until
|
||||
.timestamp()
|
||||
.try_into()
|
||||
.expect("expiration to be ahead of unix epoch");
|
||||
seconds_since_epoch > valid_until_seconds_since_epoch
|
||||
fee_params.valid_until.is_past()
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ mod common;
|
|||
use common::{create_service_and_client_nodes, get_lsps_message, Node};
|
||||
|
||||
use lightning_liquidity::events::LiquidityEvent;
|
||||
use lightning_liquidity::lsps0::ser::LSPSDateTime;
|
||||
use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
|
||||
use lightning_liquidity::lsps2::event::{LSPS2ClientEvent, LSPS2ServiceEvent};
|
||||
use lightning_liquidity::lsps2::msgs::LSPS2RawOpeningFeeParams;
|
||||
|
@ -24,8 +25,7 @@ use bitcoin::hashes::{sha256, Hash};
|
|||
use bitcoin::secp256k1::{PublicKey, Secp256k1};
|
||||
use bitcoin::Network;
|
||||
|
||||
use chrono::DateTime;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
fn create_jit_invoice(
|
||||
|
@ -128,7 +128,7 @@ fn invoice_generation_flow() {
|
|||
let raw_opening_params = LSPS2RawOpeningFeeParams {
|
||||
min_fee_msat: 100,
|
||||
proportional: 21,
|
||||
valid_until: DateTime::parse_from_rfc3339("2035-05-20T08:30:45Z").unwrap().into(),
|
||||
valid_until: LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
|
||||
min_lifetime: 144,
|
||||
max_client_to_self_delay: 128,
|
||||
min_payment_size_msat: 1,
|
||||
|
|
Loading…
Add table
Reference in a new issue