Skip to content

Commit 0ab79a6

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 4fd0048 commit 0ab79a6

File tree

6 files changed

+131
-12
lines changed

6 files changed

+131
-12
lines changed

lightning-net-tokio/src/lib.rs

Lines changed: 8 additions & 1 deletion
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(

lightning/src/ln/channel.rs

Lines changed: 71 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::BTreeMap;
70+
6971
use crate::io;
7072
use crate::prelude::*;
7173
use core::{cmp,mem,fmt};
@@ -5700,6 +5702,11 @@ impl<SP: Deref> FundedChannel<SP> where
57005702
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
57015703
)));
57025704
}
5705+
5706+
if msg.batch.is_some() {
5707+
return Err(ChannelError::close("Peer sent initial commitment_signed with a batch".to_owned()));
5708+
}
5709+
57035710
let holder_commitment_point = &mut self.holder_commitment_point.clone();
57045711
self.context.assert_no_commitment_advancement(holder_commitment_point.transaction_number(), "initial commitment_signed");
57055712

@@ -5727,6 +5734,53 @@ impl<SP: Deref> FundedChannel<SP> where
57275734
pub fn commitment_signed<L: Deref>(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
57285735
where L::Target: Logger
57295736
{
5737+
self.commitment_signed_check_state()?;
5738+
5739+
if !self.pending_funding.is_empty() {
5740+
return Err(ChannelError::close("Peer sent commitment_signed without a batch when there's a pending splice".to_owned()));
5741+
}
5742+
5743+
let updates = self
5744+
.context
5745+
.validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)
5746+
.map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5747+
vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5748+
commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5749+
}]
5750+
)?;
5751+
5752+
self.commitment_signed_update_monitor(updates, logger)
5753+
}
5754+
5755+
pub fn commitment_signed_batch<L: Deref>(&mut self, batch: &BTreeMap<Txid, msgs::CommitmentSigned>, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
5756+
where L::Target: Logger
5757+
{
5758+
self.commitment_signed_check_state()?;
5759+
5760+
// Any commitment_signed not associated with a FundingScope is ignored below if a
5761+
// pending splice transaction has confirmed since receiving the batch.
5762+
let updates = core::iter::once(&self.funding)
5763+
.chain(self.pending_funding.iter())
5764+
.map(|funding| {
5765+
let funding_txid = funding.get_funding_txo().unwrap().txid;
5766+
let msg = batch
5767+
.get(&funding_txid)
5768+
.ok_or_else(|| ChannelError::close(format!("Peer did not send a commitment_signed for pending splice transaction: {}", funding_txid)))?;
5769+
self.context
5770+
.validate_commitment_signed(funding, &self.holder_commitment_point, msg, logger)
5771+
.map(|LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, nondust_htlc_sources }|
5772+
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5773+
commitment_tx, htlc_outputs, claimed_htlcs: vec![], nondust_htlc_sources,
5774+
}
5775+
)
5776+
}
5777+
)
5778+
.collect::<Result<Vec<_>, ChannelError>>()?;
5779+
5780+
self.commitment_signed_update_monitor(updates, logger)
5781+
}
5782+
5783+
fn commitment_signed_check_state(&self) -> Result<(), ChannelError> {
57305784
if self.context.channel_state.is_quiescent() {
57315785
return Err(ChannelError::WarnAndDisconnect("Got commitment_signed message while quiescent".to_owned()));
57325786
}
@@ -5740,8 +5794,12 @@ impl<SP: Deref> FundedChannel<SP> where
57405794
return Err(ChannelError::close("Peer sent commitment_signed after we'd started exchanging closing_signeds".to_owned()));
57415795
}
57425796

5743-
let commitment_tx_info = self.context.validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)?;
5797+
Ok(())
5798+
}
57445799

5800+
fn commitment_signed_update_monitor<L: Deref>(&mut self, mut updates: Vec<ChannelMonitorUpdateStep>, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
5801+
where L::Target: Logger
5802+
{
57455803
if self.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger).is_err() {
57465804
// We only fail to advance our commitment point/number if we're currently
57475805
// waiting for our signer to unblock and provide a commitment point.
@@ -5795,18 +5853,21 @@ impl<SP: Deref> FundedChannel<SP> where
57955853
}
57965854
}
57975855

5798-
let LatestHolderCommitmentTXInfo {
5799-
commitment_tx, htlc_outputs, nondust_htlc_sources,
5800-
} = commitment_tx_info;
5856+
for mut update in updates.iter_mut() {
5857+
if let ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
5858+
claimed_htlcs: ref mut update_claimed_htlcs, ..
5859+
} = &mut update {
5860+
debug_assert!(update_claimed_htlcs.is_empty());
5861+
*update_claimed_htlcs = claimed_htlcs.clone();
5862+
} else {
5863+
debug_assert!(false);
5864+
}
5865+
}
5866+
58015867
self.context.latest_monitor_update_id += 1;
58025868
let mut monitor_update = ChannelMonitorUpdate {
58035869
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-
}],
5870+
updates,
58105871
channel_id: Some(self.context.channel_id()),
58115872
};
58125873

lightning/src/ln/channelmanager.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9041,6 +9041,38 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
90419041
}
90429042
}
90439043

9044+
fn internal_commitment_signed_batch(&self, counterparty_node_id: &PublicKey, channel_id: ChannelId, batch: &BTreeMap<Txid, msgs::CommitmentSigned>) -> Result<(), MsgHandleErrInternal> {
9045+
let per_peer_state = self.per_peer_state.read().unwrap();
9046+
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
9047+
.ok_or_else(|| {
9048+
debug_assert!(false);
9049+
MsgHandleErrInternal::send_err_msg_no_close(format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id), channel_id)
9050+
})?;
9051+
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
9052+
let peer_state = &mut *peer_state_lock;
9053+
match peer_state.channel_by_id.entry(channel_id) {
9054+
hash_map::Entry::Occupied(mut chan_entry) => {
9055+
let chan = chan_entry.get_mut();
9056+
let logger = WithChannelContext::from(&self.logger, &chan.context(), None);
9057+
let funding_txo = chan.funding().get_funding_txo();
9058+
if let Some(chan) = chan.as_funded_mut() {
9059+
let monitor_update_opt = try_channel_entry!(
9060+
self, peer_state, chan.commitment_signed_batch(batch, &&logger), chan_entry
9061+
);
9062+
9063+
if let Some(monitor_update) = monitor_update_opt {
9064+
handle_new_monitor_update!(
9065+
self, funding_txo.unwrap(), monitor_update, peer_state_lock, peer_state,
9066+
per_peer_state, chan
9067+
);
9068+
}
9069+
}
9070+
Ok(())
9071+
},
9072+
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))
9073+
}
9074+
}
9075+
90449076
fn push_decode_update_add_htlcs(&self, mut update_add_htlcs: (u64, Vec<msgs::UpdateAddHTLC>)) {
90459077
let mut push_forward_event = self.forward_htlcs.lock().unwrap().is_empty();
90469078
let mut decode_update_add_htlcs = self.decode_update_add_htlcs.lock().unwrap();
@@ -12168,6 +12200,11 @@ where
1216812200
let _ = handle_error!(self, self.internal_commitment_signed(&counterparty_node_id, msg), counterparty_node_id);
1216912201
}
1217012202

12203+
fn handle_commitment_signed_batch(&self, counterparty_node_id: PublicKey, channel_id: ChannelId, batch: BTreeMap<Txid, msgs::CommitmentSigned>) {
12204+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
12205+
let _ = handle_error!(self, self.internal_commitment_signed_batch(&counterparty_node_id, channel_id, &batch), counterparty_node_id);
12206+
}
12207+
1217112208
fn handle_revoke_and_ack(&self, counterparty_node_id: PublicKey, msg: &msgs::RevokeAndACK) {
1217212209
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
1217312210
let _ = handle_error!(self, self.internal_revoke_and_ack(&counterparty_node_id, msg), counterparty_node_id);

lightning/src/ln/msgs.rs

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

lightning/src/ln/peer_handler.rs

Lines changed: 6 additions & 0 deletions
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
}

lightning/src/util/test_utils.rs

Lines changed: 8 additions & 0 deletions
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};
@@ -1022,6 +1024,12 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
10221024
fn handle_commitment_signed(&self, _their_node_id: PublicKey, msg: &msgs::CommitmentSigned) {
10231025
self.received_msg(wire::Message::CommitmentSigned(msg.clone()));
10241026
}
1027+
fn handle_commitment_signed_batch(
1028+
&self, _their_node_id: PublicKey, _channel_id: ChannelId,
1029+
_batch: BTreeMap<Txid, msgs::CommitmentSigned>,
1030+
) {
1031+
unreachable!()
1032+
}
10251033
fn handle_revoke_and_ack(&self, _their_node_id: PublicKey, msg: &msgs::RevokeAndACK) {
10261034
self.received_msg(wire::Message::RevokeAndACK(msg.clone()));
10271035
}

0 commit comments

Comments
 (0)