Skip to content

Commit 36063ee

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 22de94a commit 36063ee

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!("ChannelManager generated a channel update for a channel that was not yet registered!");
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/functional_tests.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8457,6 +8457,43 @@ fn test_concurrent_monitor_claim() {
84578457
}
84588458
}
84598459

8460+
#[test]
8461+
fn test_pre_lockin_no_chan_closed_update() {
8462+
// Test that if a peer closes a channel in response to a funding_created message we don't
8463+
// generate a channel update (as the channel cannot appear on chain without a funding_signed
8464+
// message).
8465+
//
8466+
// Doing so would imply a channel monitor update before the initial channel monitor
8467+
// registration, violating our API guarantees.
8468+
//
8469+
// Previously, full_stack_target managed to hit this case by opening then closing a channel,
8470+
// then opening a second channel with the same funding output as the first (which is not
8471+
// rejected because the first channel does not exist in the ChannelManager) and closing it
8472+
// before receiving funding_signed.
8473+
let chanmon_cfgs = create_chanmon_cfgs(2);
8474+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
8475+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
8476+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
8477+
8478+
// Create an initial channel
8479+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
8480+
let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
8481+
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_chan_msg);
8482+
let accept_chan_msg = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
8483+
nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_chan_msg);
8484+
8485+
// Move the first channel through the funding flow...
8486+
let (temporary_channel_id, _tx, funding_output) = create_funding_transaction(&nodes[0], 100000, 42);
8487+
8488+
nodes[0].node.funding_transaction_generated(&temporary_channel_id, funding_output);
8489+
check_added_monitors!(nodes[0], 0);
8490+
8491+
let funding_created_msg = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
8492+
let channel_id = ::chain::transaction::OutPoint { txid: funding_created_msg.funding_txid, index: funding_created_msg.funding_output_index }.to_channel_id();
8493+
nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id, data: "Hi".to_owned() });
8494+
assert!(nodes[0].chain_monitor.added_monitors.lock().unwrap().is_empty());
8495+
}
8496+
84608497
#[test]
84618498
fn test_htlc_no_detection() {
84628499
// This test is a mutation to underscore the detection logic bug we had

0 commit comments

Comments
 (0)