Skip to content

Commit 34f8dd9

Browse files
authored
Merge pull request #2658 from wpaulino/bogus-channel-reestablish
Send bogus ChannelReestablish for unknown channels
2 parents 28602d9 + ed38eac commit 34f8dd9

7 files changed

+175
-55
lines changed

lightning/src/ln/channel.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3993,7 +3993,7 @@ impl<SP: Deref> Channel<SP> where
39933993

39943994
if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER ||
39953995
msg.next_local_commitment_number == 0 {
3996-
return Err(ChannelError::Close("Peer sent a garbage channel_reestablish (usually an lnd node with lost state asking us to force-close for them)".to_owned()));
3996+
return Err(ChannelError::Close("Peer sent an invalid channel_reestablish to force close in a non-standard way".to_owned()));
39973997
}
39983998

39993999
if msg.next_remote_commitment_number > 0 {

lightning/src/ln/channelmanager.rs

+121-21
Original file line numberDiff line numberDiff line change
@@ -447,16 +447,17 @@ impl MsgHandleErrInternal {
447447
}
448448
#[inline]
449449
fn from_finish_shutdown(err: String, channel_id: ChannelId, user_channel_id: u128, shutdown_res: ShutdownResult, channel_update: Option<msgs::ChannelUpdate>, channel_capacity: u64) -> Self {
450+
let err_msg = msgs::ErrorMessage { channel_id, data: err.clone() };
451+
let action = if let (Some(_), ..) = &shutdown_res {
452+
// We have a closing `ChannelMonitorUpdate`, which means the channel was funded and we
453+
// should disconnect our peer such that we force them to broadcast their latest
454+
// commitment upon reconnecting.
455+
msgs::ErrorAction::DisconnectPeer { msg: Some(err_msg) }
456+
} else {
457+
msgs::ErrorAction::SendErrorMessage { msg: err_msg }
458+
};
450459
Self {
451-
err: LightningError {
452-
err: err.clone(),
453-
action: msgs::ErrorAction::SendErrorMessage {
454-
msg: msgs::ErrorMessage {
455-
channel_id,
456-
data: err
457-
},
458-
},
459-
},
460+
err: LightningError { err, action },
460461
chan_id: Some((channel_id, user_channel_id)),
461462
shutdown_finish: Some((shutdown_res, channel_update)),
462463
channel_capacity: Some(channel_capacity)
@@ -2814,8 +2815,8 @@ where
28142815
peer_state.pending_msg_events.push(
28152816
events::MessageSendEvent::HandleError {
28162817
node_id: counterparty_node_id,
2817-
action: msgs::ErrorAction::SendErrorMessage {
2818-
msg: msgs::ErrorMessage { channel_id: *channel_id, data: "Channel force-closed".to_owned() }
2818+
action: msgs::ErrorAction::DisconnectPeer {
2819+
msg: Some(msgs::ErrorMessage { channel_id: *channel_id, data: "Channel force-closed".to_owned() })
28192820
},
28202821
}
28212822
);
@@ -4298,8 +4299,9 @@ where
42984299
}
42994300
}
43004301
}
4301-
let (counterparty_node_id, forward_chan_id) = match self.short_to_chan_info.read().unwrap().get(&short_chan_id) {
4302-
Some((cp_id, chan_id)) => (cp_id.clone(), chan_id.clone()),
4302+
let chan_info_opt = self.short_to_chan_info.read().unwrap().get(&short_chan_id).cloned();
4303+
let (counterparty_node_id, forward_chan_id) = match chan_info_opt {
4304+
Some((cp_id, chan_id)) => (cp_id, chan_id),
43034305
None => {
43044306
forwarding_channel_not_found!();
43054307
continue;
@@ -6787,7 +6789,10 @@ where
67876789
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
67886790
.ok_or_else(|| {
67896791
debug_assert!(false);
6790-
MsgHandleErrInternal::send_err_msg_no_close(format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id), msg.channel_id)
6792+
MsgHandleErrInternal::send_err_msg_no_close(
6793+
format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id),
6794+
msg.channel_id
6795+
)
67916796
})?;
67926797
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
67936798
let peer_state = &mut *peer_state_lock;
@@ -6831,7 +6836,39 @@ where
68316836
"Got a channel_reestablish message for an unfunded channel!".into())), chan_phase_entry);
68326837
}
68336838
},
6834-
hash_map::Entry::Vacant(_) => return 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), msg.channel_id))
6839+
hash_map::Entry::Vacant(_) => {
6840+
log_debug!(self.logger, "Sending bogus ChannelReestablish for unknown channel {} to force channel closure",
6841+
log_bytes!(msg.channel_id.0));
6842+
// Unfortunately, lnd doesn't force close on errors
6843+
// (https://github.com/lightningnetwork/lnd/blob/abb1e3463f3a83bbb843d5c399869dbe930ad94f/htlcswitch/link.go#L2119).
6844+
// One of the few ways to get an lnd counterparty to force close is by
6845+
// replicating what they do when restoring static channel backups (SCBs). They
6846+
// send an invalid `ChannelReestablish` with `0` commitment numbers and an
6847+
// invalid `your_last_per_commitment_secret`.
6848+
//
6849+
// Since we received a `ChannelReestablish` for a channel that doesn't exist, we
6850+
// can assume it's likely the channel closed from our point of view, but it
6851+
// remains open on the counterparty's side. By sending this bogus
6852+
// `ChannelReestablish` message now as a response to theirs, we trigger them to
6853+
// force close broadcasting their latest state. If the closing transaction from
6854+
// our point of view remains unconfirmed, it'll enter a race with the
6855+
// counterparty's to-be-broadcast latest commitment transaction.
6856+
peer_state.pending_msg_events.push(MessageSendEvent::SendChannelReestablish {
6857+
node_id: *counterparty_node_id,
6858+
msg: msgs::ChannelReestablish {
6859+
channel_id: msg.channel_id,
6860+
next_local_commitment_number: 0,
6861+
next_remote_commitment_number: 0,
6862+
your_last_per_commitment_secret: [1u8; 32],
6863+
my_current_per_commitment_point: PublicKey::from_slice(&[2u8; 33]).unwrap(),
6864+
next_funding_txid: None,
6865+
},
6866+
});
6867+
return Err(MsgHandleErrInternal::send_err_msg_no_close(
6868+
format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}",
6869+
counterparty_node_id), msg.channel_id)
6870+
)
6871+
}
68356872
}
68366873
};
68376874

@@ -6895,8 +6932,8 @@ where
68956932
self.issue_channel_close_events(&chan.context, ClosureReason::HolderForceClosed);
68966933
pending_msg_events.push(events::MessageSendEvent::HandleError {
68976934
node_id: chan.context.get_counterparty_node_id(),
6898-
action: msgs::ErrorAction::SendErrorMessage {
6899-
msg: msgs::ErrorMessage { channel_id: chan.context.channel_id(), data: "Channel force-closed".to_owned() }
6935+
action: msgs::ErrorAction::DisconnectPeer {
6936+
msg: Some(msgs::ErrorMessage { channel_id: chan.context.channel_id(), data: "Channel force-closed".to_owned() })
69006937
},
69016938
});
69026939
}
@@ -7680,10 +7717,12 @@ where
76807717
self.issue_channel_close_events(&channel.context, reason);
76817718
pending_msg_events.push(events::MessageSendEvent::HandleError {
76827719
node_id: channel.context.get_counterparty_node_id(),
7683-
action: msgs::ErrorAction::SendErrorMessage { msg: msgs::ErrorMessage {
7684-
channel_id: channel.context.channel_id(),
7685-
data: reason_message,
7686-
} },
7720+
action: msgs::ErrorAction::DisconnectPeer {
7721+
msg: Some(msgs::ErrorMessage {
7722+
channel_id: channel.context.channel_id(),
7723+
data: reason_message,
7724+
})
7725+
},
76877726
});
76887727
return false;
76897728
}
@@ -11285,6 +11324,67 @@ mod tests {
1128511324
let payment_preimage = PaymentPreimage([42; 32]);
1128611325
assert_eq!(format!("{}", &payment_preimage), "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a");
1128711326
}
11327+
11328+
#[test]
11329+
fn test_trigger_lnd_force_close() {
11330+
let chanmon_cfg = create_chanmon_cfgs(2);
11331+
let node_cfg = create_node_cfgs(2, &chanmon_cfg);
11332+
let user_config = test_default_channel_config();
11333+
let node_chanmgr = create_node_chanmgrs(2, &node_cfg, &[Some(user_config), Some(user_config)]);
11334+
let nodes = create_network(2, &node_cfg, &node_chanmgr);
11335+
11336+
// Open a channel, immediately disconnect each other, and broadcast Alice's latest state.
11337+
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
11338+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
11339+
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
11340+
nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
11341+
check_closed_broadcast(&nodes[0], 1, true);
11342+
check_added_monitors(&nodes[0], 1);
11343+
check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
11344+
{
11345+
let txn = nodes[0].tx_broadcaster.txn_broadcast();
11346+
assert_eq!(txn.len(), 1);
11347+
check_spends!(txn[0], funding_tx);
11348+
}
11349+
11350+
// Since they're disconnected, Bob won't receive Alice's `Error` message. Reconnect them
11351+
// such that Bob sends a `ChannelReestablish` to Alice since the channel is still open from
11352+
// their side.
11353+
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
11354+
features: nodes[1].node.init_features(), networks: None, remote_network_address: None
11355+
}, true).unwrap();
11356+
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
11357+
features: nodes[0].node.init_features(), networks: None, remote_network_address: None
11358+
}, false).unwrap();
11359+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
11360+
let channel_reestablish = get_event_msg!(
11361+
nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()
11362+
);
11363+
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &channel_reestablish);
11364+
11365+
// Alice should respond with an error since the channel isn't known, but a bogus
11366+
// `ChannelReestablish` should be sent first, such that we actually trigger Bob to force
11367+
// close even if it was an lnd node.
11368+
let msg_events = nodes[0].node.get_and_clear_pending_msg_events();
11369+
assert_eq!(msg_events.len(), 2);
11370+
if let MessageSendEvent::SendChannelReestablish { node_id, msg } = &msg_events[0] {
11371+
assert_eq!(*node_id, nodes[1].node.get_our_node_id());
11372+
assert_eq!(msg.next_local_commitment_number, 0);
11373+
assert_eq!(msg.next_remote_commitment_number, 0);
11374+
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &msg);
11375+
} else { panic!() };
11376+
check_closed_broadcast(&nodes[1], 1, true);
11377+
check_added_monitors(&nodes[1], 1);
11378+
let expected_close_reason = ClosureReason::ProcessingError {
11379+
err: "Peer sent an invalid channel_reestablish to force close in a non-standard way".to_string()
11380+
};
11381+
check_closed_event!(nodes[1], 1, expected_close_reason, [nodes[0].node.get_our_node_id()], 100000);
11382+
{
11383+
let txn = nodes[1].tx_broadcaster.txn_broadcast();
11384+
assert_eq!(txn.len(), 1);
11385+
check_spends!(txn[0], funding_tx);
11386+
}
11387+
}
1128811388
}
1128911389

1129011390
#[cfg(ldk_bench)]

lightning/src/ln/functional_test_utils.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,12 @@ pub fn get_err_msg(node: &Node, recipient: &PublicKey) -> msgs::ErrorMessage {
665665
assert_eq!(node_id, recipient);
666666
(*msg).clone()
667667
},
668+
MessageSendEvent::HandleError {
669+
action: msgs::ErrorAction::DisconnectPeer { ref msg }, ref node_id
670+
} => {
671+
assert_eq!(node_id, recipient);
672+
msg.as_ref().unwrap().clone()
673+
},
668674
_ => panic!("Unexpected event"),
669675
}
670676
}
@@ -1446,10 +1452,15 @@ pub fn check_closed_broadcast(node: &Node, num_channels: usize, with_error_msg:
14461452
assert_eq!(msg.contents.flags & 2, 2);
14471453
None
14481454
},
1449-
MessageSendEvent::HandleError { action: msgs::ErrorAction::SendErrorMessage { ref msg }, node_id: _ } => {
1455+
MessageSendEvent::HandleError { action: msgs::ErrorAction::SendErrorMessage { msg }, node_id: _ } => {
14501456
assert!(with_error_msg);
14511457
// TODO: Check node_id
1452-
Some(msg.clone())
1458+
Some(msg)
1459+
},
1460+
MessageSendEvent::HandleError { action: msgs::ErrorAction::DisconnectPeer { msg }, node_id: _ } => {
1461+
assert!(with_error_msg);
1462+
// TODO: Check node_id
1463+
Some(msg.unwrap())
14531464
},
14541465
_ => panic!("Unexpected event"),
14551466
}
@@ -2921,6 +2932,13 @@ pub fn handle_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, '
29212932
nodes[b].node.handle_error(&nodes[a].node.get_our_node_id(), msg);
29222933
}
29232934
},
2935+
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::DisconnectPeer { ref msg } } => {
2936+
assert_eq!(node_id, nodes[b].node.get_our_node_id());
2937+
assert_eq!(msg.as_ref().unwrap().data, expected_error);
2938+
if needs_err_handle {
2939+
nodes[b].node.handle_error(&nodes[a].node.get_our_node_id(), msg.as_ref().unwrap());
2940+
}
2941+
},
29242942
_ => panic!("Unexpected event"),
29252943
}
29262944

@@ -2938,6 +2956,10 @@ pub fn handle_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, '
29382956
assert_eq!(node_id, nodes[a].node.get_our_node_id());
29392957
assert_eq!(msg.data, expected_error);
29402958
},
2959+
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::DisconnectPeer { ref msg } } => {
2960+
assert_eq!(node_id, nodes[a].node.get_our_node_id());
2961+
assert_eq!(msg.as_ref().unwrap().data, expected_error);
2962+
},
29412963
_ => panic!("Unexpected event"),
29422964
}
29432965
}

lightning/src/ln/functional_tests.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -1338,9 +1338,9 @@ fn test_duplicate_htlc_different_direction_onchain() {
13381338
for e in events {
13391339
match e {
13401340
MessageSendEvent::BroadcastChannelUpdate { .. } => {},
1341-
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::SendErrorMessage { ref msg } } => {
1341+
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::DisconnectPeer { ref msg } } => {
13421342
assert_eq!(node_id, nodes[1].node.get_our_node_id());
1343-
assert_eq!(msg.data, "Channel closed because commitment or closing transaction was confirmed on chain.");
1343+
assert_eq!(msg.as_ref().unwrap().data, "Channel closed because commitment or closing transaction was confirmed on chain.");
13441344
},
13451345
MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => {
13461346
assert!(update_add_htlcs.is_empty());
@@ -2369,7 +2369,7 @@ fn channel_monitor_network_test() {
23692369
_ => panic!("Unexpected event"),
23702370
};
23712371
match events[1] {
2372-
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { .. }, node_id } => {
2372+
MessageSendEvent::HandleError { action: ErrorAction::DisconnectPeer { .. }, node_id } => {
23732373
assert_eq!(node_id, nodes[4].node.get_our_node_id());
23742374
},
23752375
_ => panic!("Unexpected event"),
@@ -2401,7 +2401,7 @@ fn channel_monitor_network_test() {
24012401
_ => panic!("Unexpected event"),
24022402
};
24032403
match events[1] {
2404-
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { .. }, node_id } => {
2404+
MessageSendEvent::HandleError { action: ErrorAction::DisconnectPeer { .. }, node_id } => {
24052405
assert_eq!(node_id, nodes[3].node.get_our_node_id());
24062406
},
24072407
_ => panic!("Unexpected event"),
@@ -2913,7 +2913,7 @@ fn test_htlc_on_chain_success() {
29132913
let nodes_0_event = remove_first_msg_event_to_node(&nodes[0].node.get_our_node_id(), &mut events);
29142914

29152915
match nodes_2_event {
2916-
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { .. }, node_id: _ } => {},
2916+
MessageSendEvent::HandleError { action: ErrorAction::DisconnectPeer { .. }, node_id: _ } => {},
29172917
_ => panic!("Unexpected event"),
29182918
}
29192919

@@ -3358,7 +3358,7 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use
33583358

33593359
let nodes_2_event = remove_first_msg_event_to_node(&nodes[2].node.get_our_node_id(), &mut events);
33603360
match nodes_2_event {
3361-
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { msg: msgs::ErrorMessage { channel_id, ref data } }, node_id: _ } => {
3361+
MessageSendEvent::HandleError { action: ErrorAction::DisconnectPeer { msg: Some(msgs::ErrorMessage { channel_id, ref data }) }, node_id: _ } => {
33623362
assert_eq!(channel_id, chan_2.2);
33633363
assert_eq!(data.as_str(), "Channel closed because commitment or closing transaction was confirmed on chain.");
33643364
},
@@ -4920,7 +4920,7 @@ fn test_onchain_to_onchain_claim() {
49204920
let nodes_0_event = remove_first_msg_event_to_node(&nodes[0].node.get_our_node_id(), &mut msg_events);
49214921

49224922
match nodes_2_event {
4923-
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { .. }, node_id: _ } => {},
4923+
MessageSendEvent::HandleError { action: ErrorAction::DisconnectPeer { .. }, node_id: _ } => {},
49244924
_ => panic!("Unexpected event"),
49254925
}
49264926

@@ -7860,9 +7860,9 @@ fn test_channel_conf_timeout() {
78607860
let close_ev = nodes[1].node.get_and_clear_pending_msg_events();
78617861
assert_eq!(close_ev.len(), 1);
78627862
match close_ev[0] {
7863-
MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg }, ref node_id } => {
7863+
MessageSendEvent::HandleError { action: ErrorAction::DisconnectPeer { ref msg }, ref node_id } => {
78647864
assert_eq!(*node_id, nodes[0].node.get_our_node_id());
7865-
assert_eq!(msg.data, "Channel closed because funding transaction failed to confirm within 2016 blocks");
7865+
assert_eq!(msg.as_ref().unwrap().data, "Channel closed because funding transaction failed to confirm within 2016 blocks");
78667866
},
78677867
_ => panic!("Unexpected event"),
78687868
}
@@ -9212,8 +9212,8 @@ fn test_invalid_funding_tx() {
92129212
assert_eq!(events_2.len(), 1);
92139213
if let MessageSendEvent::HandleError { node_id, action } = &events_2[0] {
92149214
assert_eq!(*node_id, nodes[0].node.get_our_node_id());
9215-
if let msgs::ErrorAction::SendErrorMessage { msg } = action {
9216-
assert_eq!(msg.data, "Channel closed because of an exception: ".to_owned() + expected_err);
9215+
if let msgs::ErrorAction::DisconnectPeer { msg } = action {
9216+
assert_eq!(msg.as_ref().unwrap().data, "Channel closed because of an exception: ".to_owned() + expected_err);
92179217
} else { panic!(); }
92189218
} else { panic!(); }
92199219
assert_eq!(nodes[1].node.list_channels().len(), 0);
@@ -10652,7 +10652,7 @@ fn do_test_funding_and_commitment_tx_confirm_same_block(confirm_remote_commitmen
1065210652
let mut msg_events = closing_node.node.get_and_clear_pending_msg_events();
1065310653
assert_eq!(msg_events.len(), 1);
1065410654
match msg_events.pop().unwrap() {
10655-
MessageSendEvent::HandleError { action: msgs::ErrorAction::SendErrorMessage { .. }, .. } => {},
10655+
MessageSendEvent::HandleError { action: msgs::ErrorAction::DisconnectPeer { .. }, .. } => {},
1065610656
_ => panic!("Unexpected event"),
1065710657
}
1065810658
check_added_monitors(closing_node, 1);

lightning/src/ln/payment_tests.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -707,8 +707,8 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
707707
let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
708708
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
709709
let as_err = nodes[0].node.get_and_clear_pending_msg_events();
710-
assert_eq!(as_err.len(), 1);
711-
match as_err[0] {
710+
assert_eq!(as_err.len(), 2);
711+
match as_err[1] {
712712
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::SendErrorMessage { ref msg } } => {
713713
assert_eq!(node_id, nodes[1].node.get_our_node_id());
714714
nodes[1].node.handle_error(&nodes[0].node.get_our_node_id(), msg);
@@ -882,9 +882,9 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) {
882882
let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
883883
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
884884
let as_err = nodes[0].node.get_and_clear_pending_msg_events();
885-
assert_eq!(as_err.len(), 1);
885+
assert_eq!(as_err.len(), 2);
886886
let bs_commitment_tx;
887-
match as_err[0] {
887+
match as_err[1] {
888888
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::SendErrorMessage { ref msg } } => {
889889
assert_eq!(node_id, nodes[1].node.get_our_node_id());
890890
nodes[1].node.handle_error(&nodes[0].node.get_our_node_id(), msg);

0 commit comments

Comments
 (0)