From 07c2eb5ff4f8f64f9562d4cd8c268f58ffde17cb Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 26 Jun 2025 10:06:28 -0700 Subject: [PATCH 1/2] Introduce RenegotiatedFundingLocked monitor update variant This is a new `ChannelMonitorUpdateStep` variant intended to be used whenever a new funding transaction that was negotiated and applied via the `RenegotiatedFunding` update reaches its intended confirmation depth and both sides of the channel exchange `channel_ready`/`splice_locked`. This commit primarily focuses on its use for splices, but future work will expand where needed to support RBFs for a dual funded channel. This monitor update ensures that the monitor can safely drop all prior commitment data since it is now considered invalid/unnecessary. Once the update is applied, only state for the new funding transaction is tracked going forward, until the monitor receives another `RenegotiatedFunding` update. --- lightning/src/chain/channelmonitor.rs | 51 ++++++- lightning/src/chain/onchaintx.rs | 9 ++ lightning/src/ln/channel.rs | 203 ++++++++++++++------------ lightning/src/ln/channelmanager.rs | 126 ++++++++++++---- 4 files changed, 261 insertions(+), 128 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index bfa5acc3bd5..7ff44bef1ba 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -676,6 +676,9 @@ pub(crate) enum ChannelMonitorUpdateStep { holder_commitment_tx: HolderCommitmentTransaction, counterparty_commitment_tx: CommitmentTransaction, }, + RenegotiatedFundingLocked { + funding_txid: Txid, + }, } impl ChannelMonitorUpdateStep { @@ -690,6 +693,7 @@ impl ChannelMonitorUpdateStep { ChannelMonitorUpdateStep::ChannelForceClosed { .. } => "ChannelForceClosed", ChannelMonitorUpdateStep::ShutdownScript { .. } => "ShutdownScript", ChannelMonitorUpdateStep::RenegotiatedFunding { .. } => "RenegotiatedFunding", + ChannelMonitorUpdateStep::RenegotiatedFundingLocked { .. } => "RenegotiatedFundingLocked", } } } @@ -733,6 +737,9 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep, (3, holder_commitment_tx, required), (5, counterparty_commitment_tx, required), }, + (12, RenegotiatedFundingLocked) => { + (1, funding_txid, required), + }, ); /// Indicates whether the balance is derived from a cooperative close, a force-close @@ -1075,6 +1082,10 @@ impl FundingScope { fn funding_txid(&self) -> Txid { self.funding_outpoint().txid } + + fn is_splice(&self) -> bool { + self.channel_parameters.splice_parent_funding_txid.is_some() + } } impl Writeable for FundingScope { @@ -1209,8 +1220,6 @@ pub(crate) struct ChannelMonitorImpl { // interface knows about the TXOs that we want to be notified of spends of. We could probably // be smart and derive them from the above storage fields, but its much simpler and more // Obviously Correct (tm) if we just keep track of them explicitly. - // - // TODO: Remove entries for stale funding transactions on `splice_locked`. outputs_to_watch: HashMap>, #[cfg(any(test, feature = "_test_utils"))] @@ -3670,6 +3679,10 @@ impl ChannelMonitorImpl { ); return Err(()); } + } else if self.funding.is_splice() { + // If we've already spliced at least once, we're no longer able to RBF the original + // funding transaction. + return Err(()); } self.outputs_to_watch.insert( @@ -3681,6 +3694,30 @@ impl ChannelMonitorImpl { Ok(()) } + fn promote_funding(&mut self, new_funding_txid: Txid) -> Result<(), ()> { + let new_funding = self + .pending_funding + .iter_mut() + .find(|funding| funding.funding_txid() == new_funding_txid); + if new_funding.is_none() { + return Err(()); + } + let mut new_funding = new_funding.unwrap(); + + mem::swap(&mut self.funding, &mut new_funding); + self.onchain_tx_handler.update_after_renegotiated_funding_locked( + self.funding.current_holder_commitment_tx.clone(), + self.funding.prev_holder_commitment_tx.clone(), + ); + + // The swap above places the previous `FundingScope` into `pending_funding`. + for funding in self.pending_funding.drain(..) { + self.outputs_to_watch.remove(&funding.funding_txid()); + } + + Ok(()) + } + #[rustfmt::skip] fn update_monitor( &mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &WithChannelMonitor @@ -3771,6 +3808,13 @@ impl ChannelMonitorImpl { ret = Err(()); } }, + ChannelMonitorUpdateStep::RenegotiatedFundingLocked { funding_txid } => { + log_trace!(logger, "Updating ChannelMonitor with locked renegotiated funding txid {}", funding_txid); + if let Err(_) = self.promote_funding(*funding_txid) { + log_error!(logger, "Unknown funding with txid {} became locked", funding_txid); + ret = Err(()); + } + }, ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } => { log_trace!(logger, "Updating ChannelMonitor: channel force closed, should broadcast: {}", should_broadcast); self.lockdown_from_offchain = true; @@ -3823,7 +3867,8 @@ impl ChannelMonitorImpl { |ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTX { .. } |ChannelMonitorUpdateStep::ShutdownScript { .. } |ChannelMonitorUpdateStep::CommitmentSecret { .. } - |ChannelMonitorUpdateStep::RenegotiatedFunding { .. } => + |ChannelMonitorUpdateStep::RenegotiatedFunding { .. } + |ChannelMonitorUpdateStep::RenegotiatedFundingLocked { .. } => is_pre_close_update = true, // After a channel is closed, we don't communicate with our peer about it, so the // only things we will update is getting a new preimage (from a different channel) diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index fd0f0d9abf5..89952ebee6b 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -1216,6 +1216,15 @@ impl OnchainTxHandler { self.prev_holder_commitment = Some(replace(&mut self.holder_commitment, tx)); } + /// Replaces the current/prev holder commitment transactions spending the currently confirmed + /// funding outpoint with those spending the new funding outpoint. + pub(crate) fn update_after_renegotiated_funding_locked( + &mut self, current: HolderCommitmentTransaction, prev: Option, + ) { + self.holder_commitment = current; + self.prev_holder_commitment = prev; + } + // Deprecated as of 0.2, only use in cases where it was not previously available. pub(crate) fn channel_parameters(&self) -> &ChannelTransactionParameters { &self.channel_transaction_parameters diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 56273d126ce..bf33a8bbb4c 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -6037,6 +6037,13 @@ type BestBlockUpdatedRes = ( Option, ); +#[cfg(splicing)] +pub struct SpliceFundingPromotion { + pub funding_txo: OutPoint, + pub monitor_update: Option, + pub announcement_sigs: Option, +} + impl FundedChannel where SP::Target: SignerProvider, @@ -9523,46 +9530,38 @@ where self.context.check_funding_meets_minimum_depth(funding, height) } + /// Returns `Some` if a splice [`FundingScope`] was promoted. #[cfg(splicing)] - fn maybe_promote_splice_funding( - &mut self, confirmed_funding_index: usize, logger: &L, - ) -> bool + fn maybe_promote_splice_funding( + &mut self, node_signer: &NS, chain_hash: ChainHash, user_config: &UserConfig, + block_height: u32, logger: &L, + ) -> Option where + NS::Target: NodeSigner, L::Target: Logger, { debug_assert!(self.pending_splice.is_some()); - debug_assert!(confirmed_funding_index < self.pending_funding.len()); let pending_splice = self.pending_splice.as_mut().unwrap(); let splice_txid = match pending_splice.sent_funding_txid { Some(sent_funding_txid) => sent_funding_txid, None => { debug_assert!(false); - return false; + return None; }, }; - if pending_splice.sent_funding_txid == pending_splice.received_funding_txid { - log_info!( - logger, - "Promoting splice funding txid {} for channel {}", - splice_txid, - &self.context.channel_id, - ); - - let funding = self.pending_funding.get_mut(confirmed_funding_index).unwrap(); - debug_assert_eq!(Some(splice_txid), funding.get_funding_txid()); - promote_splice_funding!(self, funding); - - return true; - } else if let Some(received_funding_txid) = pending_splice.received_funding_txid { - log_warn!( - logger, - "Mismatched splice_locked txid for channel {}; sent txid {}; received txid {}", - &self.context.channel_id, - splice_txid, - received_funding_txid, - ); + if let Some(received_funding_txid) = pending_splice.received_funding_txid { + if splice_txid != received_funding_txid { + log_warn!( + logger, + "Mismatched splice_locked txid for channel {}; sent txid {}; received txid {}", + &self.context.channel_id, + splice_txid, + received_funding_txid, + ); + return None; + } } else { log_info!( logger, @@ -9570,9 +9569,47 @@ where splice_txid, &self.context.channel_id, ); + return None; } - return false; + log_info!( + logger, + "Promoting splice funding txid {} for channel {}", + splice_txid, + &self.context.channel_id, + ); + + { + // Scope `funding` since it is swapped within `promote_splice_funding` and we don't want + // to unintentionally use it. + let funding = self + .pending_funding + .iter_mut() + .find(|funding| funding.get_funding_txid() == Some(splice_txid)) + .unwrap(); + promote_splice_funding!(self, funding); + } + + let funding_txo = self + .funding + .get_funding_txo() + .expect("Splice FundingScope should always have a funding_txo"); + + self.context.latest_monitor_update_id += 1; + let monitor_update = ChannelMonitorUpdate { + update_id: self.context.latest_monitor_update_id, + updates: vec![ChannelMonitorUpdateStep::RenegotiatedFundingLocked { + funding_txid: funding_txo.txid, + }], + channel_id: Some(self.context.channel_id()), + }; + self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new()); + let monitor_update = self.push_ret_blockable_mon_update(monitor_update); + + let announcement_sigs = + self.get_announcement_sigs(node_signer, chain_hash, user_config, block_height, logger); + + Some(SpliceFundingPromotion { funding_txo, monitor_update, announcement_sigs }) } /// When a transaction is confirmed, we check whether it is or spends the funding transaction @@ -9666,18 +9703,16 @@ where &self.context.channel_id, ); - let funding_promoted = - self.maybe_promote_splice_funding(confirmed_funding_index, logger); - let funding_txo = funding_promoted.then(|| { - self.funding - .get_funding_txo() - .expect("Splice FundingScope should always have a funding_txo") - }); - let announcement_sigs = funding_promoted - .then(|| self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger)) - .flatten(); + let (funding_txo, monitor_update, announcement_sigs) = + self.maybe_promote_splice_funding( + node_signer, chain_hash, user_config, height, logger, + ).map(|splice_promotion| ( + Some(splice_promotion.funding_txo), + splice_promotion.monitor_update, + splice_promotion.announcement_sigs, + )).unwrap_or((None, None, None)); - return Ok((Some(FundingConfirmedMessage::Splice(splice_locked, funding_txo)), announcement_sigs)); + return Ok((Some(FundingConfirmedMessage::Splice(splice_locked, funding_txo, monitor_update)), announcement_sigs)); } } @@ -9834,23 +9869,22 @@ where let funding = self.pending_funding.get(confirmed_funding_index).unwrap(); if let Some(splice_locked) = pending_splice.check_get_splice_locked(&self.context, funding, height) { log_info!(logger, "Sending a splice_locked to our peer for channel {}", &self.context.channel_id); + debug_assert!(chain_node_signer.is_some()); - let funding_promoted = - self.maybe_promote_splice_funding(confirmed_funding_index, logger); - let funding_txo = funding_promoted.then(|| { - self.funding - .get_funding_txo() - .expect("Splice FundingScope should always have a funding_txo") - }); - let announcement_sigs = funding_promoted - .then(|| chain_node_signer - .and_then(|(chain_hash, node_signer, user_config)| - self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger) - ) - ) - .flatten(); + let (funding_txo, monitor_update, announcement_sigs) = chain_node_signer + .and_then(|(chain_hash, node_signer, user_config)| { + // We can only promote on blocks connected, which is when we expect + // `chain_node_signer` to be `Some`. + self.maybe_promote_splice_funding(node_signer, chain_hash, user_config, height, logger) + }) + .map(|splice_promotion| ( + Some(splice_promotion.funding_txo), + splice_promotion.monitor_update, + splice_promotion.announcement_sigs, + )) + .unwrap_or((None, None, None)); - return Ok((Some(FundingConfirmedMessage::Splice(splice_locked, funding_txo)), timed_out_htlcs, announcement_sigs)); + return Ok((Some(FundingConfirmedMessage::Splice(splice_locked, funding_txo, monitor_update)), timed_out_htlcs, announcement_sigs)); } } @@ -10344,8 +10378,8 @@ where #[cfg(splicing)] pub fn splice_locked( &mut self, msg: &msgs::SpliceLocked, node_signer: &NS, chain_hash: ChainHash, - user_config: &UserConfig, best_block: &BestBlock, logger: &L, - ) -> Result<(Option, Option), ChannelError> + user_config: &UserConfig, block_height: u32, logger: &L, + ) -> Result, ChannelError> where NS::Target: NodeSigner, L::Target: Logger, @@ -10364,56 +10398,33 @@ where }, }; - if let Some(sent_funding_txid) = pending_splice.sent_funding_txid { - if sent_funding_txid == msg.splice_txid { - if let Some(funding) = self - .pending_funding - .iter_mut() - .find(|funding| funding.get_funding_txid() == Some(sent_funding_txid)) - { - log_info!( - logger, - "Promoting splice funding txid {} for channel {}", - msg.splice_txid, - &self.context.channel_id, - ); - promote_splice_funding!(self, funding); - let funding_txo = self - .funding - .get_funding_txo() - .expect("Splice FundingScope should always have a funding_txo"); - let announcement_sigs = self.get_announcement_sigs( - node_signer, - chain_hash, - user_config, - best_block.height, - logger, - ); - return Ok((Some(funding_txo), announcement_sigs)); - } + if !self + .pending_funding + .iter() + .any(|funding| funding.get_funding_txid() == Some(msg.splice_txid)) + { + let err = "unknown splice funding txid"; + return Err(ChannelError::close(err.to_string())); + } + pending_splice.received_funding_txid = Some(msg.splice_txid); - let err = "unknown splice funding txid"; - return Err(ChannelError::close(err.to_string())); - } else { - log_warn!( - logger, - "Mismatched splice_locked txid for channel {}; sent txid {}; received txid {}", - &self.context.channel_id, - sent_funding_txid, - msg.splice_txid, - ); - } - } else { + if pending_splice.sent_funding_txid.is_none() { log_info!( logger, "Waiting for enough confirmations to send splice_locked txid {} for channel {}", msg.splice_txid, &self.context.channel_id, ); + return Ok(None); } - pending_splice.received_funding_txid = Some(msg.splice_txid); - Ok((None, None)) + Ok(self.maybe_promote_splice_funding( + node_signer, + chain_hash, + user_config, + block_height, + logger, + )) } // Send stuff to our remote peers: diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 9e7031bf8cb..99b8efa00ed 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -10219,15 +10219,15 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ &self.node_signer, self.chain_hash, &self.default_configuration, - &self.best_block.read().unwrap(), + self.best_block.read().unwrap().height, &&logger, ); - let (funding_txo, announcement_sigs_opt) = - try_channel_entry!(self, peer_state, result, chan_entry); - - if funding_txo.is_some() { - let mut short_to_chan_info = self.short_to_chan_info.write().unwrap(); - insert_short_channel_id!(short_to_chan_info, chan); + let splice_promotion = try_channel_entry!(self, peer_state, result, chan_entry); + if let Some(splice_promotion) = splice_promotion { + { + let mut short_to_chan_info = self.short_to_chan_info.write().unwrap(); + insert_short_channel_id!(short_to_chan_info, chan); + } let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push_back(( @@ -10235,26 +10235,39 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ channel_id: chan.context.channel_id(), user_channel_id: chan.context.get_user_id(), counterparty_node_id: chan.context.get_counterparty_node_id(), - funding_txo: funding_txo - .map(|outpoint| outpoint.into_bitcoin_outpoint()), + funding_txo: Some( + splice_promotion.funding_txo.into_bitcoin_outpoint(), + ), channel_type: chan.funding.get_channel_type().clone(), }, None, )); - } - if let Some(announcement_sigs) = announcement_sigs_opt { - log_trace!( - logger, - "Sending announcement_signatures for channel {}", - chan.context.channel_id() - ); - peer_state.pending_msg_events.push( - MessageSendEvent::SendAnnouncementSignatures { - node_id: counterparty_node_id.clone(), - msg: announcement_sigs, - }, - ); + if let Some(announcement_sigs) = splice_promotion.announcement_sigs { + log_trace!( + logger, + "Sending announcement_signatures for channel {}", + chan.context.channel_id() + ); + peer_state.pending_msg_events.push( + MessageSendEvent::SendAnnouncementSignatures { + node_id: counterparty_node_id.clone(), + msg: announcement_sigs, + }, + ); + } + + if let Some(monitor_update) = splice_promotion.monitor_update { + handle_new_monitor_update!( + self, + splice_promotion.funding_txo, + monitor_update, + peer_state_lock, + peer_state, + per_peer_state, + chan + ); + } } } else { return Err(MsgHandleErrInternal::send_err_msg_no_close( @@ -12280,7 +12293,7 @@ where pub(super) enum FundingConfirmedMessage { Establishment(msgs::ChannelReady), #[cfg(splicing)] - Splice(msgs::SpliceLocked, Option), + Splice(msgs::SpliceLocked, Option, Option), } impl< @@ -12317,6 +12330,8 @@ where let mut failed_channels = Vec::new(); let mut timed_out_htlcs = Vec::new(); + #[cfg(splicing)] + let mut to_process_monitor_update_actions = Vec::new(); { let per_peer_state = self.per_peer_state.read().unwrap(); for (_cp_id, peer_state_mutex) in per_peer_state.iter() { @@ -12354,23 +12369,40 @@ where } }, #[cfg(splicing)] - Some(FundingConfirmedMessage::Splice(splice_locked, funding_txo)) => { - if funding_txo.is_some() { + Some(FundingConfirmedMessage::Splice(splice_locked, funding_txo, monitor_update_opt)) => { + let counterparty_node_id = funded_channel.context.get_counterparty_node_id(); + let channel_id = funded_channel.context.channel_id(); + + if let Some(funding_txo) = funding_txo { let mut short_to_chan_info = self.short_to_chan_info.write().unwrap(); insert_short_channel_id!(short_to_chan_info, funded_channel); + if let Some(monitor_update) = monitor_update_opt { + handle_new_monitor_update!( + self, + funding_txo, + monitor_update, + peer_state, + funded_channel.context, + REMAIN_LOCKED_UPDATE_ACTIONS_PROCESSED_LATER + ); + to_process_monitor_update_actions.push(( + counterparty_node_id, channel_id + )); + } + let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push_back((events::Event::ChannelReady { - channel_id: funded_channel.context.channel_id(), + channel_id, user_channel_id: funded_channel.context.get_user_id(), - counterparty_node_id: funded_channel.context.get_counterparty_node_id(), - funding_txo: funding_txo.map(|outpoint| outpoint.into_bitcoin_outpoint()), + counterparty_node_id, + funding_txo: Some(funding_txo.into_bitcoin_outpoint()), channel_type: funded_channel.funding.get_channel_type().clone(), }, None)); } pending_msg_events.push(MessageSendEvent::SendSpliceLocked { - node_id: funded_channel.context.get_counterparty_node_id(), + node_id: counterparty_node_id, msg: splice_locked, }); }, @@ -12470,6 +12502,42 @@ where } } + #[cfg(splicing)] + for (counterparty_node_id, channel_id) in to_process_monitor_update_actions { + let per_peer_state = self.per_peer_state.read().unwrap(); + if let Some(peer_state_mutex) = per_peer_state.get(&counterparty_node_id) { + let mut peer_state_lock = peer_state_mutex.lock().unwrap(); + let peer_state = &mut *peer_state_lock; + let has_in_flight_updates = peer_state + .in_flight_monitor_updates + .get(&channel_id) + .map(|in_flight_updates| !in_flight_updates.1.is_empty()) + .unwrap_or(false); + if let Some(chan) = peer_state.channel_by_id + .get_mut(&channel_id) + .and_then(Channel::as_funded_mut) + { + if !has_in_flight_updates && chan.blocked_monitor_updates_pending() == 0 { + handle_monitor_update_completion!( + self, + peer_state_lock, + peer_state, + per_peer_state, + chan + ); + } + } else { + let update_actions = peer_state + .monitor_update_blocked_actions + .remove(&channel_id) + .unwrap_or(Vec::new()); + mem::drop(peer_state_lock); + mem::drop(per_peer_state); + self.handle_monitor_update_completion_actions(update_actions); + } + } + } + if let Some(height) = height_opt { self.claimable_payments.lock().unwrap().claimable_payments.retain(|payment_hash, payment| { payment.htlcs.retain(|htlc| { From 22d542884249e7744d623e57fde4b7cbc61fd615 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 15 Jul 2025 17:25:59 -0700 Subject: [PATCH 2/2] Rename ChannelMonitor::first_confirmed_funding_txo It's only intended to be set during initialization and used to check if the channel is v1 or v2. We rename it to `first_negotiated_funding_txo` to better reflect its purpose. --- lightning/src/chain/channelmonitor.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 7ff44bef1ba..28ebe15a84b 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -1152,7 +1152,7 @@ pub(crate) struct ChannelMonitorImpl { channel_keys_id: [u8; 32], holder_revocation_basepoint: RevocationBasepoint, channel_id: ChannelId, - first_confirmed_funding_txo: OutPoint, + first_negotiated_funding_txo: OutPoint, counterparty_commitment_params: CounterpartyCommitmentParameters, @@ -1575,7 +1575,7 @@ impl Writeable for ChannelMonitorImpl { (21, self.balances_empty_height, option), (23, self.holder_pays_commitment_tx_fee, option), (25, self.payment_preimages, required), - (27, self.first_confirmed_funding_txo, required), + (27, self.first_negotiated_funding_txo, required), (29, self.initial_counterparty_commitment_tx, option), (31, self.funding.channel_parameters, required), (32, self.pending_funding, optional_vec), @@ -1761,7 +1761,7 @@ impl ChannelMonitor { channel_keys_id, holder_revocation_basepoint, channel_id, - first_confirmed_funding_txo: funding_outpoint, + first_negotiated_funding_txo: funding_outpoint, counterparty_commitment_params, their_cur_per_commitment_points: None, @@ -1820,7 +1820,7 @@ impl ChannelMonitor { /// [`Persist`]: crate::chain::chainmonitor::Persist pub fn persistence_key(&self) -> MonitorName { let inner = self.inner.lock().unwrap(); - let funding_outpoint = inner.first_confirmed_funding_txo; + let funding_outpoint = inner.first_negotiated_funding_txo; let channel_id = inner.channel_id; if ChannelId::v1_from_funding_outpoint(funding_outpoint) == channel_id { MonitorName::V1Channel(funding_outpoint) @@ -5724,7 +5724,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP let mut channel_id = None; let mut holder_pays_commitment_tx_fee = None; let mut payment_preimages_with_info: Option> = None; - let mut first_confirmed_funding_txo = RequiredWrapper(None); + let mut first_negotiated_funding_txo = RequiredWrapper(None); let mut channel_parameters = None; let mut pending_funding = None; read_tlv_fields!(reader, { @@ -5741,7 +5741,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP (21, balances_empty_height, option), (23, holder_pays_commitment_tx_fee, option), (25, payment_preimages_with_info, option), - (27, first_confirmed_funding_txo, (default_value, outpoint)), + (27, first_negotiated_funding_txo, (default_value, outpoint)), (29, initial_counterparty_commitment_tx, option), (31, channel_parameters, (option: ReadableArgs, None)), (32, pending_funding, optional_vec), @@ -5873,7 +5873,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP channel_keys_id, holder_revocation_basepoint, channel_id, - first_confirmed_funding_txo: first_confirmed_funding_txo.0.unwrap(), + first_negotiated_funding_txo: first_negotiated_funding_txo.0.unwrap(), counterparty_commitment_params, their_cur_per_commitment_points,