Skip to content

Commit 96f6124

Browse files
committed
Don't create chan-closed mon update for outbound never-signed chans
Like the previous commit for channel-closed monitor updates for inbound channels during processing of a funding_created message, this resolves a more general issue for closing outbound channels which have sent a funding_created but not yet received a funding_signed. This issue was also detected by full_stack_target. To make similar issues easier to detect in testing and fuzzing, an additional assertion is added to panic on updates to a channel monitor before registering it.
1 parent b458cbc commit 96f6124

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

lightning/src/chain/chainmonitor.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@ where C::Target: chain::Filter,
194194
match monitors.get_mut(&funding_txo) {
195195
None => {
196196
log_error!(self.logger, "Failed to update channel monitor: no such monitor registered");
197+
198+
// We should never ever trigger this from within ChannelManager. Technically a
199+
// user could use this object with some proxying in between which makes this
200+
// possible, but in tests and fuzzing, this should be a panic.
201+
#[cfg(any(test, feature = "fuzztarget"))]
202+
panic!();
203+
#[cfg(not(any(test, feature = "fuzztarget")))]
197204
Err(ChannelMonitorUpdateErr::PermanentFailure)
198205
},
199206
Some(orig_monitor) => {

lightning/src/ln/channel.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4016,11 +4016,23 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
40164016
_ => {}
40174017
}
40184018
}
4019+
let funding_txo = if let Some(funding_txo) = self.funding_txo {
4020+
// If we haven't yet exchanged funding signatures (ie channel_state < FundingSent),
4021+
// returning a channel monitor update here would imply a channel monitor update before
4022+
// we even registered the channel monitor to begin with, which is invalid.
4023+
// Thus, if we aren't actually at a point where we could conceivably broadcast the
4024+
// funding transaction, don't return a funding txo (which prevents providing the
4025+
// monitor update to the user, even if we return one).
4026+
// See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more.
4027+
if self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::ChannelFunded as u32 | ChannelState::ShutdownComplete as u32) != 0 {
4028+
Some(funding_txo.clone())
4029+
} else { None }
4030+
} else { None };
40194031

40204032
self.channel_state = ChannelState::ShutdownComplete as u32;
40214033
self.update_time_counter += 1;
40224034
self.latest_monitor_update_id += 1;
4023-
(self.funding_txo.clone(), ChannelMonitorUpdate {
4035+
(funding_txo, ChannelMonitorUpdate {
40244036
update_id: self.latest_monitor_update_id,
40254037
updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast }],
40264038
}, dropped_outbound_htlcs)

lightning/src/ln/general_unit_tests.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,3 +647,40 @@ fn test_duplicate_chan_id() {
647647
update_nodes_with_chan_announce(&nodes, 0, 1, &announcement, &as_update, &bs_update);
648648
send_payment(&nodes[0], &[&nodes[1]], 8000000, 8_000_000);
649649
}
650+
651+
#[test]
652+
fn test_pre_lockin_no_chan_closed_update() {
653+
// Test that if a peer closes a channel in response to a funding_created message we don't
654+
// generate a channel update (as the channel cannot appear on chain without a funding_signed
655+
// message).
656+
//
657+
// Doing so would imply a channel monitor update before the initial channel monitor
658+
// registration, violating our API guarantees.
659+
//
660+
// Previously, full_stack_target managed to hit this case by opening then closing a channel,
661+
// then opening a second channel with the same funding output as the first (which is not
662+
// rejected because the first channel does not exist in the ChannelManager) and closing it
663+
// before receiving funding_signed.
664+
let chanmon_cfgs = create_chanmon_cfgs(2);
665+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
666+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
667+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
668+
669+
// Create an initial channel
670+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
671+
let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
672+
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_chan_msg);
673+
let accept_chan_msg = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
674+
nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_chan_msg);
675+
676+
// Move the first channel through the funding flow...
677+
let (temporary_channel_id, _tx, funding_output) = create_funding_transaction(&nodes[0], 100000, 42);
678+
679+
nodes[0].node.funding_transaction_generated(&temporary_channel_id, funding_output);
680+
check_added_monitors!(nodes[0], 0);
681+
682+
let funding_created_msg = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
683+
let channel_id = ::chain::transaction::OutPoint { txid: funding_created_msg.funding_txid, index: funding_created_msg.funding_output_index }.to_channel_id();
684+
nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id, data: "Hi".to_owned() });
685+
assert!(nodes[0].chain_monitor.added_monitors.lock().unwrap().is_empty());
686+
}

0 commit comments

Comments
 (0)