Skip to content

Commit 8f27e3f

Browse files
committed
Batch commitment_signed messages for splicing
A FundedChannel may have more than one pending FundingScope during splicing, one for the splice attempt and one or more for any RBF attempts. The counterparty will send a commitment_signed message for each pending splice transaction and the current funding transaction. Defer handling these commitment_signed messages until the entire batch has arrived. Then validate them individually, also checking if all the pending splice transactions and the current funding transaction have a corresponding commitment_signed in the batch.
1 parent 33bc387 commit 8f27e3f

File tree

1 file changed

+76
-10
lines changed

1 file changed

+76
-10
lines changed

lightning/src/ln/channel.rs

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ use crate::util::errors::APIError;
6666
use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits, MaxDustHTLCExposure};
6767
use crate::util::scid_utils::scid_from_parts;
6868

69+
use alloc::collections::{btree_map, BTreeMap};
70+
6971
use crate::io;
7072
use crate::prelude::*;
7173
use 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 {
49274930
pub(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

Comments
 (0)