From b00376e58ebd393bea1d53f5f21e9f5672475b52 Mon Sep 17 00:00:00 2001 From: shaavan Date: Fri, 3 Jan 2025 19:10:23 +0530 Subject: [PATCH 1/2] Introduce get_and_clear_pending_raa_blockers Note: The `actions_blocking_raa_monitor_updates` list may contain stale entries in the form of `(channel_id, [])`, which do not represent actual dangling actions. To handle this, stale entries are ignored when accumulating pending actions before clearing them. This ensures that the logic focuses only on relevant actions and avoids unnecessary accumulation of already processed data. --- lightning/src/ln/channelmanager.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index a5ae07eab7f..9d85f058729 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -10600,6 +10600,29 @@ where self.pending_outbound_payments.clear_pending_payments() } + #[cfg(any(test, feature = "_test_utils"))] + pub(crate) fn get_and_clear_pending_raa_blockers( + &self, + ) -> Vec<(ChannelId, Vec)> { + let per_peer_state = self.per_peer_state.read().unwrap(); + let mut pending_blockers = Vec::new(); + + for (_peer_pubkey, peer_state_mutex) in per_peer_state.iter() { + let mut peer_state = peer_state_mutex.lock().unwrap(); + + for (chan_id, actions) in peer_state.actions_blocking_raa_monitor_updates.iter() { + // Only collect the non-empty actions into `pending_blockers`. + if !actions.is_empty() { + pending_blockers.push((chan_id.clone(), actions.clone())); + } + } + + peer_state.actions_blocking_raa_monitor_updates.clear(); + } + + pending_blockers + } + /// When something which was blocking a channel from updating its [`ChannelMonitor`] (e.g. an /// [`Event`] being handled) completes, this should be called to restore the channel to normal /// operation. It will double-check that nothing *else* is also blocking the same channel from From 1d95abeb54e9ff86fa559d0e52322111f3410ba8 Mon Sep 17 00:00:00 2001 From: shaavan Date: Fri, 3 Jan 2025 19:50:19 +0530 Subject: [PATCH 2/2] Introduce RAA Blocker check in Node::drop() --- lightning/src/ln/chanmon_update_fail_tests.rs | 32 +++++++++++++++++-- lightning/src/ln/functional_test_utils.rs | 5 +++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index fcc1f8f5a64..078438d24ea 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -19,7 +19,7 @@ use crate::chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor}; use crate::chain::transaction::OutPoint; use crate::chain::{ChannelMonitorUpdateStatus, Listen, Watch}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose, ClosureReason, HTLCDestination}; -use crate::ln::channelmanager::{RAACommitmentOrder, PaymentSendFailure, PaymentId, RecipientOnionFields}; +use crate::ln::channelmanager::{PaymentId, PaymentSendFailure, RAACommitmentOrder, RAAMonitorUpdateBlockingAction, RecipientOnionFields}; use crate::ln::channel::{AnnouncementSigsState, ChannelPhase}; use crate::ln::msgs; use crate::ln::types::ChannelId; @@ -3333,6 +3333,19 @@ fn do_test_durable_preimages_on_closed_channel(close_chans_before_reload: bool, check_added_monitors(&nodes[1], 1); assert!(nodes[1].node.get_and_clear_pending_events().is_empty()); send_payment(&nodes[1], &[&nodes[2]], 100_000); + } else { + // Handle RAA blockers on nodes[1] + let raa_blockers = nodes[1].node.get_and_clear_pending_raa_blockers(); + assert_eq!(raa_blockers.len(), 1); + let (chan_id, blockers) = &raa_blockers[0]; + assert_eq!(*chan_id, chan_id_bc); + assert_eq!(blockers.len(), 1); + match blockers[0] { + RAAMonitorUpdateBlockingAction::ForwardedPaymentInboundClaim { channel_id, .. } => { + assert_eq!(channel_id, chan_id_ab); + } + _ => panic!("Unexpected RAA blocker") + } } } @@ -3548,8 +3561,8 @@ fn do_test_glacial_peer_cant_hang(hold_chan_a: bool) { let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs); - create_announced_chan_between_nodes(&nodes, 0, 1); - create_announced_chan_between_nodes(&nodes, 1, 2); + let chan_id_ab = create_announced_chan_between_nodes(&nodes, 0, 1).2; + let chan_id_bc = create_announced_chan_between_nodes(&nodes, 1, 2).2; // Route a payment from A, through B, to C, then claim it on C. Replay the // `update_fulfill_htlc` twice on B to check that B doesn't hang. @@ -3596,6 +3609,19 @@ fn do_test_glacial_peer_cant_hang(hold_chan_a: bool) { assert!(nodes[1].node.get_and_clear_pending_events().is_empty()); assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); + + // Handle RAA blockers on nodes[1] + let raa_blockers = nodes[1].node.get_and_clear_pending_raa_blockers(); + assert_eq!(raa_blockers.len(), 1); + let (chan_id, blockers) = &raa_blockers[0]; + assert_eq!(*chan_id, chan_id_bc); + assert_eq!(blockers.len(), 1); + match blockers[0] { + RAAMonitorUpdateBlockingAction::ForwardedPaymentInboundClaim { channel_id, .. } => { + assert_eq!(channel_id, chan_id_ab); + } + _ => panic!("Unexpected RAA blocker") + } } } diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index b4f172b4a27..ba5cb65e49f 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -652,6 +652,11 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { panic!("Had {} excess added monitors on node {}", added_monitors.len(), self.logger.id); } + let raa_blockers = self.node.get_and_clear_pending_raa_blockers(); + if !raa_blockers.is_empty() { + panic!( "Had excess RAA blockers on node {}: {:?}", self.logger.id, raa_blockers); + } + // Check that if we serialize the network graph, we can deserialize it again. let network_graph = { let mut w = test_utils::TestVecWriter(Vec::new());