@@ -21,6 +21,7 @@ use crate::lsps5::msgs::{
2121use crate :: message_queue:: MessageQueue ;
2222use crate :: prelude:: { new_hash_map, HashMap } ;
2323use crate :: sync:: { Arc , Mutex , RwLock } ;
24+ use crate :: utils:: bounded_map:: BoundedMap ;
2425use crate :: utils:: generate_request_id;
2526
2627use super :: msgs:: { LSPS5AppName , LSPS5Error , LSPS5WebhookUrl } ;
@@ -40,17 +41,19 @@ use core::ops::Deref;
4041pub struct LSPS5ClientConfig { }
4142
4243struct 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 > ,
4647}
4748
49+ const MAX_PENDING_REQUESTS : usize = 5 ;
50+
4851impl PeerState {
4952 fn new ( ) -> Self {
5053 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 ) ,
5457 }
5558 }
5659}
@@ -364,19 +367,31 @@ where
364367mod tests {
365368
366369 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 } ;
370371 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+ }
371386
372387 fn setup_test_client ( ) -> (
373- LSPS5ClientHandler < Arc < TestEntropy > > ,
388+ LSPS5ClientHandler < Arc < UniqueTestEntropy > > ,
374389 Arc < MessageQueue > ,
375390 Arc < EventQueue > ,
376391 PublicKey ,
377392 PublicKey ,
378393 ) {
379- let test_entropy_source = Arc :: new ( TestEntropy { } ) ;
394+ let test_entropy_source = Arc :: new ( UniqueTestEntropy { counter : AtomicU64 :: new ( 2 ) } ) ;
380395 let message_queue = Arc :: new ( MessageQueue :: new ( ) ) ;
381396 let event_queue = Arc :: new ( EventQueue :: new ( ) ) ;
382397 let client = LSPS5ClientHandler :: new (
@@ -497,4 +512,44 @@ mod tests {
497512 let error = result. unwrap_err ( ) ;
498513 assert ! ( error. err. to_lowercase( ) . contains( "unknown request id" ) ) ;
499514 }
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+ }
500555}
0 commit comments