@@ -66,6 +66,8 @@ use crate::util::errors::APIError;
6666use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits, MaxDustHTLCExposure};
6767use crate::util::scid_utils::scid_from_parts;
6868
69+ use alloc::collections::{btree_map, BTreeMap};
70+
6971use crate::io;
7072use crate::prelude::*;
7173use core::{cmp,mem,fmt};
@@ -1515,6 +1517,7 @@ impl<SP: Deref> Channel<SP> where
15151517 let mut funded_channel = FundedChannel {
15161518 funding: chan.funding,
15171519 pending_funding: vec![],
1520+ commitment_signed_batch: BTreeMap::new(),
15181521 context: chan.context,
15191522 interactive_tx_signing_session: chan.interactive_tx_signing_session,
15201523 holder_commitment_point,
@@ -4949,6 +4952,7 @@ pub(super) struct DualFundingChannelContext {
49494952pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
49504953 pub funding: FundingScope,
49514954 pending_funding: Vec<FundingScope>,
4955+ commitment_signed_batch: BTreeMap<Txid, msgs::CommitmentSigned>,
49524956 pub context: ChannelContext<SP>,
49534957 pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
49544958 holder_commitment_point: HolderCommitmentPoint,
@@ -5741,6 +5745,11 @@ impl<SP: Deref> FundedChannel<SP> where
57415745 ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
57425746 )));
57435747 }
5748+
5749+ if msg.batch.is_some() {
5750+ return Err(ChannelError::close("Peer sent initial commitment_signed with a batch".to_owned()));
5751+ }
5752+
57445753 let holder_commitment_point = &mut self.holder_commitment_point.clone();
57455754 self.context.assert_no_commitment_advancement(holder_commitment_point.transaction_number(), "initial commitment_signed");
57465755
@@ -5781,7 +5790,58 @@ impl<SP: Deref> FundedChannel<SP> where
57815790 return Err(ChannelError::close("Peer sent commitment_signed after we'd started exchanging closing_signeds".to_owned()));
57825791 }
57835792
5784- let commitment_tx_info = self.context.validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)?;
5793+ if msg.batch.is_none() && !self.pending_funding.is_empty() {
5794+ return Err(ChannelError::close("Peer sent commitment_signed without a batch when there's a pending splice".to_owned()));
5795+ }
5796+
5797+ let mut updates = match &msg.batch {
5798+ // No pending splice
5799+ None => {
5800+ debug_assert!(self.pending_funding.is_empty());
5801+ debug_assert!(self.commitment_signed_batch.is_empty());
5802+ self.context
5803+ .validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)
5804+ .map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5805+ vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5806+ commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5807+ }]
5808+ )?
5809+ },
5810+ // May or may not have a pending splice
5811+ Some(batch) => {
5812+ match self.commitment_signed_batch.entry(batch.funding_txid) {
5813+ btree_map::Entry::Vacant(entry) => { entry.insert(msg.clone()); },
5814+ btree_map::Entry::Occupied(entry) => {
5815+ return Err(ChannelError::close(format!("Peer sent commitment_signed with duplicate funding_txid {} in a batch", entry.key())));
5816+ },
5817+ }
5818+
5819+ if self.commitment_signed_batch.len() < batch.batch_size as usize {
5820+ return Ok(None);
5821+ }
5822+
5823+ // Any commitment_signed not associated with a FundingScope is ignored below if a
5824+ // pending splice transaction has confirmed since receiving the batch.
5825+ core::iter::once(&self.funding)
5826+ .chain(self.pending_funding.iter())
5827+ .map(|funding| {
5828+ let funding_txid = funding.get_funding_txo().unwrap().txid;
5829+ let msg = self.commitment_signed_batch
5830+ .get(&funding_txid)
5831+ .ok_or_else(|| ChannelError::close(format!("Peer did not send a commitment_signed for pending splice transaction: {}", funding_txid)))?;
5832+ self.context
5833+ .validate_commitment_signed(funding, &self.holder_commitment_point, msg, logger)
5834+ .map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5835+ ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5836+ commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5837+ }
5838+ )
5839+ }
5840+ )
5841+ .collect::<Result<Vec<_>, ChannelError>>()?
5842+ },
5843+ };
5844+ self.commitment_signed_batch.clear();
57855845
57865846 if self.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger).is_err() {
57875847 // We only fail to advance our commitment point/number if we're currently
@@ -5836,18 +5896,21 @@ impl<SP: Deref> FundedChannel<SP> where
58365896 }
58375897 }
58385898
5839- let LatestHolderCommitmentTXInfo {
5840- commitment_tx, htlc_outputs, nondust_htlc_sources,
5841- } = commitment_tx_info;
5899+ for mut update in updates.iter_mut() {
5900+ if let ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5901+ claimed_htlcs: ref mut update_claimed_htlcs, ..
5902+ } = &mut update {
5903+ debug_assert!(update_claimed_htlcs.is_empty());
5904+ *update_claimed_htlcs = claimed_htlcs.clone();
5905+ } else {
5906+ debug_assert!(false);
5907+ }
5908+ }
5909+
58425910 self.context.latest_monitor_update_id += 1;
58435911 let mut monitor_update = ChannelMonitorUpdate {
58445912 update_id: self.context.latest_monitor_update_id,
5845- updates: vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5846- commitment_tx,
5847- htlc_outputs,
5848- claimed_htlcs,
5849- nondust_htlc_sources,
5850- }],
5913+ updates,
58515914 channel_id: Some(self.context.channel_id()),
58525915 };
58535916
@@ -9541,6 +9604,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
95419604 let mut channel = FundedChannel {
95429605 funding: self.funding,
95439606 pending_funding: vec![],
9607+ commitment_signed_batch: BTreeMap::new(),
95449608 context: self.context,
95459609 interactive_tx_signing_session: None,
95469610 is_v2_established: false,
@@ -9818,6 +9882,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
98189882 let mut channel = FundedChannel {
98199883 funding: self.funding,
98209884 pending_funding: vec![],
9885+ commitment_signed_batch: BTreeMap::new(),
98219886 context: self.context,
98229887 interactive_tx_signing_session: None,
98239888 is_v2_established: false,
@@ -11084,6 +11149,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1108411149 funding_transaction,
1108511150 },
1108611151 pending_funding: pending_funding.unwrap(),
11152+ commitment_signed_batch: BTreeMap::new(),
1108711153 context: ChannelContext {
1108811154 user_id,
1108911155
0 commit comments