From efaba118da42431fb64e0ee23111b333ad3b3a87 Mon Sep 17 00:00:00 2001 From: optout <13562139+optout21@users.noreply.github.com> Date: Thu, 11 Jan 2024 09:15:53 +0100 Subject: [PATCH] Add channel funding txo to Channel Event::ChannelClosed --- lightning/src/events/mod.rs | 14 +++++++++++--- lightning/src/ln/channel.rs | 4 ++++ lightning/src/ln/channelmanager.rs | 3 +++ lightning/src/ln/functional_test_utils.rs | 18 ++++++++++++++++-- lightning/src/ln/functional_tests.rs | 20 ++++++++++++++++---- 5 files changed, 50 insertions(+), 9 deletions(-) diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index 76e5f25c0e5..b3aa79fca88 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -24,6 +24,7 @@ use crate::ln::channel::FUNDING_CONF_DEADLINE_BLOCKS; use crate::ln::features::ChannelTypeFeatures; use crate::ln::msgs; use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret}; +use crate::chain::transaction; use crate::routing::gossip::NetworkUpdate; use crate::util::errors::APIError; use crate::util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, RequiredWrapper, UpgradableRequired, WithoutLength}; @@ -861,7 +862,7 @@ pub enum Event { /// /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels - ChannelClosed { + ChannelClosed { /// The `channel_id` of the channel which has been closed. Note that on-chain transactions /// resolving the channel are likely still awaiting confirmation. channel_id: ChannelId, @@ -886,6 +887,10 @@ pub enum Event { /// /// This field will be `None` for objects serialized prior to LDK 0.0.117. channel_capacity_sats: Option, + /// The original channel funding TXO; this helps checking for the existence and confirmation + /// status of the closing tx. + /// Note that for instances serialized in v0.0.119 or prior this will be missing (None). + channel_funding_txo: Option, }, /// Used to indicate to the user that they can abandon the funding transaction and recycle the /// inputs for another purpose. @@ -1091,7 +1096,7 @@ impl Writeable for Event { }); }, &Event::ChannelClosed { ref channel_id, ref user_channel_id, ref reason, - ref counterparty_node_id, ref channel_capacity_sats + ref counterparty_node_id, ref channel_capacity_sats, ref channel_funding_txo } => { 9u8.write(writer)?; // `user_channel_id` used to be a single u64 value. In order to remain backwards @@ -1106,6 +1111,7 @@ impl Writeable for Event { (3, user_channel_id_high, required), (5, counterparty_node_id, option), (7, channel_capacity_sats, option), + (9, channel_funding_txo, option), }); }, &Event::DiscardFunding { ref channel_id, ref transaction } => { @@ -1405,6 +1411,7 @@ impl MaybeReadable for Event { let mut user_channel_id_high_opt: Option = None; let mut counterparty_node_id = None; let mut channel_capacity_sats = None; + let mut channel_funding_txo = None; read_tlv_fields!(reader, { (0, channel_id, required), (1, user_channel_id_low_opt, option), @@ -1412,6 +1419,7 @@ impl MaybeReadable for Event { (3, user_channel_id_high_opt, option), (5, counterparty_node_id, option), (7, channel_capacity_sats, option), + (9, channel_funding_txo, option), }); // `user_channel_id` used to be a single u64 value. In order to remain @@ -1421,7 +1429,7 @@ impl MaybeReadable for Event { ((user_channel_id_high_opt.unwrap_or(0) as u128) << 64); Ok(Some(Event::ChannelClosed { channel_id, user_channel_id, reason: _init_tlv_based_struct_field!(reason, upgradable_required), - counterparty_node_id, channel_capacity_sats })) + counterparty_node_id, channel_capacity_sats, channel_funding_txo })) }; f() }, diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 7026ab6d376..8e389d3a816 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -827,6 +827,7 @@ pub(crate) struct ShutdownResult { pub(crate) channel_capacity_satoshis: u64, pub(crate) counterparty_node_id: PublicKey, pub(crate) unbroadcasted_funding_tx: Option, + pub(crate) channel_funding_txo: Option, } /// If the majority of the channels funds are to the fundee and the initiator holds only just @@ -2420,6 +2421,7 @@ impl ChannelContext where SP::Target: SignerProvider { channel_capacity_satoshis: self.channel_value_satoshis, counterparty_node_id: self.counterparty_node_id, unbroadcasted_funding_tx, + channel_funding_txo: self.get_funding_txo(), } } @@ -4956,6 +4958,7 @@ impl Channel where channel_capacity_satoshis: self.context.channel_value_satoshis, counterparty_node_id: self.context.counterparty_node_id, unbroadcasted_funding_tx: self.context.unbroadcasted_funding(), + channel_funding_txo: self.context.get_funding_txo(), }; let tx = self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &sig); self.context.channel_state = ChannelState::ShutdownComplete; @@ -4990,6 +4993,7 @@ impl Channel where channel_capacity_satoshis: self.context.channel_value_satoshis, counterparty_node_id: self.context.counterparty_node_id, unbroadcasted_funding_tx: self.context.unbroadcasted_funding(), + channel_funding_txo: self.context.get_funding_txo(), }; self.context.channel_state = ChannelState::ShutdownComplete; self.context.update_time_counter += 1; diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 81b9d766d7b..b76ba3c3db7 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -2878,6 +2878,7 @@ where reason: shutdown_res.closure_reason, counterparty_node_id: Some(shutdown_res.counterparty_node_id), channel_capacity_sats: Some(shutdown_res.channel_capacity_satoshis), + channel_funding_txo: shutdown_res.channel_funding_txo, }, None)); if let Some(transaction) = shutdown_res.unbroadcasted_funding_tx { @@ -10304,6 +10305,7 @@ where reason: ClosureReason::OutdatedChannelManager, counterparty_node_id: Some(channel.context.get_counterparty_node_id()), channel_capacity_sats: Some(channel.context.get_value_satoshis()), + channel_funding_txo: channel.context.get_funding_txo(), }, None)); for (channel_htlc_source, payment_hash) in channel.inflight_htlc_sources() { let mut found_htlc = false; @@ -10357,6 +10359,7 @@ where reason: ClosureReason::DisconnectedPeer, counterparty_node_id: Some(channel.context.get_counterparty_node_id()), channel_capacity_sats: Some(channel.context.get_value_satoshis()), + channel_funding_txo: channel.context.get_funding_txo(), }, None)); } else { log_error!(logger, "Missing ChannelMonitor for channel {} needed by ChannelManager.", &channel.context.channel_id()); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 2adfe2f9379..d153a0a4c2d 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -1539,6 +1539,8 @@ pub struct ExpectedCloseEvent { pub counterparty_node_id: Option, pub discard_funding: bool, pub reason: Option, + pub channel_funding_txo: Option, + pub user_channel_id: Option, } impl ExpectedCloseEvent { @@ -1549,6 +1551,8 @@ impl ExpectedCloseEvent { counterparty_node_id: None, discard_funding, reason: Some(reason), + channel_funding_txo: None, + user_channel_id: None, } } } @@ -1567,12 +1571,20 @@ pub fn check_closed_events(node: &Node, expected_close_events: &[ExpectedCloseEv reason, counterparty_node_id, channel_capacity_sats, + channel_funding_txo, + user_channel_id, .. } if ( expected_event.channel_id.map(|expected| *channel_id == expected).unwrap_or(true) && expected_event.reason.as_ref().map(|expected| reason == expected).unwrap_or(true) && - expected_event.counterparty_node_id.map(|expected| *counterparty_node_id == Some(expected)).unwrap_or(true) && - expected_event.channel_capacity_sats.map(|expected| *channel_capacity_sats == Some(expected)).unwrap_or(true) + expected_event. + counterparty_node_id.map(|expected| *counterparty_node_id == Some(expected)).unwrap_or(true) && + expected_event.channel_capacity_sats + .map(|expected| *channel_capacity_sats == Some(expected)).unwrap_or(true) && + expected_event.channel_funding_txo + .map(|expected| *channel_funding_txo == Some(expected)).unwrap_or(true) && + expected_event.user_channel_id + .map(|expected| *user_channel_id == expected).unwrap_or(true) ) ))); } @@ -1597,6 +1609,8 @@ pub fn check_closed_event(node: &Node, events_count: usize, expected_reason: Clo counterparty_node_id: Some(*node_id), discard_funding: is_check_discard_funding, reason: Some(expected_reason.clone()), + channel_funding_txo: None, + user_channel_id: None, }).collect::>(); check_closed_events(node, expected_close_events.as_slice()); } diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 78207c57b45..59d8625b0d7 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -10687,17 +10687,23 @@ fn test_disconnect_in_funding_batch() { nodes[0].node.peer_disconnected(&nodes[2].node.get_our_node_id()); // The channels in the batch will close immediately. - let channel_id_1 = OutPoint { txid: tx.txid(), index: 0 }.to_channel_id(); - let channel_id_2 = OutPoint { txid: tx.txid(), index: 1 }.to_channel_id(); + let funding_txo_1 = OutPoint { txid: tx.txid(), index: 0 }; + let funding_txo_2 = OutPoint { txid: tx.txid(), index: 1 }; + let channel_id_1 = funding_txo_1.to_channel_id(); + let channel_id_2 = funding_txo_2.to_channel_id(); check_closed_events(&nodes[0], &[ ExpectedCloseEvent { channel_id: Some(channel_id_1), discard_funding: true, + channel_funding_txo: Some(funding_txo_1), + user_channel_id: Some(42), ..Default::default() }, ExpectedCloseEvent { channel_id: Some(channel_id_2), discard_funding: true, + channel_funding_txo: Some(funding_txo_2), + user_channel_id: Some(43), ..Default::default() }, ]); @@ -10755,8 +10761,10 @@ fn test_batch_funding_close_after_funding_signed() { assert_eq!(nodes[0].tx_broadcaster.txn_broadcast().len(), 0); // Force-close the channel for which we've completed the initial monitor. - let channel_id_1 = OutPoint { txid: tx.txid(), index: 0 }.to_channel_id(); - let channel_id_2 = OutPoint { txid: tx.txid(), index: 1 }.to_channel_id(); + let funding_txo_1 = OutPoint { txid: tx.txid(), index: 0 }; + let funding_txo_2 = OutPoint { txid: tx.txid(), index: 1 }; + let channel_id_1 = funding_txo_1.to_channel_id(); + let channel_id_2 = funding_txo_2.to_channel_id(); nodes[0].node.force_close_broadcasting_latest_txn(&channel_id_1, &nodes[1].node.get_our_node_id()).unwrap(); check_added_monitors(&nodes[0], 2); { @@ -10788,11 +10796,15 @@ fn test_batch_funding_close_after_funding_signed() { ExpectedCloseEvent { channel_id: Some(channel_id_1), discard_funding: true, + channel_funding_txo: Some(funding_txo_1), + user_channel_id: Some(42), ..Default::default() }, ExpectedCloseEvent { channel_id: Some(channel_id_2), discard_funding: true, + channel_funding_txo: Some(funding_txo_2), + user_channel_id: Some(43), ..Default::default() }, ]);