Skip to content

Commit a9125e3

Browse files
committed
Support receiving multiple funding_locked messages
As a part of adding SCID aliases to channels, we now have to accept otherwise-redundant funding_locked messages which serve only to update the SCID alias. Previously, we'd failt he channel as such an update used to be bogus.
1 parent 95a2c96 commit a9125e3

File tree

2 files changed

+36
-11
lines changed

2 files changed

+36
-11
lines changed

lightning/src/ln/channel.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,17 +2177,28 @@ impl<Signer: Sign> Channel<Signer> {
21772177
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
21782178
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
21792179
self.update_time_counter += 1;
2180-
} else if (self.channel_state & (ChannelState::ChannelFunded as u32) != 0 &&
2181-
// Note that funding_signed/funding_created will have decremented both by 1!
2182-
self.cur_holder_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 &&
2183-
self.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1) ||
2184-
// If we reconnected before sending our funding locked they may still resend theirs:
2185-
(self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) ==
2186-
(ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32)) {
2187-
if self.counterparty_cur_commitment_point != Some(msg.next_per_commitment_point) {
2180+
} else if self.channel_state & (ChannelState::ChannelFunded as u32) != 0 ||
2181+
// If we reconnected before sending our funding locked they may still resend theirs:
2182+
(self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) ==
2183+
(ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32))
2184+
{
2185+
// They probably disconnected/reconnected and re-sent the funding_locked, which is
2186+
// required, or we're getting a fresh SCID alias.
2187+
let expected_point =
2188+
if self.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 {
2189+
// If they haven't ever sent an updated point, the point they send should match
2190+
// the current one.
2191+
self.counterparty_cur_commitment_point
2192+
} else {
2193+
// If they have sent updated points, funding_locked is always supposed to match
2194+
// their "first" point, which we re-derive here.
2195+
self.commitment_secrets.get_secret(INITIAL_COMMITMENT_NUMBER - 1)
2196+
.map(|secret| SecretKey::from_slice(&secret).ok()).flatten()
2197+
.map(|sk| PublicKey::from_secret_key(&self.secp_ctx, &sk))
2198+
};
2199+
if expected_point != Some(msg.next_per_commitment_point) {
21882200
return Err(ChannelError::Close("Peer sent a reconnect funding_locked with a different point".to_owned()));
21892201
}
2190-
// They probably disconnected/reconnected and re-sent the funding_locked, which is required
21912202
return Ok(None);
21922203
} else {
21932204
return Err(ChannelError::Close("Peer sent a funding_locked at a strange time".to_owned()));
@@ -4481,7 +4492,8 @@ impl<Signer: Sign> Channel<Signer> {
44814492
if need_commitment_update {
44824493
if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 {
44834494
if self.channel_state & (ChannelState::PeerDisconnected as u32) == 0 {
4484-
let next_per_commitment_point = self.holder_signer.get_per_commitment_point(self.cur_holder_commitment_transaction_number, &self.secp_ctx);
4495+
let next_per_commitment_point =
4496+
self.holder_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, &self.secp_ctx);
44854497
return Some(msgs::FundingLocked {
44864498
channel_id: self.channel_id,
44874499
next_per_commitment_point,

lightning/src/ln/priv_short_conf_tests.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ fn test_routed_scid_alias() {
249249
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
250250

251251
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).2;
252-
create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
252+
let mut as_funding_locked = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).0;
253253

254254
let last_hop = nodes[2].node.list_usable_channels();
255255
let hop_hints = vec![RouteHint(vec![RouteHintHop {
@@ -270,4 +270,17 @@ fn test_routed_scid_alias() {
270270

271271
pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], 100_000, payment_hash, payment_secret);
272272
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
273+
274+
// Now test that if a peer sends us a second funding_locked after the channel is operational we
275+
// will use the new alias.
276+
as_funding_locked.short_channel_id_alias = Some(0xdeadbeef);
277+
nodes[2].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &as_funding_locked);
278+
// Note that we always respond to a funding_locked with a channel_update. Not a lot of reason
279+
// to bother updating that code, so just drop the message here.
280+
get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
281+
let updated_channel_info = nodes[2].node.list_usable_channels();
282+
assert_eq!(updated_channel_info.len(), 1);
283+
assert_eq!(updated_channel_info[0].inbound_scid_alias.unwrap(), 0xdeadbeef);
284+
// Note that because we never send a duplicate funding_locked we can't send a payment through
285+
// the 0xdeadbeef SCID alias.
273286
}

0 commit comments

Comments
 (0)