Skip to content

Commit a1de713

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 060fbf1 commit a1de713

File tree

6 files changed

+127
-12
lines changed

6 files changed

+127
-12
lines changed

Diff for: lightning-net-tokio/src/lib.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -622,15 +622,17 @@ impl Hash for SocketDescriptor {
622622
mod tests {
623623
use bitcoin::constants::ChainHash;
624624
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
625-
use bitcoin::Network;
625+
use bitcoin::{Network, Txid};
626626
use lightning::ln::msgs::*;
627627
use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler, PeerManager};
628+
use lightning::ln::types::ChannelId;
628629
use lightning::routing::gossip::NodeId;
629630
use lightning::types::features::*;
630631
use lightning::util::test_utils::TestNodeSigner;
631632

632633
use tokio::sync::mpsc;
633634

635+
use std::collections::BTreeMap;
634636
use std::mem;
635637
use std::sync::atomic::{AtomicBool, Ordering};
636638
use std::sync::{Arc, Mutex};
@@ -723,6 +725,11 @@ mod tests {
723725
) {
724726
}
725727
fn handle_commitment_signed(&self, _their_node_id: PublicKey, _msg: &CommitmentSigned) {}
728+
fn handle_commitment_signed_batch(
729+
&self, _their_node_id: PublicKey, _channel_id: ChannelId,
730+
_batch: BTreeMap<Txid, CommitmentSigned>,
731+
) {
732+
}
726733
fn handle_revoke_and_ack(&self, _their_node_id: PublicKey, _msg: &RevokeAndACK) {}
727734
fn handle_update_fee(&self, _their_node_id: PublicKey, _msg: &UpdateFee) {}
728735
fn handle_announcement_signatures(

Diff for: lightning/src/ln/channel.rs

+67-10
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::BTreeMap;
70+
6971
use crate::io;
7072
use crate::prelude::*;
7173
use core::time::Duration;
@@ -5777,6 +5779,11 @@ impl<SP: Deref> FundedChannel<SP> where
57775779
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
57785780
)));
57795781
}
5782+
5783+
if msg.batch.is_some() {
5784+
return Err(ChannelError::close("Peer sent initial commitment_signed with a batch".to_owned()));
5785+
}
5786+
57805787
let holder_commitment_point = &mut self.holder_commitment_point.clone();
57815788
self.context.assert_no_commitment_advancement(holder_commitment_point.transaction_number(), "initial commitment_signed");
57825789

@@ -5804,6 +5811,49 @@ impl<SP: Deref> FundedChannel<SP> where
58045811
pub fn commitment_signed<L: Deref>(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
58055812
where L::Target: Logger
58065813
{
5814+
self.commitment_signed_check_state()?;
5815+
5816+
let updates = self
5817+
.context
5818+
.validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)
5819+
.map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5820+
vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5821+
commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5822+
}]
5823+
)?;
5824+
5825+
self.commitment_signed_update_monitor(updates, logger)
5826+
}
5827+
5828+
pub fn commitment_signed_batch<L: Deref>(&mut self, batch: &BTreeMap<Txid, msgs::CommitmentSigned>, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
5829+
where L::Target: Logger
5830+
{
5831+
self.commitment_signed_check_state()?;
5832+
5833+
// Any commitment_signed not associated with a FundingScope is ignored below if a
5834+
// pending splice transaction has confirmed since receiving the batch.
5835+
let updates = core::iter::once(&self.funding)
5836+
.chain(self.pending_funding.iter())
5837+
.map(|funding| {
5838+
let funding_txid = funding.get_funding_txo().unwrap().txid;
5839+
let msg = batch
5840+
.get(&funding_txid)
5841+
.ok_or_else(|| ChannelError::close(format!("Peer did not send a commitment_signed for pending splice transaction: {}", funding_txid)))?;
5842+
self.context
5843+
.validate_commitment_signed(funding, &self.holder_commitment_point, msg, logger)
5844+
.map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5845+
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5846+
commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5847+
}
5848+
)
5849+
}
5850+
)
5851+
.collect::<Result<Vec<_>, ChannelError>>()?;
5852+
5853+
self.commitment_signed_update_monitor(updates, logger)
5854+
}
5855+
5856+
fn commitment_signed_check_state(&self) -> Result<(), ChannelError> {
58075857
if self.context.channel_state.is_quiescent() {
58085858
return Err(ChannelError::WarnAndDisconnect("Got commitment_signed message while quiescent".to_owned()));
58095859
}
@@ -5817,8 +5867,12 @@ impl<SP: Deref> FundedChannel<SP> where
58175867
return Err(ChannelError::close("Peer sent commitment_signed after we'd started exchanging closing_signeds".to_owned()));
58185868
}
58195869

5820-
let commitment_tx_info = self.context.validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)?;
5870+
Ok(())
5871+
}
58215872

5873+
fn commitment_signed_update_monitor<L: Deref>(&mut self, mut updates: Vec<ChannelMonitorUpdateStep>, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
5874+
where L::Target: Logger
5875+
{
58225876
if self.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger).is_err() {
58235877
// We only fail to advance our commitment point/number if we're currently
58245878
// waiting for our signer to unblock and provide a commitment point.
@@ -5872,18 +5926,21 @@ impl<SP: Deref> FundedChannel<SP> where
58725926
}
58735927
}
58745928

5875-
let LatestHolderCommitmentTXInfo {
5876-
commitment_tx, htlc_outputs, nondust_htlc_sources,
5877-
} = commitment_tx_info;
5929+
for mut update in updates.iter_mut() {
5930+
if let ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5931+
claimed_htlcs: ref mut update_claimed_htlcs, ..
5932+
} = &mut update {
5933+
debug_assert!(update_claimed_htlcs.is_empty());
5934+
*update_claimed_htlcs = claimed_htlcs.clone();
5935+
} else {
5936+
debug_assert!(false);
5937+
}
5938+
}
5939+
58785940
self.context.latest_monitor_update_id += 1;
58795941
let mut monitor_update = ChannelMonitorUpdate {
58805942
update_id: self.context.latest_monitor_update_id,
5881-
updates: vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5882-
commitment_tx,
5883-
htlc_outputs,
5884-
claimed_htlcs,
5885-
nondust_htlc_sources,
5886-
}],
5943+
updates,
58875944
channel_id: Some(self.context.channel_id()),
58885945
};
58895946

Diff for: lightning/src/ln/channelmanager.rs

+37
Original file line numberDiff line numberDiff line change
@@ -9020,6 +9020,38 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
90209020
}
90219021
}
90229022

9023+
fn internal_commitment_signed_batch(&self, counterparty_node_id: &PublicKey, channel_id: ChannelId, batch: &BTreeMap<Txid, msgs::CommitmentSigned>) -> Result<(), MsgHandleErrInternal> {
9024+
let per_peer_state = self.per_peer_state.read().unwrap();
9025+
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
9026+
.ok_or_else(|| {
9027+
debug_assert!(false);
9028+
MsgHandleErrInternal::send_err_msg_no_close(format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id), channel_id)
9029+
})?;
9030+
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
9031+
let peer_state = &mut *peer_state_lock;
9032+
match peer_state.channel_by_id.entry(channel_id) {
9033+
hash_map::Entry::Occupied(mut chan_entry) => {
9034+
let chan = chan_entry.get_mut();
9035+
let logger = WithChannelContext::from(&self.logger, &chan.context(), None);
9036+
let funding_txo = chan.funding().get_funding_txo();
9037+
if let Some(chan) = chan.as_funded_mut() {
9038+
let monitor_update_opt = try_channel_entry!(
9039+
self, peer_state, chan.commitment_signed_batch(batch, &&logger), chan_entry
9040+
);
9041+
9042+
if let Some(monitor_update) = monitor_update_opt {
9043+
handle_new_monitor_update!(
9044+
self, funding_txo.unwrap(), monitor_update, peer_state_lock, peer_state,
9045+
per_peer_state, chan
9046+
);
9047+
}
9048+
}
9049+
Ok(())
9050+
},
9051+
hash_map::Entry::Vacant(_) => Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), channel_id))
9052+
}
9053+
}
9054+
90239055
fn push_decode_update_add_htlcs(&self, mut update_add_htlcs: (u64, Vec<msgs::UpdateAddHTLC>)) {
90249056
let mut push_forward_event = self.forward_htlcs.lock().unwrap().is_empty();
90259057
let mut decode_update_add_htlcs = self.decode_update_add_htlcs.lock().unwrap();
@@ -12130,6 +12162,11 @@ where
1213012162
let _ = handle_error!(self, self.internal_commitment_signed(&counterparty_node_id, msg), counterparty_node_id);
1213112163
}
1213212164

12165+
fn handle_commitment_signed_batch(&self, counterparty_node_id: PublicKey, channel_id: ChannelId, batch: BTreeMap<Txid, msgs::CommitmentSigned>) {
12166+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
12167+
let _ = handle_error!(self, self.internal_commitment_signed_batch(&counterparty_node_id, channel_id, &batch), counterparty_node_id);
12168+
}
12169+
1213312170
fn handle_revoke_and_ack(&self, counterparty_node_id: PublicKey, msg: &msgs::RevokeAndACK) {
1213412171
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
1213512172
let _ = handle_error!(self, self.internal_revoke_and_ack(&counterparty_node_id, msg), counterparty_node_id);

Diff for: lightning/src/ln/msgs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1940,7 +1940,7 @@ pub trait ChannelMessageHandler : BaseMessageHandler {
19401940
fn handle_commitment_signed_batch(
19411941
&self, their_node_id: PublicKey, channel_id: ChannelId,
19421942
batch: BTreeMap<Txid, CommitmentSigned>,
1943-
) {}
1943+
);
19441944
/// Handle an incoming `revoke_and_ack` message from the given peer.
19451945
fn handle_revoke_and_ack(&self, their_node_id: PublicKey, msg: &RevokeAndACK);
19461946

Diff for: lightning/src/ln/peer_handler.rs

+6
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,12 @@ impl ChannelMessageHandler for ErroringMessageHandler {
334334
fn handle_commitment_signed(&self, their_node_id: PublicKey, msg: &msgs::CommitmentSigned) {
335335
ErroringMessageHandler::push_error(self, their_node_id, msg.channel_id);
336336
}
337+
fn handle_commitment_signed_batch(
338+
&self, their_node_id: PublicKey, channel_id: ChannelId,
339+
_batch: BTreeMap<Txid, msgs::CommitmentSigned>,
340+
) {
341+
ErroringMessageHandler::push_error(self, their_node_id, channel_id);
342+
}
337343
fn handle_revoke_and_ack(&self, their_node_id: PublicKey, msg: &msgs::RevokeAndACK) {
338344
ErroringMessageHandler::push_error(self, their_node_id, msg.channel_id);
339345
}

Diff for: lightning/src/util/test_utils.rs

+8
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
7979

8080
use lightning_invoice::RawBolt11Invoice;
8181

82+
use alloc::collections::BTreeMap;
83+
8284
use crate::io;
8385
use crate::prelude::*;
8486
use crate::sign::{EntropySource, NodeSigner, RandomBytes, Recipient, SignerProvider};
@@ -1053,6 +1055,12 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
10531055
fn handle_commitment_signed(&self, _their_node_id: PublicKey, msg: &msgs::CommitmentSigned) {
10541056
self.received_msg(wire::Message::CommitmentSigned(msg.clone()));
10551057
}
1058+
fn handle_commitment_signed_batch(
1059+
&self, _their_node_id: PublicKey, _channel_id: ChannelId,
1060+
_batch: BTreeMap<Txid, msgs::CommitmentSigned>,
1061+
) {
1062+
unreachable!()
1063+
}
10561064
fn handle_revoke_and_ack(&self, _their_node_id: PublicKey, msg: &msgs::RevokeAndACK) {
10571065
self.received_msg(wire::Message::RevokeAndACK(msg.clone()));
10581066
}

0 commit comments

Comments
 (0)