Skip to content

Commit 057fdc3

Browse files
committed
lsps2: Track channel creation time via created_at field
Add a `created_at: LSPSDateTime` field to `OutboundJITChannel` to record when each JIT channel was created (i.e., when the buy request was accepted by the LSP). This timestamp is needed to implement time-based bulk pruning of completed channel state. The field is persisted as TLV type 10 with a `default_value` of Unix epoch, ensuring old serialized data (without TLV 10) is read back successfully with the epoch sentinel rather than failing deserialization.
1 parent ebaa7ed commit 057fdc3

2 files changed

Lines changed: 79 additions & 15 deletions

File tree

lightning-liquidity/src/lsps2/service.rs

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ use core::ops::Deref;
1919
use core::pin::pin;
2020
use core::sync::atomic::{AtomicUsize, Ordering};
2121
use core::task;
22+
use core::time::Duration;
2223

2324
use crate::events::EventQueue;
2425
use crate::lsps0::ser::{
25-
LSPSMessage, LSPSProtocolMessageHandler, LSPSRequestId, LSPSResponseError,
26+
LSPSDateTime, LSPSMessage, LSPSProtocolMessageHandler, LSPSRequestId, LSPSResponseError,
2627
JSONRPC_INTERNAL_ERROR_ERROR_CODE, JSONRPC_INTERNAL_ERROR_ERROR_MESSAGE,
2728
LSPS0_CLIENT_REJECTED_ERROR_CODE,
2829
};
30+
use crate::utils::time::TimeProvider;
2931
use crate::lsps2::event::LSPS2ServiceEvent;
3032
use crate::lsps2::payment_queue::{InterceptedHTLC, PaymentQueue};
3133
use crate::lsps2::utils::{
@@ -497,6 +499,8 @@ struct OutboundJITChannel {
497499
opening_fee_params: LSPS2OpeningFeeParams,
498500
payment_size_msat: Option<u64>,
499501
trust_model: TrustModel,
502+
/// The time at which the JIT channel was created (i.e., the buy request was accepted).
503+
created_at: LSPSDateTime,
500504
}
501505

502506
impl_writeable_tlv_based!(OutboundJITChannel, {
@@ -505,19 +509,21 @@ impl_writeable_tlv_based!(OutboundJITChannel, {
505509
(4, opening_fee_params, required),
506510
(6, payment_size_msat, option),
507511
(8, trust_model, required),
512+
(10, created_at, (default_value, LSPSDateTime::new_from_duration_since_epoch(Duration::ZERO))),
508513
});
509514

510515
impl OutboundJITChannel {
511516
fn new(
512517
payment_size_msat: Option<u64>, opening_fee_params: LSPS2OpeningFeeParams,
513-
user_channel_id: u128, client_trusts_lsp: bool,
518+
user_channel_id: u128, client_trusts_lsp: bool, created_at: LSPSDateTime,
514519
) -> Self {
515520
Self {
516521
user_channel_id,
517522
state: OutboundJITChannelState::new(),
518523
opening_fee_params,
519524
payment_size_msat,
520525
trust_model: TrustModel::new(client_trusts_lsp),
526+
created_at,
521527
}
522528
}
523529

@@ -702,9 +708,10 @@ macro_rules! get_or_insert_peer_state_entry {
702708
}
703709

704710
/// The main object allowing to send and receive bLIP-52 / LSPS2 messages.
705-
pub struct LSPS2ServiceHandler<CM: Deref, K: KVStore + Clone, T: BroadcasterInterface>
711+
pub struct LSPS2ServiceHandler<CM: Deref, K: KVStore + Clone, T: BroadcasterInterface, TP: Deref + Clone>
706712
where
707713
CM::Target: AChannelManager,
714+
TP::Target: TimeProvider,
708715
{
709716
channel_manager: CM,
710717
kv_store: K,
@@ -717,17 +724,20 @@ where
717724
total_pending_requests: AtomicUsize,
718725
config: LSPS2ServiceConfig,
719726
persistence_in_flight: AtomicUsize,
727+
time_provider: TP,
720728
}
721729

722-
impl<CM: Deref, K: KVStore + Clone, T: BroadcasterInterface + Clone> LSPS2ServiceHandler<CM, K, T>
730+
impl<CM: Deref, K: KVStore + Clone, T: BroadcasterInterface + Clone, TP: Deref + Clone>
731+
LSPS2ServiceHandler<CM, K, T, TP>
723732
where
724733
CM::Target: AChannelManager,
734+
TP::Target: TimeProvider,
725735
{
726736
/// Constructs a `LSPS2ServiceHandler`.
727737
pub(crate) fn new(
728738
per_peer_state: HashMap<PublicKey, Mutex<PeerState>>, pending_messages: Arc<MessageQueue>,
729739
pending_events: Arc<EventQueue<K>>, channel_manager: CM, kv_store: K, tx_broadcaster: T,
730-
config: LSPS2ServiceConfig,
740+
config: LSPS2ServiceConfig, time_provider: TP,
731741
) -> Result<Self, lightning::io::Error> {
732742
let mut peer_by_intercept_scid = new_hash_map();
733743
let mut peer_by_channel_id = new_hash_map();
@@ -768,6 +778,7 @@ where
768778
kv_store,
769779
tx_broadcaster,
770780
config,
781+
time_provider,
771782
})
772783
}
773784

@@ -921,11 +932,15 @@ where
921932
peer_by_intercept_scid.insert(intercept_scid, *counterparty_node_id);
922933
}
923934

935+
let created_at = LSPSDateTime::new_from_duration_since_epoch(
936+
self.time_provider.duration_since_epoch(),
937+
);
924938
let outbound_jit_channel = OutboundJITChannel::new(
925939
buy_request.payment_size_msat,
926940
buy_request.opening_fee_params,
927941
user_channel_id,
928942
client_trusts_lsp,
943+
created_at,
929944
);
930945

931946
peer_state_lock
@@ -2050,10 +2065,11 @@ where
20502065
}
20512066
}
20522067

2053-
impl<CM: Deref, K: KVStore + Clone, T: BroadcasterInterface + Clone> LSPSProtocolMessageHandler
2054-
for LSPS2ServiceHandler<CM, K, T>
2068+
impl<CM: Deref, K: KVStore + Clone, T: BroadcasterInterface + Clone, TP: Deref + Clone>
2069+
LSPSProtocolMessageHandler for LSPS2ServiceHandler<CM, K, T, TP>
20552070
where
20562071
CM::Target: AChannelManager,
2072+
TP::Target: TimeProvider,
20572073
{
20582074
type ProtocolMessage = LSPS2Message;
20592075
const PROTOCOL_NUMBER: Option<u16> = Some(2);
@@ -2128,18 +2144,21 @@ pub struct LSPS2ServiceHandlerSync<
21282144
CM: Deref,
21292145
K: KVStore + Clone,
21302146
T: BroadcasterInterface + Clone,
2147+
TP: Deref + Clone,
21312148
> where
21322149
CM::Target: AChannelManager,
2150+
TP::Target: TimeProvider,
21332151
{
2134-
inner: &'a LSPS2ServiceHandler<CM, K, T>,
2152+
inner: &'a LSPS2ServiceHandler<CM, K, T, TP>,
21352153
}
21362154

2137-
impl<'a, CM: Deref, K: KVStore + Clone, T: BroadcasterInterface + Clone>
2138-
LSPS2ServiceHandlerSync<'a, CM, K, T>
2155+
impl<'a, CM: Deref, K: KVStore + Clone, T: BroadcasterInterface + Clone, TP: Deref + Clone>
2156+
LSPS2ServiceHandlerSync<'a, CM, K, T, TP>
21392157
where
21402158
CM::Target: AChannelManager,
2159+
TP::Target: TimeProvider,
21412160
{
2142-
pub(crate) fn from_inner(inner: &'a LSPS2ServiceHandler<CM, K, T>) -> Self {
2161+
pub(crate) fn from_inner(inner: &'a LSPS2ServiceHandler<CM, K, T, TP>) -> Self {
21432162
Self { inner }
21442163
}
21452164

@@ -2785,6 +2804,7 @@ mod tests {
27852804
opening_fee_params.clone(),
27862805
user_channel_id,
27872806
true,
2807+
LSPSDateTime::from_str("2024-01-01T00:00:00Z").unwrap(),
27882808
);
27892809

27902810
let opening_payment_hash = PaymentHash([42; 32]);
@@ -2864,4 +2884,47 @@ mod tests {
28642884
"Broadcast was not allowed even though all the skimmed fees were collected"
28652885
);
28662886
}
2887+
2888+
#[test]
2889+
fn test_outbound_jit_channel_created_at_stored() {
2890+
let opening_fee_params = LSPS2OpeningFeeParams {
2891+
min_fee_msat: 1_000,
2892+
proportional: 0,
2893+
valid_until: LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
2894+
min_lifetime: 144,
2895+
max_client_to_self_delay: 128,
2896+
min_payment_size_msat: 1,
2897+
max_payment_size_msat: 10_000_000_000,
2898+
promise: "ignore".to_string(),
2899+
};
2900+
let created_at = LSPSDateTime::from_str("2024-06-15T12:00:00Z").unwrap();
2901+
let channel =
2902+
OutboundJITChannel::new(Some(1_000_000), opening_fee_params, 1u128, true, created_at);
2903+
assert_eq!(channel.created_at, created_at);
2904+
}
2905+
2906+
#[test]
2907+
fn test_outbound_jit_channel_created_at_round_trips() {
2908+
use lightning::util::ser::{Readable, Writeable};
2909+
2910+
let opening_fee_params = LSPS2OpeningFeeParams {
2911+
min_fee_msat: 1_000,
2912+
proportional: 0,
2913+
valid_until: LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
2914+
min_lifetime: 144,
2915+
max_client_to_self_delay: 128,
2916+
min_payment_size_msat: 1,
2917+
max_payment_size_msat: 10_000_000_000,
2918+
promise: "ignore".to_string(),
2919+
};
2920+
let created_at = LSPSDateTime::from_str("2024-06-15T12:00:00Z").unwrap();
2921+
let channel =
2922+
OutboundJITChannel::new(Some(1_000_000), opening_fee_params, 1u128, true, created_at);
2923+
2924+
let mut buf = Vec::new();
2925+
channel.write(&mut buf).unwrap();
2926+
2927+
let decoded = <OutboundJITChannel as Readable>::read(&mut &buf[..]).unwrap();
2928+
assert_eq!(decoded.created_at, created_at);
2929+
}
28672930
}

lightning-liquidity/src/manager.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ pub struct LiquidityManager<
283283
lsps0_service_handler: Option<LSPS0ServiceHandler>,
284284
lsps1_service_handler: Option<LSPS1ServiceHandler<ES, CM, K, TP>>,
285285
lsps1_client_handler: Option<LSPS1ClientHandler<ES, K>>,
286-
lsps2_service_handler: Option<LSPS2ServiceHandler<CM, K, T>>,
286+
lsps2_service_handler: Option<LSPS2ServiceHandler<CM, K, T, TP>>,
287287
lsps2_client_handler: Option<LSPS2ClientHandler<ES, K>>,
288288
lsps5_service_handler: Option<LSPS5ServiceHandler<CM, NS, K, TP>>,
289289
lsps5_client_handler: Option<LSPS5ClientHandler<ES, K>>,
@@ -377,7 +377,7 @@ where
377377
let lsps2_service_handler = if let Some(service_config) = service_config.as_ref() {
378378
if let Some(lsps2_service_config) = service_config.lsps2_service_config.as_ref() {
379379
if let Some(number) =
380-
<LSPS2ServiceHandler<CM, K, T> as LSPSProtocolMessageHandler>::PROTOCOL_NUMBER
380+
<LSPS2ServiceHandler<CM, K, T, TP> as LSPSProtocolMessageHandler>::PROTOCOL_NUMBER
381381
{
382382
supported_protocols.push(number);
383383
}
@@ -391,6 +391,7 @@ where
391391
kv_store.clone(),
392392
transaction_broadcaster.clone(),
393393
lsps2_service_config.clone(),
394+
time_provider.clone(),
394395
)?)
395396
} else {
396397
None
@@ -540,7 +541,7 @@ where
540541
/// Returns a reference to the LSPS2 server-side handler.
541542
///
542543
/// The returned hendler allows to initiate the LSPS2 service-side flow.
543-
pub fn lsps2_service_handler(&self) -> Option<&LSPS2ServiceHandler<CM, K, T>> {
544+
pub fn lsps2_service_handler(&self) -> Option<&LSPS2ServiceHandler<CM, K, T, TP>> {
544545
self.lsps2_service_handler.as_ref()
545546
}
546547

@@ -1053,7 +1054,7 @@ where
10531054
/// Wraps [`LiquidityManager::lsps2_service_handler`].
10541055
pub fn lsps2_service_handler<'a>(
10551056
&'a self,
1056-
) -> Option<LSPS2ServiceHandlerSync<'a, CM, KVStoreSyncWrapper<KS>, T>> {
1057+
) -> Option<LSPS2ServiceHandlerSync<'a, CM, KVStoreSyncWrapper<KS>, T, TP>> {
10571058
self.inner.lsps2_service_handler.as_ref().map(|r| LSPS2ServiceHandlerSync::from_inner(r))
10581059
}
10591060

0 commit comments

Comments
 (0)