11
11
12
12
use crate :: alloc:: string:: ToString ;
13
13
use crate :: events:: EventQueue ;
14
- use crate :: lsps0:: ser:: { LSPSDateTime , LSPSMessage , LSPSProtocolMessageHandler , LSPSRequestId } ;
14
+ use crate :: lsps0:: ser:: { LSPSMessage , LSPSProtocolMessageHandler , LSPSRequestId } ;
15
15
use crate :: lsps5:: event:: LSPS5ClientEvent ;
16
16
use crate :: lsps5:: msgs:: {
17
17
LSPS5Message , LSPS5Request , LSPS5Response , ListWebhooksRequest , RemoveWebhookRequest ,
@@ -22,7 +22,6 @@ use crate::message_queue::MessageQueue;
22
22
use crate :: prelude:: { new_hash_map, HashMap } ;
23
23
use crate :: sync:: { Arc , Mutex , RwLock } ;
24
24
use crate :: utils:: generate_request_id;
25
- use crate :: utils:: time:: TimeProvider ;
26
25
27
26
use super :: msgs:: { LSPS5AppName , LSPS5Error , LSPS5WebhookUrl } ;
28
27
@@ -35,76 +34,25 @@ use lightning::util::logger::Level;
35
34
use alloc:: string:: String ;
36
35
37
36
use core:: ops:: Deref ;
38
- use core:: time:: Duration ;
39
37
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 ) ]
44
39
/// 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 { }
49
41
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 > ,
54
46
}
55
47
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 {
74
50
Self {
75
51
pending_set_webhook_requests : new_hash_map ( ) ,
76
52
pending_list_webhooks_requests : new_hash_map ( ) ,
77
53
pending_remove_webhook_requests : new_hash_map ( ) ,
78
- last_cleanup : None ,
79
- max_age_secs,
80
- time_provider,
81
54
}
82
55
}
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
- }
108
56
}
109
57
110
58
/// Client-side handler for the LSPS5 (bLIP-55) webhook registration protocol.
@@ -128,51 +76,44 @@ where
128
76
/// [`lsps5.list_webhooks`]: super::msgs::LSPS5Request::ListWebhooks
129
77
/// [`lsps5.remove_webhook`]: super::msgs::LSPS5Request::RemoveWebhook
130
78
/// [`LSPS5Validator`]: super::validator::LSPS5Validator
131
- pub struct LSPS5ClientHandler < ES : Deref , TP : Deref + Clone >
79
+ pub struct LSPS5ClientHandler < ES : Deref >
132
80
where
133
81
ES :: Target : EntropySource ,
134
- TP :: Target : TimeProvider ,
135
82
{
136
83
pending_messages : Arc < MessageQueue > ,
137
84
pending_events : Arc < EventQueue > ,
138
85
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 ,
142
88
}
143
89
144
- impl < ES : Deref , TP : Deref + Clone > LSPS5ClientHandler < ES , TP >
90
+ impl < ES : Deref > LSPS5ClientHandler < ES >
145
91
where
146
92
ES :: Target : EntropySource ,
147
- TP :: Target : TimeProvider ,
148
93
{
149
94
/// Constructs an `LSPS5ClientHandler`.
150
- pub ( crate ) fn new_with_time_provider (
95
+ pub ( crate ) fn new (
151
96
entropy_source : ES , pending_messages : Arc < MessageQueue > , pending_events : Arc < EventQueue > ,
152
- config : LSPS5ClientConfig , time_provider : TP ,
97
+ _config : LSPS5ClientConfig ,
153
98
) -> Self {
154
99
Self {
155
100
pending_messages,
156
101
pending_events,
157
102
entropy_source,
158
103
per_peer_state : RwLock :: new ( new_hash_map ( ) ) ,
159
- config,
160
- time_provider,
104
+ _config,
161
105
}
162
106
}
163
107
164
108
fn with_peer_state < F , R > ( & self , counterparty_node_id : PublicKey , f : F ) -> R
165
109
where
166
- F : FnOnce ( & mut PeerState < TP > ) -> R ,
110
+ F : FnOnce ( & mut PeerState ) -> R ,
167
111
{
168
112
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 ( ) ) ) ;
172
115
let mut peer_state_lock = inner_state_lock. lock ( ) . unwrap ( ) ;
173
116
174
- peer_state_lock. cleanup_expired_responses ( ) ;
175
-
176
117
f ( & mut * peer_state_lock)
177
118
}
178
119
@@ -212,16 +153,9 @@ where
212
153
let request_id = generate_request_id ( & self . entropy_source ) ;
213
154
214
155
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 ( ) ) ) ;
225
159
} ) ;
226
160
227
161
let request =
@@ -251,11 +185,9 @@ where
251
185
/// [`LSPS5Response::ListWebhooks`]: super::msgs::LSPS5Response::ListWebhooks
252
186
pub fn list_webhooks ( & self , counterparty_node_id : PublicKey ) -> LSPSRequestId {
253
187
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 ( ) ) ;
256
188
257
189
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 ( ) , ( ) ) ;
259
191
} ) ;
260
192
261
193
let request = LSPS5Request :: ListWebhooks ( ListWebhooksRequest { } ) ;
@@ -290,13 +222,9 @@ where
290
222
let app_name = LSPS5AppName :: from_string ( app_name) ?;
291
223
292
224
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 ( ) ) ;
295
225
296
226
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 ( ) ) ;
300
228
} ) ;
301
229
302
230
let request = LSPS5Request :: RemoveWebhook ( RemoveWebhookRequest { app_name } ) ;
@@ -326,8 +254,8 @@ where
326
254
action : ErrorAction :: IgnoreAndLog ( Level :: Debug ) ,
327
255
} ) ;
328
256
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) ) =
331
259
peer_state. pending_set_webhook_requests . remove ( & request_id)
332
260
{
333
261
match & response {
@@ -378,7 +306,7 @@ where
378
306
} ) ;
379
307
} ,
380
308
}
381
- } else if let Some ( ( app_name, _ ) ) =
309
+ } else if let Some ( app_name) =
382
310
peer_state. pending_remove_webhook_requests . remove ( & request_id)
383
311
{
384
312
match & response {
@@ -418,10 +346,9 @@ where
418
346
}
419
347
}
420
348
421
- impl < ES : Deref , TP : Deref + Clone > LSPSProtocolMessageHandler for LSPS5ClientHandler < ES , TP >
349
+ impl < ES : Deref > LSPSProtocolMessageHandler for LSPS5ClientHandler < ES >
422
350
where
423
351
ES :: Target : EntropySource ,
424
- TP :: Target : TimeProvider ,
425
352
{
426
353
type ProtocolMessage = LSPS5Message ;
427
354
const PROTOCOL_NUMBER : Option < u16 > = Some ( 5 ) ;
@@ -435,17 +362,15 @@ where
435
362
436
363
#[ cfg( all( test, feature = "time" ) ) ]
437
364
mod tests {
438
- use core:: time:: Duration ;
439
365
440
366
use super :: * ;
441
367
use crate :: {
442
368
lsps0:: ser:: LSPSRequestId , lsps5:: msgs:: SetWebhookResponse , tests:: utils:: TestEntropy ,
443
- utils:: time:: DefaultTimeProvider ,
444
369
} ;
445
370
use bitcoin:: { key:: Secp256k1 , secp256k1:: SecretKey } ;
446
371
447
372
fn setup_test_client ( ) -> (
448
- LSPS5ClientHandler < Arc < TestEntropy > , Arc < DefaultTimeProvider > > ,
373
+ LSPS5ClientHandler < Arc < TestEntropy > > ,
449
374
Arc < MessageQueue > ,
450
375
Arc < EventQueue > ,
451
376
PublicKey ,
@@ -454,12 +379,11 @@ mod tests {
454
379
let test_entropy_source = Arc :: new ( TestEntropy { } ) ;
455
380
let message_queue = Arc :: new ( MessageQueue :: new ( ) ) ;
456
381
let event_queue = Arc :: new ( EventQueue :: new ( ) ) ;
457
- let client = LSPS5ClientHandler :: new_with_time_provider (
382
+ let client = LSPS5ClientHandler :: new (
458
383
test_entropy_source,
459
384
Arc :: clone ( & message_queue) ,
460
385
Arc :: clone ( & event_queue) ,
461
386
LSPS5ClientConfig :: default ( ) ,
462
- Arc :: new ( DefaultTimeProvider ) ,
463
387
) ;
464
388
465
389
let secp = Secp256k1 :: new ( ) ;
@@ -510,18 +434,14 @@ mod tests {
510
434
let peer_state = outer_state_lock. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
511
435
assert_eq ! (
512
436
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)
518
438
) ;
519
439
520
440
assert ! ( peer_state. pending_list_webhooks_requests. contains_key( & list_req_id) ) ;
521
441
522
442
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
525
445
) ;
526
446
}
527
447
}
@@ -556,66 +476,6 @@ mod tests {
556
476
}
557
477
}
558
478
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
-
619
479
#[ test]
620
480
fn test_unknown_request_id_handling ( ) {
621
481
let ( client, _message_queue, _, peer, _) = setup_test_client ( ) ;
0 commit comments