Skip to content

Commit 74f1007

Browse files
authored
Merge pull request #966 from TheBlueMatt/2021-06-workaround-broken-lnd
Workaround lnd sending funding_locked before channel_reestablish
2 parents ecddfe1 + 8df1412 commit 74f1007

File tree

3 files changed

+51
-12
lines changed

3 files changed

+51
-12
lines changed

lightning/src/ln/channel.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,15 @@ pub(super) struct Channel<Signer: Sign> {
434434
next_local_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
435435
#[cfg(any(test, feature = "fuzztarget"))]
436436
next_remote_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
437+
438+
/// lnd has a long-standing bug where, upon reconnection, if the channel is not yet confirmed
439+
/// they will not send a channel_reestablish until the channel locks in. Then, they will send a
440+
/// funding_locked *before* sending the channel_reestablish (which is clearly a violation of
441+
/// the BOLT specs). We copy c-lightning's workaround here and simply store the funding_locked
442+
/// message until we receive a channel_reestablish.
443+
///
444+
/// See-also <https://github.com/lightningnetwork/lnd/issues/4006>
445+
pub workaround_lnd_bug_4006: Option<msgs::FundingLocked>,
437446
}
438447

439448
#[cfg(any(test, feature = "fuzztarget"))]
@@ -633,6 +642,8 @@ impl<Signer: Sign> Channel<Signer> {
633642
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
634643
#[cfg(any(test, feature = "fuzztarget"))]
635644
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
645+
646+
workaround_lnd_bug_4006: None,
636647
})
637648
}
638649

@@ -876,6 +887,8 @@ impl<Signer: Sign> Channel<Signer> {
876887
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
877888
#[cfg(any(test, feature = "fuzztarget"))]
878889
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
890+
891+
workaround_lnd_bug_4006: None,
879892
};
880893

881894
Ok(chan)
@@ -1691,7 +1704,8 @@ impl<Signer: Sign> Channel<Signer> {
16911704

16921705
pub fn funding_locked(&mut self, msg: &msgs::FundingLocked) -> Result<(), ChannelError> {
16931706
if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
1694-
return Err(ChannelError::Close("Peer sent funding_locked when we needed a channel_reestablish".to_owned()));
1707+
self.workaround_lnd_bug_4006 = Some(msg.clone());
1708+
return Err(ChannelError::Ignore("Peer sent funding_locked when we needed a channel_reestablish. The peer is likely lnd, see https://github.com/lightningnetwork/lnd/issues/4006".to_owned()));
16951709
}
16961710

16971711
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
@@ -4863,6 +4877,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
48634877
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
48644878
#[cfg(any(test, feature = "fuzztarget"))]
48654879
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
4880+
4881+
workaround_lnd_bug_4006: None,
48664882
})
48674883
}
48684884
}

lightning/src/ln/channelmanager.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3365,7 +3365,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33653365
}
33663366

33673367
fn internal_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) -> Result<(), MsgHandleErrInternal> {
3368-
let (htlcs_failed_forward, chan_restoration_res) = {
3368+
let (htlcs_failed_forward, need_lnd_workaround, chan_restoration_res) = {
33693369
let mut channel_state_lock = self.channel_state.lock().unwrap();
33703370
let channel_state = &mut *channel_state_lock;
33713371

@@ -3386,13 +3386,19 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33863386
msg,
33873387
});
33883388
}
3389-
(htlcs_failed_forward, handle_chan_restoration_locked!(self, channel_state_lock, channel_state, chan, revoke_and_ack, commitment_update, order, monitor_update_opt, Vec::new(), None, funding_locked))
3389+
let need_lnd_workaround = chan.get_mut().workaround_lnd_bug_4006.take();
3390+
(htlcs_failed_forward, need_lnd_workaround,
3391+
handle_chan_restoration_locked!(self, channel_state_lock, channel_state, chan, revoke_and_ack, commitment_update, order, monitor_update_opt, Vec::new(), None, funding_locked))
33903392
},
33913393
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
33923394
}
33933395
};
33943396
post_handle_chan_restoration!(self, chan_restoration_res);
33953397
self.fail_holding_cell_htlcs(htlcs_failed_forward, msg.channel_id);
3398+
3399+
if let Some(funding_locked_msg) = need_lnd_workaround {
3400+
self.internal_funding_locked(counterparty_node_id, &funding_locked_msg)?;
3401+
}
33963402
Ok(())
33973403
}
33983404

lightning/src/ln/functional_tests.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3605,15 +3605,20 @@ fn test_simple_peer_disconnect() {
36053605
fail_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), payment_hash_6);
36063606
}
36073607

3608-
fn do_test_drop_messages_peer_disconnect(messages_delivered: u8) {
3608+
fn do_test_drop_messages_peer_disconnect(messages_delivered: u8, simulate_broken_lnd: bool) {
36093609
// Test that we can reconnect when in-flight HTLC updates get dropped
36103610
let chanmon_cfgs = create_chanmon_cfgs(2);
36113611
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
36123612
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
36133613
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
3614+
3615+
let mut as_funding_locked = None;
36143616
if messages_delivered == 0 {
3615-
create_chan_between_nodes_with_value_a(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::known(), InitFeatures::known());
3617+
let (funding_locked, _, _) = create_chan_between_nodes_with_value_a(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::known(), InitFeatures::known());
3618+
as_funding_locked = Some(funding_locked);
36163619
// nodes[1] doesn't receive the funding_locked message (it'll be re-sent on reconnect)
3620+
// Note that we store it so that if we're running with `simulate_broken_lnd` we can deliver
3621+
// it before the channel_reestablish message.
36173622
} else {
36183623
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
36193624
}
@@ -3668,6 +3673,17 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8) {
36683673
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
36693674
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
36703675
if messages_delivered < 3 {
3676+
if simulate_broken_lnd {
3677+
// lnd has a long-standing bug where they send a funding_locked prior to a
3678+
// channel_reestablish if you reconnect prior to funding_locked time.
3679+
//
3680+
// Here we simulate that behavior, delivering a funding_locked immediately on
3681+
// reconnect. Note that we don't bother skipping the now-duplicate funding_locked sent
3682+
// in `reconnect_nodes` but we currently don't fail based on that.
3683+
//
3684+
// See-also <https://github.com/lightningnetwork/lnd/issues/4006>
3685+
nodes[1].node.handle_funding_locked(&nodes[0].node.get_our_node_id(), &as_funding_locked.as_ref().unwrap().0);
3686+
}
36713687
// Even if the funding_locked messages get exchanged, as long as nothing further was
36723688
// received on either side, both sides will need to resend them.
36733689
reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 1), (0, 0), (0, 0), (0, 0), (false, false));
@@ -3811,17 +3827,18 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8) {
38113827

38123828
#[test]
38133829
fn test_drop_messages_peer_disconnect_a() {
3814-
do_test_drop_messages_peer_disconnect(0);
3815-
do_test_drop_messages_peer_disconnect(1);
3816-
do_test_drop_messages_peer_disconnect(2);
3817-
do_test_drop_messages_peer_disconnect(3);
3830+
do_test_drop_messages_peer_disconnect(0, true);
3831+
do_test_drop_messages_peer_disconnect(0, false);
3832+
do_test_drop_messages_peer_disconnect(1, false);
3833+
do_test_drop_messages_peer_disconnect(2, false);
38183834
}
38193835

38203836
#[test]
38213837
fn test_drop_messages_peer_disconnect_b() {
3822-
do_test_drop_messages_peer_disconnect(4);
3823-
do_test_drop_messages_peer_disconnect(5);
3824-
do_test_drop_messages_peer_disconnect(6);
3838+
do_test_drop_messages_peer_disconnect(3, false);
3839+
do_test_drop_messages_peer_disconnect(4, false);
3840+
do_test_drop_messages_peer_disconnect(5, false);
3841+
do_test_drop_messages_peer_disconnect(6, false);
38253842
}
38263843

38273844
#[test]

0 commit comments

Comments
 (0)