@@ -632,17 +632,20 @@ impl PeerState {
632632 } ) ;
633633 }
634634
635- fn prune_expired_request_state ( & mut self ) {
635+ fn prune_expired_request_state ( & mut self ) -> Vec < u64 > {
636+ let mut pruned_scids = Vec :: new ( ) ;
636637 self . outbound_channels_by_intercept_scid . retain ( |intercept_scid, entry| {
637638 if entry. is_prunable ( ) {
638639 // We abort the flow, and prune any data kept.
639640 self . intercept_scid_by_channel_id . retain ( |_, iscid| intercept_scid != iscid) ;
640641 self . intercept_scid_by_user_channel_id . retain ( |_, iscid| intercept_scid != iscid) ;
641642 self . needs_persist |= true ;
643+ pruned_scids. push ( * intercept_scid) ;
642644 return false ;
643645 }
644646 true
645647 } ) ;
648+ pruned_scids
646649 }
647650
648651 fn pending_requests_and_channels ( & self ) -> usize {
@@ -788,6 +791,29 @@ where
788791 & self . config
789792 }
790793
794+ /// Cleans up `peer_by_intercept_scid` entries for the given SCIDs, and deregisters the peer
795+ /// from onion message interception if they have no remaining active intercept SCIDs.
796+ fn cleanup_intercept_scids (
797+ & self , counterparty_node_id : & PublicKey , pruned_scids : & [ u64 ] , has_remaining_channels : bool ,
798+ ) {
799+ if pruned_scids. is_empty ( ) {
800+ return ;
801+ }
802+
803+ {
804+ let mut peer_by_intercept_scid = self . peer_by_intercept_scid . write ( ) . unwrap ( ) ;
805+ for scid in pruned_scids {
806+ peer_by_intercept_scid. remove ( scid) ;
807+ }
808+ }
809+
810+ if !has_remaining_channels {
811+ if let Some ( ref interceptor) = self . onion_message_interceptor {
812+ interceptor. deregister_peer_for_interception ( counterparty_node_id) ;
813+ }
814+ }
815+ }
816+
791817 /// Returns whether the peer has any active LSPS2 requests.
792818 pub ( crate ) fn has_active_requests ( & self , counterparty_node_id : & PublicKey ) -> bool {
793819 let outer_state_lock = self . per_peer_state . read ( ) . unwrap ( ) ;
@@ -1067,7 +1093,15 @@ where
10671093 peer_state
10681094 . outbound_channels_by_intercept_scid
10691095 . remove ( & intercept_scid) ;
1070- // TODO: cleanup peer_by_intercept_scid
1096+ let has_remaining =
1097+ !peer_state. outbound_channels_by_intercept_scid . is_empty ( ) ;
1098+ drop ( peer_state) ;
1099+ drop ( outer_state_lock) ;
1100+ self . cleanup_intercept_scids (
1101+ counterparty_node_id,
1102+ & [ intercept_scid] ,
1103+ has_remaining,
1104+ ) ;
10711105 return Err ( APIError :: APIMisuseError { err : e. err } ) ;
10721106 } ,
10731107 }
@@ -1286,7 +1320,7 @@ where
12861320 pub async fn channel_open_abandoned (
12871321 & self , counterparty_node_id : & PublicKey , user_channel_id : u128 ,
12881322 ) -> Result < ( ) , APIError > {
1289- {
1323+ let ( intercept_scid , has_remaining ) = {
12901324 let outer_state_lock = self . per_peer_state . read ( ) . unwrap ( ) ;
12911325 let inner_state_lock = outer_state_lock. get ( counterparty_node_id) . ok_or_else ( || {
12921326 APIError :: APIMisuseError {
@@ -1333,7 +1367,11 @@ where
13331367 peer_state. outbound_channels_by_intercept_scid . remove ( & intercept_scid) ;
13341368 peer_state. intercept_scid_by_channel_id . retain ( |_, & mut scid| scid != intercept_scid) ;
13351369 peer_state. needs_persist |= true ;
1336- }
1370+ let has_remaining = !peer_state. outbound_channels_by_intercept_scid . is_empty ( ) ;
1371+ ( intercept_scid, has_remaining)
1372+ } ;
1373+
1374+ self . cleanup_intercept_scids ( counterparty_node_id, & [ intercept_scid] , has_remaining) ;
13371375
13381376 self . persist_peer_state ( * counterparty_node_id) . await . map_err ( |e| {
13391377 APIError :: APIMisuseError {
@@ -1817,17 +1855,32 @@ where
18171855 {
18181856 // First build a list of peers to persist and prune with the read lock. This allows
18191857 // us to avoid the write lock unless we actually need to remove a node.
1858+ let mut all_pruned_scids = Vec :: new ( ) ;
18201859 let outer_state_lock = self . per_peer_state . read ( ) . unwrap ( ) ;
18211860 for ( counterparty_node_id, inner_state_lock) in outer_state_lock. iter ( ) {
18221861 let mut peer_state_lock = inner_state_lock. lock ( ) . unwrap ( ) ;
1823- peer_state_lock. prune_expired_request_state ( ) ;
1862+ let pruned_scids = peer_state_lock. prune_expired_request_state ( ) ;
1863+ if !pruned_scids. is_empty ( ) {
1864+ let has_remaining =
1865+ !peer_state_lock. outbound_channels_by_intercept_scid . is_empty ( ) ;
1866+ all_pruned_scids. push ( ( * counterparty_node_id, pruned_scids, has_remaining) ) ;
1867+ }
18241868 let is_prunable = peer_state_lock. is_prunable ( ) ;
18251869 if is_prunable {
18261870 need_remove. push ( * counterparty_node_id) ;
18271871 } else if peer_state_lock. needs_persist {
18281872 need_persist. push ( * counterparty_node_id) ;
18291873 }
18301874 }
1875+ drop ( outer_state_lock) ;
1876+
1877+ for ( counterparty_node_id, pruned_scids, has_remaining) in all_pruned_scids {
1878+ self . cleanup_intercept_scids (
1879+ & counterparty_node_id,
1880+ & pruned_scids,
1881+ has_remaining,
1882+ ) ;
1883+ }
18311884 }
18321885
18331886 for counterparty_node_id in need_persist. into_iter ( ) {
@@ -1838,6 +1891,7 @@ where
18381891
18391892 for counterparty_node_id in need_remove {
18401893 let mut future_opt = None ;
1894+ let mut was_removed = false ;
18411895 {
18421896 // We need to take the `per_peer_state` write lock to remove an entry, but also
18431897 // have to hold it until after the `remove` call returns (but not through
@@ -1849,6 +1903,7 @@ where
18491903 let state = entry. get_mut ( ) . get_mut ( ) . unwrap ( ) ;
18501904 if state. is_prunable ( ) {
18511905 entry. remove ( ) ;
1906+ was_removed = true ;
18521907 let key = counterparty_node_id. to_string ( ) ;
18531908 future_opt = Some ( self . kv_store . remove (
18541909 LIQUIDITY_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE ,
@@ -1866,6 +1921,20 @@ where
18661921 debug_assert ! ( false ) ;
18671922 }
18681923 }
1924+ if was_removed {
1925+ // Clean up handler-level maps for the removed peer.
1926+ self . peer_by_intercept_scid
1927+ . write ( )
1928+ . unwrap ( )
1929+ . retain ( |_, node_id| * node_id != counterparty_node_id) ;
1930+ self . peer_by_channel_id
1931+ . write ( )
1932+ . unwrap ( )
1933+ . retain ( |_, node_id| * node_id != counterparty_node_id) ;
1934+ if let Some ( ref interceptor) = self . onion_message_interceptor {
1935+ interceptor. deregister_peer_for_interception ( & counterparty_node_id) ;
1936+ }
1937+ }
18691938 if let Some ( future) = future_opt {
18701939 future. await ?;
18711940 did_persist = true ;
@@ -1893,7 +1962,11 @@ where
18931962 // We clean up the peer state, but leave removing the peer entry to the prune logic in
18941963 // `persist` which removes it from the store.
18951964 peer_state_lock. prune_pending_requests ( ) ;
1896- peer_state_lock. prune_expired_request_state ( ) ;
1965+ let pruned_scids = peer_state_lock. prune_expired_request_state ( ) ;
1966+ let has_remaining = !peer_state_lock. outbound_channels_by_intercept_scid . is_empty ( ) ;
1967+ drop ( peer_state_lock) ;
1968+ drop ( outer_state_lock) ;
1969+ self . cleanup_intercept_scids ( & counterparty_node_id, & pruned_scids, has_remaining) ;
18971970 }
18981971 }
18991972
0 commit comments