@@ -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};
@@ -1518,6 +1520,7 @@ impl<SP: Deref> Channel<SP> where
15181520 let mut funded_channel = FundedChannel {
15191521 funding: chan.funding,
15201522 pending_funding: vec![],
1523+ commitment_signed_batch: BTreeMap::new(),
15211524 context: chan.context,
15221525 interactive_tx_signing_session: chan.interactive_tx_signing_session,
15231526 holder_commitment_point,
@@ -4927,6 +4930,7 @@ pub(super) struct DualFundingChannelContext {
49274930pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
49284931 pub funding: FundingScope,
49294932 pending_funding: Vec<FundingScope>,
4933+ commitment_signed_batch: BTreeMap<Txid, msgs::CommitmentSigned>,
49304934 pub context: ChannelContext<SP>,
49314935 pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
49324936 holder_commitment_point: HolderCommitmentPoint,
@@ -5719,6 +5723,11 @@ impl<SP: Deref> FundedChannel<SP> where
57195723 ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
57205724 )));
57215725 }
5726+
5727+ if msg.batch.is_some() {
5728+ return Err(ChannelError::close("Peer sent initial commitment_signed with a batch".to_owned()));
5729+ }
5730+
57225731 let holder_commitment_point = &mut self.holder_commitment_point.clone();
57235732 self.context.assert_no_commitment_advancement(holder_commitment_point.transaction_number(), "initial commitment_signed");
57245733
@@ -5759,7 +5768,58 @@ impl<SP: Deref> FundedChannel<SP> where
57595768 return Err(ChannelError::close("Peer sent commitment_signed after we'd started exchanging closing_signeds".to_owned()));
57605769 }
57615770
5762- let commitment_tx_info = self.context.validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)?;
5771+ if msg.batch.is_none() && !self.pending_funding.is_empty() {
5772+ return Err(ChannelError::close("Peer sent commitment_signed without a batch when there's a pending splice".to_owned()));
5773+ }
5774+
5775+ let mut updates = match &msg.batch {
5776+ // No pending splice
5777+ None => {
5778+ debug_assert!(self.pending_funding.is_empty());
5779+ debug_assert!(self.commitment_signed_batch.is_empty());
5780+ self.context
5781+ .validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)
5782+ .map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5783+ vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5784+ commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5785+ }]
5786+ )?
5787+ },
5788+ // May or may not have a pending splice
5789+ Some(batch) => {
5790+ match self.commitment_signed_batch.entry(batch.funding_txid) {
5791+ btree_map::Entry::Vacant(entry) => { entry.insert(msg.clone()); },
5792+ btree_map::Entry::Occupied(entry) => {
5793+ return Err(ChannelError::close(format!("Peer sent commitment_signed with duplicate funding_txid {} in a batch", entry.key())));
5794+ },
5795+ }
5796+
5797+ if self.commitment_signed_batch.len() < batch.batch_size as usize {
5798+ return Ok(None);
5799+ }
5800+
5801+ // Any commitment_signed not associated with a FundingScope is ignored below if a
5802+ // pending splice transaction has confirmed since receiving the batch.
5803+ core::iter::once(&self.funding)
5804+ .chain(self.pending_funding.iter())
5805+ .map(|funding| {
5806+ let funding_txid = funding.get_funding_txo().unwrap().txid;
5807+ let msg = self.commitment_signed_batch
5808+ .get(&funding_txid)
5809+ .ok_or_else(|| ChannelError::close(format!("Peer did not send a commitment_signed for pending splice transaction: {}", funding_txid)))?;
5810+ self.context
5811+ .validate_commitment_signed(funding, &self.holder_commitment_point, msg, logger)
5812+ .map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5813+ ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5814+ commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5815+ }
5816+ )
5817+ }
5818+ )
5819+ .collect::<Result<Vec<_>, ChannelError>>()?
5820+ },
5821+ };
5822+ self.commitment_signed_batch.clear();
57635823
57645824 if self.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger).is_err() {
57655825 // We only fail to advance our commitment point/number if we're currently
@@ -5814,18 +5874,21 @@ impl<SP: Deref> FundedChannel<SP> where
58145874 }
58155875 }
58165876
5817- let LatestHolderCommitmentTXInfo {
5818- commitment_tx, htlc_outputs, nondust_htlc_sources,
5819- } = commitment_tx_info;
5877+ for mut update in updates.iter_mut() {
5878+ if let ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5879+ claimed_htlcs: ref mut update_claimed_htlcs, ..
5880+ } = &mut update {
5881+ debug_assert!(update_claimed_htlcs.is_empty());
5882+ *update_claimed_htlcs = claimed_htlcs.clone();
5883+ } else {
5884+ debug_assert!(false);
5885+ }
5886+ }
5887+
58205888 self.context.latest_monitor_update_id += 1;
58215889 let mut monitor_update = ChannelMonitorUpdate {
58225890 update_id: self.context.latest_monitor_update_id,
5823- updates: vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5824- commitment_tx,
5825- htlc_outputs,
5826- claimed_htlcs,
5827- nondust_htlc_sources,
5828- }],
5891+ updates,
58295892 channel_id: Some(self.context.channel_id()),
58305893 };
58315894
@@ -9524,6 +9587,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
95249587 let mut channel = FundedChannel {
95259588 funding: self.funding,
95269589 pending_funding: vec![],
9590+ commitment_signed_batch: BTreeMap::new(),
95279591 context: self.context,
95289592 interactive_tx_signing_session: None,
95299593 is_v2_established: false,
@@ -9801,6 +9865,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
98019865 let mut channel = FundedChannel {
98029866 funding: self.funding,
98039867 pending_funding: vec![],
9868+ commitment_signed_batch: BTreeMap::new(),
98049869 context: self.context,
98059870 interactive_tx_signing_session: None,
98069871 is_v2_established: false,
@@ -11067,6 +11132,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1106711132 funding_transaction,
1106811133 },
1106911134 pending_funding: pending_funding.unwrap(),
11135+ commitment_signed_batch: BTreeMap::new(),
1107011136 context: ChannelContext {
1107111137 user_id,
1107211138
0 commit comments