From 1955008d6d1322733039cea486691fe00af094e7 Mon Sep 17 00:00:00 2001 From: 1nF0rmed Date: Mon, 27 Sep 2021 22:20:07 +0530 Subject: [PATCH] Adds DiscardFunding event During the event of a channel close, if the funding transaction is yet to be broadcasted then a DiscardFunding event is issued along with the ChannelClose event. --- lightning/src/ln/channel.rs | 9 +++++ lightning/src/ln/channelmanager.rs | 41 ++++++++++++----------- lightning/src/ln/functional_test_utils.rs | 12 +++++-- lightning/src/ln/functional_tests.rs | 2 +- lightning/src/util/events.rs | 25 ++++++++++++++ 5 files changed, 66 insertions(+), 23 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 858e307b7..936bbab7c 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1901,6 +1901,15 @@ impl Channel { Ok(()) } + /// Returns transaction if there is pending funding transaction that is yet to broadcast + pub fn unbroadcasted_funding(&self) -> Option { + if self.channel_state & (ChannelState::FundingCreated as u32) != 0 { + self.funding_transaction.clone() + } else { + None + } + } + /// Returns a HTLCStats about inbound pending htlcs fn get_inbound_pending_htlc_stats(&self) -> HTLCStats { let mut stats = HTLCStats { diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index a4684bfe6..5e43158b1 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -1326,6 +1326,18 @@ impl ChannelMana self.list_channels_with_filter(|&(_, ref channel)| channel.is_live()) } + /// Helper function that issues the channel close events + fn issue_channel_close_events(&self, channel: &Channel, closure_reason: ClosureReason) { + let mut pending_events_lock = self.pending_events.lock().unwrap(); + match channel.unbroadcasted_funding() { + Some(transaction) => { + pending_events_lock.push(events::Event::DiscardFunding { channel_id: channel.channel_id(), transaction }) + }, + None => {}, + } + pending_events_lock.push(events::Event::ChannelClosed { channel_id: channel.channel_id(), reason: closure_reason }); + } + fn close_channel_internal(&self, channel_id: &[u8; 32], target_feerate_sats_per_1000_weight: Option) -> Result<(), APIError> { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); @@ -1372,12 +1384,7 @@ impl ChannelMana msg: channel_update }); } - if let Ok(mut pending_events_lock) = self.pending_events.lock() { - pending_events_lock.push(events::Event::ChannelClosed { - channel_id: *channel_id, - reason: ClosureReason::HolderForceClosed - }); - } + self.issue_channel_close_events(&channel, ClosureReason::HolderForceClosed); } break Ok(()); }, @@ -1468,13 +1475,12 @@ impl ChannelMana if let Some(short_id) = chan.get().get_short_channel_id() { channel_state.short_to_id.remove(&short_id); } - let mut pending_events_lock = self.pending_events.lock().unwrap(); if peer_node_id.is_some() { if let Some(peer_msg) = peer_msg { - pending_events_lock.push(events::Event::ChannelClosed { channel_id: *channel_id, reason: ClosureReason::CounterpartyForceClosed { peer_msg: peer_msg.to_string() } }); + self.issue_channel_close_events(chan.get(),ClosureReason::CounterpartyForceClosed { peer_msg: peer_msg.to_string() }); } } else { - pending_events_lock.push(events::Event::ChannelClosed { channel_id: *channel_id, reason: ClosureReason::HolderForceClosed }); + self.issue_channel_close_events(chan.get(),ClosureReason::HolderForceClosed); } chan.remove_entry().1 } else { @@ -3574,7 +3580,7 @@ impl ChannelMana msg: update }); } - self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: msg.channel_id, reason: ClosureReason::CooperativeClosure }); + self.issue_channel_close_events(&chan, ClosureReason::CooperativeClosure); } Ok(()) } @@ -3986,7 +3992,7 @@ impl ChannelMana msg: update }); } - self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: chan.channel_id(), reason: ClosureReason::CommitmentTxConfirmed }); + self.issue_channel_close_events(&chan, ClosureReason::CommitmentTxConfirmed); pending_msg_events.push(events::MessageSendEvent::HandleError { node_id: chan.get_counterparty_node_id(), action: msgs::ErrorAction::SendErrorMessage { @@ -4102,12 +4108,7 @@ impl ChannelMana }); } - if let Ok(mut pending_events_lock) = self.pending_events.lock() { - pending_events_lock.push(events::Event::ChannelClosed { - channel_id: *channel_id, - reason: ClosureReason::CooperativeClosure - }); - } + self.issue_channel_close_events(chan, ClosureReason::CooperativeClosure); log_info!(self.logger, "Broadcasting {}", log_tx!(tx)); self.tx_broadcaster.broadcast_transaction(&tx); @@ -4529,7 +4530,7 @@ where msg: update }); } - self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: channel.channel_id(), reason: ClosureReason::CommitmentTxConfirmed }); + self.issue_channel_close_events(channel, ClosureReason::CommitmentTxConfirmed); pending_msg_events.push(events::MessageSendEvent::HandleError { node_id: channel.get_counterparty_node_id(), action: msgs::ErrorAction::SendErrorMessage { msg: e }, @@ -4720,7 +4721,7 @@ impl msg: update }); } - self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: chan.channel_id(), reason: ClosureReason::DisconnectedPeer }); + self.issue_channel_close_events(chan, ClosureReason::DisconnectedPeer); false } else { true @@ -4735,7 +4736,7 @@ impl if let Some(short_id) = chan.get_short_channel_id() { short_to_id.remove(&short_id); } - self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: chan.channel_id(), reason: ClosureReason::DisconnectedPeer }); + self.issue_channel_close_events(chan, ClosureReason::DisconnectedPeer); return false; } else { no_channels_remain = false; diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 9fbbcfff3..92aaee100 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -763,21 +763,29 @@ macro_rules! check_closed_broadcast { }} } -/// Check that a channel's closing channel event has been issued +/// Check that a channel's closing channel events has been issued #[macro_export] macro_rules! check_closed_event { - ($node: expr, $events: expr, $reason: expr) => {{ + ($node: expr, $events: expr, $reason: expr) => { + check_closed_event!($node, $events, $reason, false); + }; + ($node: expr, $events: expr, $reason: expr, $is_check_discard_funding: expr) => {{ let events = $node.node.get_and_clear_pending_events(); assert_eq!(events.len(), $events); let expected_reason = $reason; + let mut issues_discard_funding = false; for event in events { match event { Event::ChannelClosed { ref reason, .. } => { assert_eq!(*reason, expected_reason); }, + Event::DiscardFunding { .. } => { + issues_discard_funding = true; + } _ => panic!("Unexpected event"), } } + assert_eq!($is_check_discard_funding, issues_discard_funding); }} } diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 03b62ac18..76d4eda13 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -8632,7 +8632,7 @@ fn test_pre_lockin_no_chan_closed_update() { let channel_id = ::chain::transaction::OutPoint { txid: funding_created_msg.funding_txid, index: funding_created_msg.funding_output_index }.to_channel_id(); nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id, data: "Hi".to_owned() }); assert!(nodes[0].chain_monitor.added_monitors.lock().unwrap().is_empty()); - check_closed_event!(nodes[0], 1, ClosureReason::CounterpartyForceClosed { peer_msg: "Hi".to_string() }); + check_closed_event!(nodes[0], 2, ClosureReason::CounterpartyForceClosed { peer_msg: "Hi".to_string() }, true); } #[test] diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index 1319f7d21..7da4781ac 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -30,6 +30,7 @@ use io; use prelude::*; use core::time::Duration; use core::ops::Deref; +use bitcoin::Transaction; /// Some information provided on receipt of payment depends on whether the payment received is a /// spontaneous payment or a "conventional" lightning payment that's paying an invoice. @@ -254,6 +255,14 @@ pub enum Event { channel_id: [u8; 32], /// The reason the channel was closed. reason: ClosureReason + }, + /// Used to indicate to the user that they can abandon the funding transaction and recycle the + /// inputs for another purpose. + DiscardFunding { + /// The channel_id of the channel which has been closed. + channel_id: [u8; 32], + /// The full transaction received from the user + transaction: Transaction } } @@ -340,6 +349,13 @@ impl Writeable for Event { (2, reason, required) }); }, + &Event::DiscardFunding { ref channel_id, ref transaction } => { + 11u8.write(writer)?; + write_tlv_fields!(writer, { + (0, channel_id, required), + (2, transaction, required) + }) + }, // Note that, going forward, all new events must only write data inside of // `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write // data via `write_tlv_fields`. @@ -471,6 +487,15 @@ impl MaybeReadable for Event { if reason.is_none() { return Ok(None); } Ok(Some(Event::ChannelClosed { channel_id, reason: reason.unwrap() })) }, + 11u8 => { + let mut channel_id = [0; 32]; + let mut transaction = Transaction{ version: 2, lock_time: 0, input: Vec::new(), output: Vec::new() }; + read_tlv_fields!(reader, { + (0, channel_id, required), + (2, transaction, required), + }); + Ok(Some(Event::DiscardFunding { channel_id, transaction } )) + }, // Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue. // Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt // reads. -- 2.39.5