Skip to content

Commit c8672e2

Browse files
committed
Handle batched commitment_signed messages
Update commitment_signed message to contain the funding_txid instead of both that and a batch_size. The spec was updated to batch messages using start_batch, which contains the batch_size. This commit also updates PeerManager to batch commitment_signed messages in this manner instead of the previous custom approach.
1 parent c906974 commit c8672e2

File tree

6 files changed

+103
-69
lines changed

6 files changed

+103
-69
lines changed

lightning/src/ln/channel.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4978,7 +4978,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
49784978
channel_id: self.channel_id,
49794979
htlc_signatures: vec![],
49804980
signature,
4981-
batch: None,
4981+
funding_txid: funding.get_funding_txo().map(|funding_txo| funding_txo.txid),
49824982
#[cfg(taproot)]
49834983
partial_signature_with_nonce: None,
49844984
})
@@ -5948,10 +5948,6 @@ impl<SP: Deref> FundedChannel<SP> where
59485948
)));
59495949
}
59505950

5951-
if msg.batch.is_some() {
5952-
return Err(ChannelError::close("Peer sent initial commitment_signed with a batch".to_owned()));
5953-
}
5954-
59555951
let holder_commitment_point = &mut self.holder_commitment_point.clone();
59565952
self.context.assert_no_commitment_advancement(holder_commitment_point.transaction_number(), "initial commitment_signed");
59575953

@@ -9349,20 +9345,11 @@ impl<SP: Deref> FundedChannel<SP> where
93499345
}
93509346
}
93519347

9352-
let batch = if self.pending_funding.is_empty() { None } else {
9353-
Some(msgs::CommitmentSignedBatch {
9354-
batch_size: self.pending_funding.len() as u16 + 1,
9355-
funding_txid: funding
9356-
.get_funding_txo()
9357-
.expect("splices should have their funding transactions negotiated before exiting quiescence while un-negotiated splices are discarded on reload")
9358-
.txid,
9359-
})
9360-
};
93619348
Ok(msgs::CommitmentSigned {
93629349
channel_id: self.context.channel_id,
93639350
signature,
93649351
htlc_signatures,
9365-
batch,
9352+
funding_txid: funding.get_funding_txo().map(|funding_txo| funding_txo.txid),
93669353
#[cfg(taproot)]
93679354
partial_signature_with_nonce: None,
93689355
})

lightning/src/ln/dual_funding_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession)
185185
)
186186
.unwrap(),
187187
htlc_signatures: vec![],
188-
batch: None,
188+
funding_txid: None,
189189
#[cfg(taproot)]
190190
partial_signature_with_nonce: None,
191191
};

lightning/src/ln/htlc_reserve_unit_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ pub fn test_fee_spike_violation_fails_htlc() {
899899
channel_id: chan.2,
900900
signature: res.0,
901901
htlc_signatures: res.1,
902-
batch: None,
902+
funding_txid: None,
903903
#[cfg(taproot)]
904904
partial_signature_with_nonce: None,
905905
};

lightning/src/ln/msgs.rs

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -807,15 +807,6 @@ pub struct UpdateFailMalformedHTLC {
807807
pub failure_code: u16,
808808
}
809809

810-
/// Optional batch parameters for `commitment_signed` message.
811-
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
812-
pub struct CommitmentSignedBatch {
813-
/// Batch size N: all N `commitment_signed` messages must be received before being processed
814-
pub batch_size: u16,
815-
/// The funding transaction, to discriminate among multiple pending funding transactions (e.g. in case of splicing)
816-
pub funding_txid: Txid,
817-
}
818-
819810
/// A [`commitment_signed`] message to be sent to or received from a peer.
820811
///
821812
/// [`commitment_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#committing-updates-so-far-commitment_signed
@@ -827,8 +818,8 @@ pub struct CommitmentSigned {
827818
pub signature: Signature,
828819
/// Signatures on the HTLC transactions
829820
pub htlc_signatures: Vec<Signature>,
830-
/// Optional batch size and other parameters
831-
pub batch: Option<CommitmentSignedBatch>,
821+
/// The funding transaction, to discriminate among multiple pending funding transactions (e.g. in case of splicing)
822+
pub funding_txid: Option<Txid>,
832823
#[cfg(taproot)]
833824
/// The partial Taproot signature on the commitment transaction
834825
pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
@@ -1986,15 +1977,14 @@ pub trait ChannelMessageHandler: BaseMessageHandler {
19861977
) {
19871978
assert!(!batch.is_empty());
19881979
if batch.len() == 1 {
1989-
assert!(batch[0].batch.is_none());
19901980
self.handle_commitment_signed(their_node_id, &batch[0]);
19911981
} else {
19921982
let channel_id = batch[0].channel_id;
19931983
let batch: BTreeMap<Txid, CommitmentSigned> = batch
19941984
.iter()
19951985
.cloned()
1996-
.map(|mut cs| {
1997-
let funding_txid = cs.batch.take().unwrap().funding_txid;
1986+
.map(|cs| {
1987+
let funding_txid = cs.funding_txid.unwrap();
19981988
(funding_txid, cs)
19991989
})
20001990
.collect();
@@ -2768,18 +2758,14 @@ impl_writeable!(ClosingSignedFeeRange, {
27682758
max_fee_satoshis
27692759
});
27702760

2771-
impl_writeable_msg!(CommitmentSignedBatch, {
2772-
batch_size,
2773-
funding_txid,
2774-
}, {});
2775-
27762761
#[cfg(not(taproot))]
27772762
impl_writeable_msg!(CommitmentSigned, {
27782763
channel_id,
27792764
signature,
27802765
htlc_signatures
27812766
}, {
2782-
(0, batch, option),
2767+
// TOOD(splicing): Change this to 1 once the spec is finalized
2768+
(1001, funding_txid, option),
27832769
});
27842770

27852771
#[cfg(taproot)]
@@ -2788,8 +2774,9 @@ impl_writeable_msg!(CommitmentSigned, {
27882774
signature,
27892775
htlc_signatures
27902776
}, {
2791-
(0, batch, option),
27922777
(2, partial_signature_with_nonce, option),
2778+
// TOOD(splicing): Change this to 1 and reorder once the spec is finalized
2779+
(1001, funding_txid, option),
27932780
});
27942781

27952782
impl_writeable!(DecodedOnionErrorPacket, {
@@ -5649,13 +5636,10 @@ mod tests {
56495636
channel_id: ChannelId::from_bytes([2; 32]),
56505637
signature: sig_1,
56515638
htlc_signatures: if htlcs { vec![sig_2, sig_3, sig_4] } else { Vec::new() },
5652-
batch: Some(msgs::CommitmentSignedBatch {
5653-
batch_size: 3,
5654-
funding_txid: Txid::from_str(
5655-
"c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e",
5656-
)
5657-
.unwrap(),
5658-
}),
5639+
funding_txid: Some(
5640+
Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e")
5641+
.unwrap(),
5642+
),
56595643
#[cfg(taproot)]
56605644
partial_signature_with_nonce: None,
56615645
};
@@ -5666,7 +5650,9 @@ mod tests {
56665650
} else {
56675651
target_value += "0000";
56685652
}
5669-
target_value += "002200036e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2"; // batch
5653+
target_value += "fd03e9"; // Type (funding_txid)
5654+
target_value += "20"; // Length (funding_txid)
5655+
target_value += "6e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2"; // Value
56705656
assert_eq!(encoded_value.as_hex().to_string(), target_value);
56715657
}
56725658

lightning/src/ln/peer_handler.rs

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ struct Peer {
620620

621621
inbound_connection: bool,
622622

623-
commitment_signed_batch: Option<(ChannelId, BTreeMap<Txid, msgs::CommitmentSigned>)>,
623+
commitment_signed_batch: Option<(ChannelId, usize, BTreeMap<Txid, msgs::CommitmentSigned>)>,
624624
}
625625

626626
impl Peer {
@@ -1772,41 +1772,95 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
17721772

17731773
// During splicing, commitment_signed messages need to be collected into a single batch
17741774
// before they are handled.
1775-
if let wire::Message::CommitmentSigned(msg) = message {
1776-
if let Some(ref batch) = msg.batch {
1777-
let (channel_id, buffer) = peer_lock
1778-
.commitment_signed_batch
1779-
.get_or_insert_with(|| (msg.channel_id, BTreeMap::new()));
1775+
if let wire::Message::StartBatch(msg) = message {
1776+
if peer_lock.commitment_signed_batch.is_some() {
1777+
let error = format!("Peer {} sent start_batch for channel {} before previous batch completed", log_pubkey!(their_node_id), &msg.channel_id);
1778+
log_debug!(logger, "{}", error);
1779+
return Err(LightningError {
1780+
err: error.clone(),
1781+
action: msgs::ErrorAction::DisconnectPeerWithWarning {
1782+
msg: msgs::WarningMessage {
1783+
channel_id: msg.channel_id,
1784+
data: error,
1785+
},
1786+
},
1787+
}.into());
1788+
}
1789+
1790+
let batch_size = msg.batch_size as usize;
1791+
if batch_size <= 1 {
1792+
let error = format!("Peer {} sent start_batch for channel {} not strictly greater than 1", log_pubkey!(their_node_id), &msg.channel_id);
1793+
log_debug!(logger, "{}", error);
1794+
return Err(LightningError {
1795+
err: error.clone(),
1796+
action: msgs::ErrorAction::SendWarningMessage {
1797+
msg: msgs::WarningMessage {
1798+
channel_id: msg.channel_id,
1799+
data: error,
1800+
},
1801+
log_level: Level::Debug,
1802+
},
1803+
}.into());
1804+
}
17801805

1806+
const COMMITMENT_SIGNED_BATCH_LIMIT: usize = 20;
1807+
if batch_size > COMMITMENT_SIGNED_BATCH_LIMIT {
1808+
let error = format!("Peer {} sent start_batch for channel {} exceeding the limit", log_pubkey!(their_node_id), &msg.channel_id);
1809+
log_debug!(logger, "{}", error);
1810+
return Err(LightningError {
1811+
err: error.clone(),
1812+
action: msgs::ErrorAction::DisconnectPeerWithWarning {
1813+
msg: msgs::WarningMessage {
1814+
channel_id: msg.channel_id,
1815+
data: error,
1816+
},
1817+
},
1818+
}.into());
1819+
}
1820+
1821+
peer_lock.commitment_signed_batch = Some((msg.channel_id, batch_size, BTreeMap::new()));
1822+
1823+
return Ok(None);
1824+
}
1825+
1826+
if let wire::Message::CommitmentSigned(msg) = message {
1827+
if let Some((channel_id, batch_size, buffer)) = &mut peer_lock.commitment_signed_batch {
17811828
if msg.channel_id != *channel_id {
1782-
log_debug!(logger, "Peer {} sent batched commitment_signed for the wrong channel (expected: {}, actual: {})", log_pubkey!(their_node_id), channel_id, &msg.channel_id);
1783-
return Err(PeerHandleError { }.into());
1829+
let error = format!("Peer {} sent batched commitment_signed for the wrong channel (expected: {}, actual: {})", log_pubkey!(their_node_id), channel_id, &msg.channel_id);
1830+
log_debug!(logger, "{}", error);
1831+
return Err(LightningError {
1832+
err: error.clone(),
1833+
action: msgs::ErrorAction::DisconnectPeerWithWarning {
1834+
msg: msgs::WarningMessage {
1835+
channel_id: msg.channel_id,
1836+
data: error,
1837+
},
1838+
},
1839+
}.into());
17841840
}
17851841

1786-
const COMMITMENT_SIGNED_BATCH_LIMIT: usize = 100;
1787-
if buffer.len() == COMMITMENT_SIGNED_BATCH_LIMIT {
1788-
log_debug!(logger, "Peer {} sent batched commitment_signed for channel {} exceeding the limit", log_pubkey!(their_node_id), channel_id);
1789-
return Err(PeerHandleError { }.into());
1790-
}
1842+
let funding_txid = match msg.funding_txid {
1843+
Some(funding_txid) => funding_txid,
1844+
None => {
1845+
log_debug!(logger, "Peer {} sent batched commitment_signed without a funding_txid for channel {}", log_pubkey!(their_node_id), channel_id);
1846+
return Err(PeerHandleError { }.into());
1847+
},
1848+
};
17911849

1792-
let batch_size = batch.batch_size as usize;
1793-
match buffer.entry(batch.funding_txid) {
1850+
match buffer.entry(funding_txid) {
17941851
btree_map::Entry::Vacant(entry) => { entry.insert(msg); },
17951852
btree_map::Entry::Occupied(_) => {
1796-
log_debug!(logger, "Peer {} sent batched commitment_signed with duplicate funding_txid {} for channel {}", log_pubkey!(their_node_id), channel_id, &batch.funding_txid);
1853+
log_debug!(logger, "Peer {} sent batched commitment_signed with duplicate funding_txid {} for channel {}", log_pubkey!(their_node_id), funding_txid, channel_id);
17971854
return Err(PeerHandleError { }.into());
17981855
}
17991856
}
18001857

1801-
if buffer.len() >= batch_size {
1802-
let (channel_id, batch) = peer_lock.commitment_signed_batch.take().expect("batch should have been inserted");
1858+
if buffer.len() == *batch_size {
1859+
let (channel_id, _, batch) = peer_lock.commitment_signed_batch.take().expect("batch should have been inserted");
18031860
return Ok(Some(LogicalMessage::CommitmentSignedBatch(channel_id, batch)));
18041861
} else {
18051862
return Ok(None);
18061863
}
1807-
} else if peer_lock.commitment_signed_batch.is_some() {
1808-
log_debug!(logger, "Peer {} sent non-batched commitment_signed for channel {} when expecting batched commitment_signed", log_pubkey!(their_node_id), &msg.channel_id);
1809-
return Err(PeerHandleError { }.into());
18101864
} else {
18111865
return Ok(Some(LogicalMessage::FromWire(wire::Message::CommitmentSigned(msg))));
18121866
}
@@ -2407,6 +2461,13 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
24072461
if let &Some(ref msg) = update_fee {
24082462
self.enqueue_message(&mut *peer, msg);
24092463
}
2464+
if commitment_signed.len() > 1 {
2465+
let msg = msgs::StartBatch {
2466+
channel_id: *channel_id,
2467+
batch_size: commitment_signed.len() as u16,
2468+
};
2469+
self.enqueue_message(&mut *peer, &msg);
2470+
}
24102471
for msg in commitment_signed {
24112472
self.enqueue_message(&mut *peer, msg);
24122473
}

lightning/src/ln/update_fee_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ pub fn do_test_update_fee_that_funder_cannot_afford(channel_type_features: Chann
520520
channel_id: chan.2,
521521
signature: res.0,
522522
htlc_signatures: res.1,
523-
batch: None,
523+
funding_txid: None,
524524
#[cfg(taproot)]
525525
partial_signature_with_nonce: None,
526526
};
@@ -621,7 +621,7 @@ pub fn test_update_fee_that_saturates_subs() {
621621
channel_id: chan_id,
622622
signature: res.0,
623623
htlc_signatures: res.1,
624-
batch: None,
624+
funding_txid: None,
625625
#[cfg(taproot)]
626626
partial_signature_with_nonce: None,
627627
};

0 commit comments

Comments
 (0)