1111
1212use crate :: alloc:: string:: ToString ;
1313use crate :: events:: EventQueue ;
14- use crate :: lsps0:: ser:: { LSPSDateTime , LSPSMessage , LSPSProtocolMessageHandler , LSPSRequestId } ;
14+ use crate :: lsps0:: ser:: { LSPSMessage , LSPSProtocolMessageHandler , LSPSRequestId } ;
1515use crate :: lsps5:: event:: LSPS5ClientEvent ;
1616use crate :: lsps5:: msgs:: {
1717 LSPS5Message , LSPS5Request , LSPS5Response , ListWebhooksRequest , RemoveWebhookRequest ,
@@ -22,7 +22,6 @@ use crate::message_queue::MessageQueue;
2222use crate :: prelude:: { new_hash_map, HashMap } ;
2323use crate :: sync:: { Arc , Mutex , RwLock } ;
2424use crate :: utils:: generate_request_id;
25- use crate :: utils:: time:: TimeProvider ;
2625
2726use super :: msgs:: { LSPS5AppName , LSPS5Error , LSPS5WebhookUrl } ;
2827
@@ -35,76 +34,25 @@ use lightning::util::logger::Level;
3534use alloc:: string:: String ;
3635
3736use core:: ops:: Deref ;
38- use core:: time:: Duration ;
3937
40- /// Default maximum age in seconds for cached responses (1 hour).
41- pub const DEFAULT_RESPONSE_MAX_AGE_SECS : u64 = 3600 ;
42-
43- #[ derive( Debug , Clone ) ]
38+ #[ derive( Debug , Clone , Copy , Default ) ]
4439/// Configuration for the LSPS5 client
45- pub struct LSPS5ClientConfig {
46- /// Maximum age in seconds for cached responses (default: [`DEFAULT_RESPONSE_MAX_AGE_SECS`]).
47- pub response_max_age_secs : Duration ,
48- }
40+ pub struct LSPS5ClientConfig { }
4941
50- impl Default for LSPS5ClientConfig {
51- fn default ( ) -> Self {
52- Self { response_max_age_secs : Duration :: from_secs ( DEFAULT_RESPONSE_MAX_AGE_SECS ) }
53- }
42+ struct PeerState {
43+ pending_set_webhook_requests : HashMap < LSPSRequestId , ( LSPS5AppName , LSPS5WebhookUrl ) > ,
44+ pending_list_webhooks_requests : HashMap < LSPSRequestId , ( ) > ,
45+ pending_remove_webhook_requests : HashMap < LSPSRequestId , LSPS5AppName > ,
5446}
5547
56- struct PeerState < TP : Deref + Clone >
57- where
58- TP :: Target : TimeProvider ,
59- {
60- pending_set_webhook_requests :
61- HashMap < LSPSRequestId , ( LSPS5AppName , LSPS5WebhookUrl , LSPSDateTime ) > ,
62- pending_list_webhooks_requests : HashMap < LSPSRequestId , LSPSDateTime > ,
63- pending_remove_webhook_requests : HashMap < LSPSRequestId , ( LSPS5AppName , LSPSDateTime ) > ,
64- last_cleanup : Option < LSPSDateTime > ,
65- max_age_secs : Duration ,
66- time_provider : TP ,
67- }
68-
69- impl < TP : Deref + Clone > PeerState < TP >
70- where
71- TP :: Target : TimeProvider ,
72- {
73- fn new ( max_age_secs : Duration , time_provider : TP ) -> Self {
48+ impl PeerState {
49+ fn new ( ) -> Self {
7450 Self {
7551 pending_set_webhook_requests : new_hash_map ( ) ,
7652 pending_list_webhooks_requests : new_hash_map ( ) ,
7753 pending_remove_webhook_requests : new_hash_map ( ) ,
78- last_cleanup : None ,
79- max_age_secs,
80- time_provider,
8154 }
8255 }
83-
84- fn cleanup_expired_responses ( & mut self ) {
85- let now =
86- LSPSDateTime :: new_from_duration_since_epoch ( self . time_provider . duration_since_epoch ( ) ) ;
87- // Only run cleanup once per minute to avoid excessive processing
88- const CLEANUP_INTERVAL : Duration = Duration :: from_secs ( 60 ) ;
89- if let Some ( last_cleanup) = & self . last_cleanup {
90- let time_since_last_cleanup = Duration :: from_secs ( now. abs_diff ( & last_cleanup) ) ;
91- if time_since_last_cleanup < CLEANUP_INTERVAL {
92- return ;
93- }
94- }
95-
96- self . last_cleanup = Some ( now. clone ( ) ) ;
97-
98- self . pending_set_webhook_requests . retain ( |_, ( _, _, timestamp) | {
99- Duration :: from_secs ( timestamp. abs_diff ( & now) ) < self . max_age_secs
100- } ) ;
101- self . pending_list_webhooks_requests . retain ( |_, timestamp| {
102- Duration :: from_secs ( timestamp. abs_diff ( & now) ) < self . max_age_secs
103- } ) ;
104- self . pending_remove_webhook_requests . retain ( |_, ( _, timestamp) | {
105- Duration :: from_secs ( timestamp. abs_diff ( & now) ) < self . max_age_secs
106- } ) ;
107- }
10856}
10957
11058/// Client-side handler for the LSPS5 (bLIP-55) webhook registration protocol.
@@ -128,51 +76,44 @@ where
12876/// [`lsps5.list_webhooks`]: super::msgs::LSPS5Request::ListWebhooks
12977/// [`lsps5.remove_webhook`]: super::msgs::LSPS5Request::RemoveWebhook
13078/// [`LSPS5Validator`]: super::validator::LSPS5Validator
131- pub struct LSPS5ClientHandler < ES : Deref , TP : Deref + Clone >
79+ pub struct LSPS5ClientHandler < ES : Deref >
13280where
13381 ES :: Target : EntropySource ,
134- TP :: Target : TimeProvider ,
13582{
13683 pending_messages : Arc < MessageQueue > ,
13784 pending_events : Arc < EventQueue > ,
13885 entropy_source : ES ,
139- per_peer_state : RwLock < HashMap < PublicKey , Mutex < PeerState < TP > > > > ,
140- config : LSPS5ClientConfig ,
141- time_provider : TP ,
86+ per_peer_state : RwLock < HashMap < PublicKey , Mutex < PeerState > > > ,
87+ _config : LSPS5ClientConfig ,
14288}
14389
144- impl < ES : Deref , TP : Deref + Clone > LSPS5ClientHandler < ES , TP >
90+ impl < ES : Deref > LSPS5ClientHandler < ES >
14591where
14692 ES :: Target : EntropySource ,
147- TP :: Target : TimeProvider ,
14893{
14994 /// Constructs an `LSPS5ClientHandler`.
150- pub ( crate ) fn new_with_time_provider (
95+ pub ( crate ) fn new (
15196 entropy_source : ES , pending_messages : Arc < MessageQueue > , pending_events : Arc < EventQueue > ,
152- config : LSPS5ClientConfig , time_provider : TP ,
97+ _config : LSPS5ClientConfig ,
15398 ) -> Self {
15499 Self {
155100 pending_messages,
156101 pending_events,
157102 entropy_source,
158103 per_peer_state : RwLock :: new ( new_hash_map ( ) ) ,
159- config,
160- time_provider,
104+ _config,
161105 }
162106 }
163107
164108 fn with_peer_state < F , R > ( & self , counterparty_node_id : PublicKey , f : F ) -> R
165109 where
166- F : FnOnce ( & mut PeerState < TP > ) -> R ,
110+ F : FnOnce ( & mut PeerState ) -> R ,
167111 {
168112 let mut outer_state_lock = self . per_peer_state . write ( ) . unwrap ( ) ;
169- let inner_state_lock = outer_state_lock. entry ( counterparty_node_id) . or_insert ( Mutex :: new (
170- PeerState :: new ( self . config . response_max_age_secs , self . time_provider . clone ( ) ) ,
171- ) ) ;
113+ let inner_state_lock =
114+ outer_state_lock. entry ( counterparty_node_id) . or_insert ( Mutex :: new ( PeerState :: new ( ) ) ) ;
172115 let mut peer_state_lock = inner_state_lock. lock ( ) . unwrap ( ) ;
173116
174- peer_state_lock. cleanup_expired_responses ( ) ;
175-
176117 f ( & mut * peer_state_lock)
177118 }
178119
@@ -212,16 +153,9 @@ where
212153 let request_id = generate_request_id ( & self . entropy_source ) ;
213154
214155 self . with_peer_state ( counterparty_node_id, |peer_state| {
215- peer_state. pending_set_webhook_requests . insert (
216- request_id. clone ( ) ,
217- (
218- app_name. clone ( ) ,
219- lsps_webhook_url. clone ( ) ,
220- LSPSDateTime :: new_from_duration_since_epoch (
221- self . time_provider . duration_since_epoch ( ) ,
222- ) ,
223- ) ,
224- ) ;
156+ peer_state
157+ . pending_set_webhook_requests
158+ . insert ( request_id. clone ( ) , ( app_name. clone ( ) , lsps_webhook_url. clone ( ) ) ) ;
225159 } ) ;
226160
227161 let request =
@@ -251,11 +185,9 @@ where
251185 /// [`LSPS5Response::ListWebhooks`]: super::msgs::LSPS5Response::ListWebhooks
252186 pub fn list_webhooks ( & self , counterparty_node_id : PublicKey ) -> LSPSRequestId {
253187 let request_id = generate_request_id ( & self . entropy_source ) ;
254- let now =
255- LSPSDateTime :: new_from_duration_since_epoch ( self . time_provider . duration_since_epoch ( ) ) ;
256188
257189 self . with_peer_state ( counterparty_node_id, |peer_state| {
258- peer_state. pending_list_webhooks_requests . insert ( request_id. clone ( ) , now ) ;
190+ peer_state. pending_list_webhooks_requests . insert ( request_id. clone ( ) , ( ) ) ;
259191 } ) ;
260192
261193 let request = LSPS5Request :: ListWebhooks ( ListWebhooksRequest { } ) ;
@@ -290,13 +222,9 @@ where
290222 let app_name = LSPS5AppName :: from_string ( app_name) ?;
291223
292224 let request_id = generate_request_id ( & self . entropy_source ) ;
293- let now =
294- LSPSDateTime :: new_from_duration_since_epoch ( self . time_provider . duration_since_epoch ( ) ) ;
295225
296226 self . with_peer_state ( counterparty_node_id, |peer_state| {
297- peer_state
298- . pending_remove_webhook_requests
299- . insert ( request_id. clone ( ) , ( app_name. clone ( ) , now) ) ;
227+ peer_state. pending_remove_webhook_requests . insert ( request_id. clone ( ) , app_name. clone ( ) ) ;
300228 } ) ;
301229
302230 let request = LSPS5Request :: RemoveWebhook ( RemoveWebhookRequest { app_name } ) ;
@@ -326,8 +254,8 @@ where
326254 action : ErrorAction :: IgnoreAndLog ( Level :: Debug ) ,
327255 } ) ;
328256 let event_queue_notifier = self . pending_events . notifier ( ) ;
329- let handle_response = |peer_state : & mut PeerState < TP > | {
330- if let Some ( ( app_name, webhook_url, _ ) ) =
257+ let handle_response = |peer_state : & mut PeerState | {
258+ if let Some ( ( app_name, webhook_url) ) =
331259 peer_state. pending_set_webhook_requests . remove ( & request_id)
332260 {
333261 match & response {
@@ -378,7 +306,7 @@ where
378306 } ) ;
379307 } ,
380308 }
381- } else if let Some ( ( app_name, _ ) ) =
309+ } else if let Some ( app_name) =
382310 peer_state. pending_remove_webhook_requests . remove ( & request_id)
383311 {
384312 match & response {
@@ -418,10 +346,9 @@ where
418346 }
419347}
420348
421- impl < ES : Deref , TP : Deref + Clone > LSPSProtocolMessageHandler for LSPS5ClientHandler < ES , TP >
349+ impl < ES : Deref > LSPSProtocolMessageHandler for LSPS5ClientHandler < ES >
422350where
423351 ES :: Target : EntropySource ,
424- TP :: Target : TimeProvider ,
425352{
426353 type ProtocolMessage = LSPS5Message ;
427354 const PROTOCOL_NUMBER : Option < u16 > = Some ( 5 ) ;
@@ -435,17 +362,15 @@ where
435362
436363#[ cfg( all( test, feature = "time" ) ) ]
437364mod tests {
438- use core:: time:: Duration ;
439365
440366 use super :: * ;
441367 use crate :: {
442368 lsps0:: ser:: LSPSRequestId , lsps5:: msgs:: SetWebhookResponse , tests:: utils:: TestEntropy ,
443- utils:: time:: DefaultTimeProvider ,
444369 } ;
445370 use bitcoin:: { key:: Secp256k1 , secp256k1:: SecretKey } ;
446371
447372 fn setup_test_client ( ) -> (
448- LSPS5ClientHandler < Arc < TestEntropy > , Arc < DefaultTimeProvider > > ,
373+ LSPS5ClientHandler < Arc < TestEntropy > > ,
449374 Arc < MessageQueue > ,
450375 Arc < EventQueue > ,
451376 PublicKey ,
@@ -454,12 +379,11 @@ mod tests {
454379 let test_entropy_source = Arc :: new ( TestEntropy { } ) ;
455380 let message_queue = Arc :: new ( MessageQueue :: new ( ) ) ;
456381 let event_queue = Arc :: new ( EventQueue :: new ( ) ) ;
457- let client = LSPS5ClientHandler :: new_with_time_provider (
382+ let client = LSPS5ClientHandler :: new (
458383 test_entropy_source,
459384 Arc :: clone ( & message_queue) ,
460385 Arc :: clone ( & event_queue) ,
461386 LSPS5ClientConfig :: default ( ) ,
462- Arc :: new ( DefaultTimeProvider ) ,
463387 ) ;
464388
465389 let secp = Secp256k1 :: new ( ) ;
@@ -510,18 +434,14 @@ mod tests {
510434 let peer_state = outer_state_lock. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
511435 assert_eq ! (
512436 peer_state. pending_set_webhook_requests. get( & set_req_id) . unwrap( ) ,
513- & (
514- lsps5_app_name. clone( ) ,
515- lsps5_webhook_url,
516- peer_state. pending_set_webhook_requests. get( & set_req_id) . unwrap( ) . 2 . clone( )
517- )
437+ & ( lsps5_app_name. clone( ) , lsps5_webhook_url)
518438 ) ;
519439
520440 assert ! ( peer_state. pending_list_webhooks_requests. contains_key( & list_req_id) ) ;
521441
522442 assert_eq ! (
523- peer_state. pending_remove_webhook_requests. get( & remove_req_id) . unwrap( ) . 0 ,
524- lsps5_app_name
443+ peer_state. pending_remove_webhook_requests. get( & remove_req_id) . unwrap( ) ,
444+ & lsps5_app_name
525445 ) ;
526446 }
527447 }
@@ -556,66 +476,6 @@ mod tests {
556476 }
557477 }
558478
559- #[ test]
560- fn test_cleanup_expired_responses ( ) {
561- let ( client, _, _, _, _) = setup_test_client ( ) ;
562- let time_provider = & client. time_provider ;
563- const OLD_APP_NAME : & str = "test-app-old" ;
564- const NEW_APP_NAME : & str = "test-app-new" ;
565- const WEBHOOK_URL : & str = "https://example.com/hook" ;
566- let lsps5_old_app_name = LSPS5AppName :: from_string ( OLD_APP_NAME . to_string ( ) ) . unwrap ( ) ;
567- let lsps5_new_app_name = LSPS5AppName :: from_string ( NEW_APP_NAME . to_string ( ) ) . unwrap ( ) ;
568- let lsps5_webhook_url = LSPS5WebhookUrl :: from_string ( WEBHOOK_URL . to_string ( ) ) . unwrap ( ) ;
569- let now = time_provider. duration_since_epoch ( ) ;
570- let mut peer_state = PeerState :: < Arc < DefaultTimeProvider > > :: new (
571- Duration :: from_secs ( 1800 ) ,
572- Arc :: clone ( time_provider) ,
573- ) ;
574- peer_state. last_cleanup = Some ( LSPSDateTime :: new_from_duration_since_epoch (
575- now. checked_sub ( Duration :: from_secs ( 120 ) ) . unwrap ( ) ,
576- ) ) ;
577-
578- let old_request_id = LSPSRequestId ( "test:request:old" . to_string ( ) ) ;
579- let new_request_id = LSPSRequestId ( "test:request:new" . to_string ( ) ) ;
580-
581- // Add an old request (should be removed during cleanup)
582- peer_state. pending_set_webhook_requests . insert (
583- old_request_id. clone ( ) ,
584- (
585- lsps5_old_app_name,
586- lsps5_webhook_url. clone ( ) ,
587- LSPSDateTime :: new_from_duration_since_epoch (
588- now. checked_sub ( Duration :: from_secs ( 7200 ) ) . unwrap ( ) ,
589- ) ,
590- ) , // 2 hours old
591- ) ;
592-
593- // Add a recent request (should be kept)
594- peer_state. pending_set_webhook_requests . insert (
595- new_request_id. clone ( ) ,
596- (
597- lsps5_new_app_name,
598- lsps5_webhook_url,
599- LSPSDateTime :: new_from_duration_since_epoch (
600- now. checked_sub ( Duration :: from_secs ( 600 ) ) . unwrap ( ) ,
601- ) ,
602- ) , // 10 minutes old
603- ) ;
604-
605- peer_state. cleanup_expired_responses ( ) ;
606-
607- assert ! ( !peer_state. pending_set_webhook_requests. contains_key( & old_request_id) ) ;
608- assert ! ( peer_state. pending_set_webhook_requests. contains_key( & new_request_id) ) ;
609-
610- let cleanup_age = if let Some ( last_cleanup) = peer_state. last_cleanup {
611- LSPSDateTime :: new_from_duration_since_epoch ( time_provider. duration_since_epoch ( ) )
612- . abs_diff ( & last_cleanup)
613- } else {
614- 0
615- } ;
616- assert ! ( cleanup_age < 10 ) ;
617- }
618-
619479 #[ test]
620480 fn test_unknown_request_id_handling ( ) {
621481 let ( client, _message_queue, _, peer, _) = setup_test_client ( ) ;
0 commit comments