@@ -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,
@@ -4917,6 +4920,7 @@ pub(super) struct DualFundingChannelContext {
49174920pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
49184921 pub funding: FundingScope,
49194922 pending_funding: Vec<FundingScope>,
4923+ commitment_signed_batch: BTreeMap<Txid, msgs::CommitmentSigned>,
49204924 pub context: ChannelContext<SP>,
49214925 pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
49224926 holder_commitment_point: HolderCommitmentPoint,
@@ -5700,6 +5704,11 @@ impl<SP: Deref> FundedChannel<SP> where
57005704 ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
57015705 )));
57025706 }
5707+
5708+ if msg.batch.is_some() {
5709+ return Err(ChannelError::close("Peer sent initial commitment_signed with a batch".to_owned()));
5710+ }
5711+
57035712 let holder_commitment_point = &mut self.holder_commitment_point.clone();
57045713 self.context.assert_no_commitment_advancement(holder_commitment_point.transaction_number(), "initial commitment_signed");
57055714
@@ -5740,7 +5749,58 @@ impl<SP: Deref> FundedChannel<SP> where
57405749 return Err(ChannelError::close("Peer sent commitment_signed after we'd started exchanging closing_signeds".to_owned()));
57415750 }
57425751
5743- let commitment_tx_info = self.context.validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)?;
5752+ if msg.batch.is_none() && !self.pending_funding.is_empty() {
5753+ return Err(ChannelError::close("Peer sent commitment_signed without a batch when there's a pending splice".to_owned()));
5754+ }
5755+
5756+ let mut updates = match &msg.batch {
5757+ // No pending splice
5758+ None => {
5759+ debug_assert!(self.pending_funding.is_empty());
5760+ debug_assert!(self.commitment_signed_batch.is_empty());
5761+ self.context
5762+ .validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)
5763+ .map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5764+ vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5765+ commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5766+ }]
5767+ )?
5768+ },
5769+ // May or may not have a pending splice
5770+ Some(batch) => {
5771+ match self.commitment_signed_batch.entry(batch.funding_txid) {
5772+ btree_map::Entry::Vacant(entry) => { entry.insert(msg.clone()); },
5773+ btree_map::Entry::Occupied(entry) => {
5774+ return Err(ChannelError::close(format!("Peer sent commitment_signed with duplicate funding_txid {} in a batch", entry.key())));
5775+ },
5776+ }
5777+
5778+ if self.commitment_signed_batch.len() < batch.batch_size as usize {
5779+ return Ok(None);
5780+ }
5781+
5782+ // Any commitment_signed not associated with a FundingScope is ignored below if a
5783+ // pending splice transaction has confirmed since receiving the batch.
5784+ core::iter::once(&self.funding)
5785+ .chain(self.pending_funding.iter())
5786+ .map(|funding| {
5787+ let funding_txid = funding.get_funding_txo().unwrap().txid;
5788+ let msg = self.commitment_signed_batch
5789+ .get(&funding_txid)
5790+ .ok_or_else(|| ChannelError::close(format!("Peer did not send a commitment_signed for pending splice transaction: {}", funding_txid)))?;
5791+ self.context
5792+ .validate_commitment_signed(funding, &self.holder_commitment_point, msg, logger)
5793+ .map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5794+ ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5795+ commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5796+ }
5797+ )
5798+ }
5799+ )
5800+ .collect::<Result<Vec<_>, ChannelError>>()?
5801+ },
5802+ };
5803+ self.commitment_signed_batch.clear();
57445804
57455805 if self.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger).is_err() {
57465806 // We only fail to advance our commitment point/number if we're currently
@@ -5795,18 +5855,21 @@ impl<SP: Deref> FundedChannel<SP> where
57955855 }
57965856 }
57975857
5798- let LatestHolderCommitmentTXInfo {
5799- commitment_tx, htlc_outputs, nondust_htlc_sources,
5800- } = commitment_tx_info;
5858+ for mut update in updates.iter_mut() {
5859+ if let ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5860+ claimed_htlcs: ref mut update_claimed_htlcs, ..
5861+ } = &mut update {
5862+ debug_assert!(update_claimed_htlcs.is_empty());
5863+ *update_claimed_htlcs = claimed_htlcs.clone();
5864+ } else {
5865+ debug_assert!(false);
5866+ }
5867+ }
5868+
58015869 self.context.latest_monitor_update_id += 1;
58025870 let mut monitor_update = ChannelMonitorUpdate {
58035871 update_id: self.context.latest_monitor_update_id,
5804- updates: vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5805- commitment_tx,
5806- htlc_outputs,
5807- claimed_htlcs,
5808- nondust_htlc_sources,
5809- }],
5872+ updates,
58105873 channel_id: Some(self.context.channel_id()),
58115874 };
58125875
@@ -9505,6 +9568,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
95059568 let mut channel = FundedChannel {
95069569 funding: self.funding,
95079570 pending_funding: vec![],
9571+ commitment_signed_batch: BTreeMap::new(),
95089572 context: self.context,
95099573 interactive_tx_signing_session: None,
95109574 is_v2_established: false,
@@ -9782,6 +9846,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
97829846 let mut channel = FundedChannel {
97839847 funding: self.funding,
97849848 pending_funding: vec![],
9849+ commitment_signed_batch: BTreeMap::new(),
97859850 context: self.context,
97869851 interactive_tx_signing_session: None,
97879852 is_v2_established: false,
@@ -11048,6 +11113,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1104811113 funding_transaction,
1104911114 },
1105011115 pending_funding: pending_funding.unwrap(),
11116+ commitment_signed_batch: BTreeMap::new(),
1105111117 context: ChannelContext {
1105211118 user_id,
1105311119
0 commit comments