@@ -21,6 +21,7 @@ use crate::lsps5::msgs::{
21
21
use crate :: message_queue:: MessageQueue ;
22
22
use crate :: prelude:: { new_hash_map, HashMap } ;
23
23
use crate :: sync:: { Arc , Mutex , RwLock } ;
24
+ use crate :: utils:: bounded_map:: BoundedMap ;
24
25
use crate :: utils:: generate_request_id;
25
26
26
27
use super :: msgs:: { LSPS5AppName , LSPS5Error , LSPS5WebhookUrl } ;
@@ -40,17 +41,19 @@ use core::ops::Deref;
40
41
pub struct LSPS5ClientConfig { }
41
42
42
43
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 > ,
44
+ pending_set_webhook_requests : BoundedMap < LSPSRequestId , ( LSPS5AppName , LSPS5WebhookUrl ) > ,
45
+ pending_list_webhooks_requests : BoundedMap < LSPSRequestId , ( ) > ,
46
+ pending_remove_webhook_requests : BoundedMap < LSPSRequestId , LSPS5AppName > ,
46
47
}
47
48
49
+ const MAX_PENDING_REQUESTS : usize = 5 ;
50
+
48
51
impl PeerState {
49
52
fn new ( ) -> Self {
50
53
Self {
51
- pending_set_webhook_requests : new_hash_map ( ) ,
52
- pending_list_webhooks_requests : new_hash_map ( ) ,
53
- pending_remove_webhook_requests : new_hash_map ( ) ,
54
+ pending_set_webhook_requests : BoundedMap :: new ( MAX_PENDING_REQUESTS ) ,
55
+ pending_list_webhooks_requests : BoundedMap :: new ( MAX_PENDING_REQUESTS ) ,
56
+ pending_remove_webhook_requests : BoundedMap :: new ( MAX_PENDING_REQUESTS ) ,
54
57
}
55
58
}
56
59
}
@@ -364,19 +367,31 @@ where
364
367
mod tests {
365
368
366
369
use super :: * ;
367
- use crate :: {
368
- lsps0:: ser:: LSPSRequestId , lsps5:: msgs:: SetWebhookResponse , tests:: utils:: TestEntropy ,
369
- } ;
370
+ use crate :: { lsps0:: ser:: LSPSRequestId , lsps5:: msgs:: SetWebhookResponse } ;
370
371
use bitcoin:: { key:: Secp256k1 , secp256k1:: SecretKey } ;
372
+ use core:: sync:: atomic:: { AtomicU64 , Ordering } ;
373
+
374
+ struct UniqueTestEntropy {
375
+ counter : AtomicU64 ,
376
+ }
377
+
378
+ impl EntropySource for UniqueTestEntropy {
379
+ fn get_secure_random_bytes ( & self ) -> [ u8 ; 32 ] {
380
+ let counter = self . counter . fetch_add ( 1 , Ordering :: SeqCst ) ;
381
+ let mut bytes = [ 0u8 ; 32 ] ;
382
+ bytes[ 0 ..8 ] . copy_from_slice ( & counter. to_be_bytes ( ) ) ;
383
+ bytes
384
+ }
385
+ }
371
386
372
387
fn setup_test_client ( ) -> (
373
- LSPS5ClientHandler < Arc < TestEntropy > > ,
388
+ LSPS5ClientHandler < Arc < UniqueTestEntropy > > ,
374
389
Arc < MessageQueue > ,
375
390
Arc < EventQueue > ,
376
391
PublicKey ,
377
392
PublicKey ,
378
393
) {
379
- let test_entropy_source = Arc :: new ( TestEntropy { } ) ;
394
+ let test_entropy_source = Arc :: new ( UniqueTestEntropy { counter : AtomicU64 :: new ( 2 ) } ) ;
380
395
let message_queue = Arc :: new ( MessageQueue :: new ( ) ) ;
381
396
let event_queue = Arc :: new ( EventQueue :: new ( ) ) ;
382
397
let client = LSPS5ClientHandler :: new (
@@ -497,4 +512,44 @@ mod tests {
497
512
let error = result. unwrap_err ( ) ;
498
513
assert ! ( error. err. to_lowercase( ) . contains( "unknown request id" ) ) ;
499
514
}
515
+
516
+ #[ test]
517
+ fn test_pending_request_eviction ( ) {
518
+ let ( client, _, _, peer, _) = setup_test_client ( ) ;
519
+
520
+ let mut request_ids = Vec :: new ( ) ;
521
+ for i in 0 ..MAX_PENDING_REQUESTS {
522
+ let req_id = client
523
+ . set_webhook ( peer, format ! ( "app-{}" , i) , format ! ( "https://example.com/hook{}" , i) )
524
+ . unwrap ( ) ;
525
+ request_ids. push ( req_id) ;
526
+ }
527
+
528
+ {
529
+ let outer_state_lock = client. per_peer_state . read ( ) . unwrap ( ) ;
530
+ let peer_state = outer_state_lock. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
531
+ for req_id in & request_ids {
532
+ assert ! ( peer_state. pending_set_webhook_requests. contains_key( req_id) ) ;
533
+ }
534
+ assert_eq ! ( peer_state. pending_set_webhook_requests. len( ) , MAX_PENDING_REQUESTS ) ;
535
+ }
536
+
537
+ let new_req_id = client
538
+ . set_webhook ( peer, "app-new" . to_string ( ) , "https://example.com/hook-new" . to_string ( ) )
539
+ . unwrap ( ) ;
540
+
541
+ {
542
+ let outer_state_lock = client. per_peer_state . read ( ) . unwrap ( ) ;
543
+ let peer_state = outer_state_lock. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
544
+ assert_eq ! ( peer_state. pending_set_webhook_requests. len( ) , MAX_PENDING_REQUESTS ) ;
545
+
546
+ assert ! ( !peer_state. pending_set_webhook_requests. contains_key( & request_ids[ 0 ] ) ) ;
547
+
548
+ for req_id in & request_ids[ 1 ..] {
549
+ assert ! ( peer_state. pending_set_webhook_requests. contains_key( req_id) ) ;
550
+ }
551
+
552
+ assert ! ( peer_state. pending_set_webhook_requests. contains_key( & new_req_id) ) ;
553
+ }
554
+ }
500
555
}
0 commit comments