diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index 971cdaa208e..a0634759d2f 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -669,6 +669,12 @@ where C::Target: chain::Filter, } } + fn get_latest_holder_commitment_txn(&self, funding_txo: OutPoint) -> Vec { + let monitors = self.monitors.read().unwrap(); + let monitor = monitors.get(&funding_txo).expect("To have a monitor for the requested channel"); + monitor.monitor.get_latest_holder_commitment_txn_internal(&self.logger) + } + /// Note that we persist the given `ChannelMonitor` update while holding the /// `ChainMonitor` monitors lock. fn update_channel(&self, funding_txo: OutPoint, update: &ChannelMonitorUpdate) -> ChannelMonitorUpdateStatus { diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 4286370fadb..bca6a84e012 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -1357,6 +1357,11 @@ impl ChannelMonitor { self.inner.lock().unwrap().get_latest_holder_commitment_txn(logger) } + pub(crate) fn get_latest_holder_commitment_txn_internal(&self, logger: &L) -> Vec + where L::Target: Logger { + self.inner.lock().unwrap().get_latest_holder_commitment_txn_internal(logger) + } + /// Unsafe test-only version of get_latest_holder_commitment_txn used by our test framework /// to bypass HolderCommitmentTransaction state update lockdown after signature and generate /// revoked commitment transaction. @@ -2848,8 +2853,12 @@ impl ChannelMonitorImpl { } pub fn get_latest_holder_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { - log_debug!(logger, "Getting signed latest holder commitment transaction!"); self.holder_tx_signed = true; + self.get_latest_holder_commitment_txn_internal(logger) + } + + pub(crate) fn get_latest_holder_commitment_txn_internal(&mut self, logger: &L) -> Vec where L::Target: Logger { + log_debug!(logger, "Getting signed latest holder commitment transaction!"); let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript); let txid = commitment_tx.txid(); let mut holder_transactions = vec![commitment_tx]; diff --git a/lightning/src/chain/mod.rs b/lightning/src/chain/mod.rs index e6239d7311c..3d822b4fb35 100644 --- a/lightning/src/chain/mod.rs +++ b/lightning/src/chain/mod.rs @@ -299,6 +299,9 @@ pub trait Watch { /// Update the outpoint funding the channel. fn update_channel_funding_txo(&self, old_funding_txo: OutPoint, new_funding_txo: OutPoint, channel_value_satoshis: u64) -> ChannelMonitorUpdateStatus; + /// Get the latest commitment transaction to broadcast + fn get_latest_holder_commitment_txn(&self, funding_txo: OutPoint) -> Vec; + /// Returns any monitor events since the last call. Subsequent calls must only return new /// events. /// diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 6d1d939aff4..1b433e3e655 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -5119,8 +5119,22 @@ impl Channel { return Ok((Some(channel_ready), announcement_sigs)); } } + + let original_funding_outpoint = self.get_original_funding_txo().map(|x| x.into_bitcoin_outpoint()); + let funding_bitcoin_outpoint = funding_txo.into_bitcoin_outpoint(); + let funding_match = |prev_outpoint: &bitcoin::OutPoint| -> bool { + prev_outpoint == &funding_bitcoin_outpoint + }; + let original_funding_match = |prev_outpoint: &bitcoin::OutPoint, outputs: &[bitcoin::TxOut]| -> bool { + if let Some(original_funding_outpoint) = original_funding_outpoint { + // We want to filter for the split tx which is not closing the LN channel. + prev_outpoint == &original_funding_outpoint && !(outputs.len() == 2 && outputs[0].script_pubkey == outputs[1].script_pubkey) + } else { + false + } + }; for inp in tx.input.iter() { - if inp.previous_output == funding_txo.into_bitcoin_outpoint() { + if funding_match(&inp.previous_output) || original_funding_match(&inp.previous_output, &tx.output) { log_info!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(self.channel_id())); return Err(ClosureReason::CommitmentTxConfirmed); } diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 9cc73611bbb..81cf8d23e89 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -2012,6 +2012,15 @@ where let chan = &mut channel_lock.channel; chan.set_funding_outpoint(funding_outpoint, channel_value, own_balance, false, &self.logger); + if ChannelMonitorUpdateStatus::Completed != self.chain_monitor.update_channel_funding_txo(chan.get_original_funding_txo().unwrap(), *funding_outpoint, channel_value) { + log_error!(self.logger, "Error setting funding txo on chain monitor"); + } + } + + fn get_latest_holder_commitment_txn_internal(&self, channel_lock: &ChannelLock<::Signer>) -> Vec { + let chan = &channel_lock.channel; + + self.chain_monitor.get_latest_holder_commitment_txn(chan.get_original_funding_txo().expect("To have a funding txo")) } fn close_channel_internal(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option) -> Result<(), APIError> { @@ -2143,6 +2152,11 @@ where self.set_funding_outpoint_internal(channel_lock, funding_output, channel_value_satoshis, value_to_self_msat); } + /// + pub fn get_latest_holder_commitment_txn(&self, channel_lock: &ChannelLock<::Signer>) -> Vec { + self.get_latest_holder_commitment_txn_internal(channel_lock) + } + #[inline] fn finish_force_close_channel(&self, shutdown_res: ShutdownResult) { let (monitor_update_option, mut failed_htlcs) = shutdown_res;