@@ -56,6 +56,12 @@ impl PeerState {
5656 pending_remove_webhook_requests : BoundedMap :: new ( MAX_PENDING_REQUESTS ) ,
5757 }
5858 }
59+
60+ fn is_empty ( & self ) -> bool {
61+ self . pending_set_webhook_requests . is_empty ( )
62+ && self . pending_list_webhooks_requests . is_empty ( )
63+ && self . pending_remove_webhook_requests . is_empty ( )
64+ }
5965}
6066
6167/// Client-side handler for the LSPS5 (bLIP-55) webhook registration protocol.
@@ -345,8 +351,26 @@ where
345351 }
346352 } ;
347353 self . with_peer_state ( * counterparty_node_id, handle_response) ;
354+
355+ self . check_and_remove_empty_peer_state ( counterparty_node_id) ;
356+
348357 result
349358 }
359+
360+ fn check_and_remove_empty_peer_state ( & self , counterparty_node_id : & PublicKey ) {
361+ let mut outer_state_lock = self . per_peer_state . write ( ) . unwrap ( ) ;
362+ let should_remove =
363+ if let Some ( peer_state_mutex) = outer_state_lock. get ( counterparty_node_id) {
364+ let peer_state = peer_state_mutex. lock ( ) . unwrap ( ) ;
365+ peer_state. is_empty ( )
366+ } else {
367+ false
368+ } ;
369+
370+ if should_remove {
371+ outer_state_lock. remove ( counterparty_node_id) ;
372+ }
373+ }
350374}
351375
352376impl < ES : Deref > LSPSProtocolMessageHandler for LSPS5ClientHandler < ES >
@@ -461,36 +485,6 @@ mod tests {
461485 }
462486 }
463487
464- #[ test]
465- fn test_handle_response_clears_pending_state ( ) {
466- let ( client, _, _, peer, _) = setup_test_client ( ) ;
467-
468- let req_id = client
469- . set_webhook ( peer, "test-app" . to_string ( ) , "https://example.com/hook" . to_string ( ) )
470- . unwrap ( ) ;
471-
472- let response = LSPS5Response :: SetWebhook ( SetWebhookResponse {
473- num_webhooks : 1 ,
474- max_webhooks : 5 ,
475- no_change : false ,
476- } ) ;
477- let response_msg = LSPS5Message :: Response ( req_id. clone ( ) , response) ;
478-
479- {
480- let outer_state_lock = client. per_peer_state . read ( ) . unwrap ( ) ;
481- let peer_state = outer_state_lock. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
482- assert ! ( peer_state. pending_set_webhook_requests. contains_key( & req_id) ) ;
483- }
484-
485- client. handle_message ( response_msg, & peer) . unwrap ( ) ;
486-
487- {
488- let outer_state_lock = client. per_peer_state . read ( ) . unwrap ( ) ;
489- let peer_state = outer_state_lock. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
490- assert ! ( !peer_state. pending_set_webhook_requests. contains_key( & req_id) ) ;
491- }
492- }
493-
494488 #[ test]
495489 fn test_unknown_request_id_handling ( ) {
496490 let ( client, _message_queue, _, peer, _) = setup_test_client ( ) ;
@@ -552,4 +546,68 @@ mod tests {
552546 assert ! ( peer_state. pending_set_webhook_requests. contains_key( & new_req_id) ) ;
553547 }
554548 }
549+
550+ #[ test]
551+ fn test_peer_state_cleanup_and_recreation ( ) {
552+ let ( client, _, _, peer, _) = setup_test_client ( ) ;
553+
554+ let set_webhook_req_id = client
555+ . set_webhook ( peer, "test-app" . to_string ( ) , "https://example.com/hook" . to_string ( ) )
556+ . unwrap ( ) ;
557+
558+ let list_webhooks_req_id = client. list_webhooks ( peer) ;
559+
560+ {
561+ let state = client. per_peer_state . read ( ) . unwrap ( ) ;
562+ assert ! ( state. contains_key( & peer) ) ;
563+ let peer_state = state. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
564+ assert ! ( peer_state. pending_set_webhook_requests. contains_key( & set_webhook_req_id) ) ;
565+ assert ! ( peer_state. pending_list_webhooks_requests. contains_key( & list_webhooks_req_id) ) ;
566+ }
567+
568+ let set_webhook_response = LSPS5Response :: SetWebhook ( SetWebhookResponse {
569+ num_webhooks : 1 ,
570+ max_webhooks : 5 ,
571+ no_change : false ,
572+ } ) ;
573+ let response_msg = LSPS5Message :: Response ( set_webhook_req_id. clone ( ) , set_webhook_response) ;
574+ // trigger cleanup but there is still a pending request
575+ // so the peer state should not be removed
576+ client. handle_message ( response_msg, & peer) . unwrap ( ) ;
577+
578+ {
579+ let state = client. per_peer_state . read ( ) . unwrap ( ) ;
580+ assert ! ( state. contains_key( & peer) ) ;
581+ let peer_state = state. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
582+ assert ! ( !peer_state. pending_set_webhook_requests. contains_key( & set_webhook_req_id) ) ;
583+ assert ! ( peer_state. pending_list_webhooks_requests. contains_key( & list_webhooks_req_id) ) ;
584+ }
585+
586+ let list_webhooks_response =
587+ LSPS5Response :: ListWebhooks ( crate :: lsps5:: msgs:: ListWebhooksResponse {
588+ app_names : vec ! [ ] ,
589+ max_webhooks : 5 ,
590+ } ) ;
591+ let response_msg = LSPS5Message :: Response ( list_webhooks_req_id, list_webhooks_response) ;
592+
593+ // now the pending request is handled, so the peer state should be removed
594+ client. handle_message ( response_msg, & peer) . unwrap ( ) ;
595+
596+ {
597+ let state = client. per_peer_state . read ( ) . unwrap ( ) ;
598+ assert ! ( !state. contains_key( & peer) ) ;
599+ }
600+
601+ // check that it's possible to recreate the peer state by sending a new request
602+ let new_req_id = client
603+ . set_webhook ( peer, "test-app-2" . to_string ( ) , "https://example.com/hook2" . to_string ( ) )
604+ . unwrap ( ) ;
605+
606+ {
607+ let state = client. per_peer_state . read ( ) . unwrap ( ) ;
608+ assert ! ( state. contains_key( & peer) ) ;
609+ let peer_state = state. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
610+ assert ! ( peer_state. pending_set_webhook_requests. contains_key( & new_req_id) ) ;
611+ }
612+ }
555613}
0 commit comments