Skip to content

Commit d793bb8

Browse files
committed
Fail HTLCs which were removed from a channel but not persisted
When a channel is force-closed, if a `ChannelMonitor` update is completed but a `ChannelManager` persist has not yet happened, HTLCs which were removed in the latest (persisted) `ChannelMonitor` update will not be failed even though they do not appear in the commitment transaction which went on chain. This is because the `ChannelManager` thinks the `ChannelMonitor` is responsible for them (as it is stale), but the `ChannelMonitor` has no knowledge of the HTLC at all (as it is not stale). The fix for this is relatively simple - we need to check for this specific case and fail back such HTLCs when deserializing a `ChannelManager`
1 parent e2a1f8a commit d793bb8

File tree

3 files changed

+98
-3
lines changed

3 files changed

+98
-3
lines changed

lightning/src/ln/channel.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5942,15 +5942,16 @@ impl<Signer: Sign> Channel<Signer> {
59425942
(monitor_update, dropped_outbound_htlcs)
59435943
}
59445944

5945-
pub fn inflight_htlc_sources(&self) -> impl Iterator<Item=&HTLCSource> {
5945+
pub fn inflight_htlc_sources(&self) -> impl Iterator<Item=(&HTLCSource, &PaymentHash)> {
59465946
self.holding_cell_htlc_updates.iter()
59475947
.flat_map(|htlc_update| {
59485948
match htlc_update {
5949-
HTLCUpdateAwaitingACK::AddHTLC { source, .. } => { Some(source) }
5949+
HTLCUpdateAwaitingACK::AddHTLC { source, payment_hash, .. }
5950+
=> Some((source, payment_hash)),
59505951
_ => { None }
59515952
}
59525953
})
5953-
.chain(self.pending_outbound_htlcs.iter().map(|htlc| &htlc.source))
5954+
.chain(self.pending_outbound_htlcs.iter().map(|htlc| (&htlc.source, &htlc.payment_hash)))
59545955
}
59555956
}
59565957

lightning/src/ln/channelmanager.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5729,6 +5729,12 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
57295729
events.into_inner()
57305730
}
57315731

5732+
#[cfg(test)]
5733+
pub fn pop_pending_event(&self) -> Option<events::Event> {
5734+
let mut events = self.pending_events.lock().unwrap();
5735+
if events.is_empty() { None } else { Some(events.remove(0)) }
5736+
}
5737+
57325738
#[cfg(test)]
57335739
pub fn has_pending_payments(&self) -> bool {
57345740
!self.pending_outbound_payments.lock().unwrap().is_empty()
@@ -7189,6 +7195,25 @@ impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
71897195
user_channel_id: channel.get_user_id(),
71907196
reason: ClosureReason::OutdatedChannelManager
71917197
});
7198+
for (channel_htlc_source, payment_hash) in channel.inflight_htlc_sources() {
7199+
let mut found_htlc = false;
7200+
for (monitor_htlc_source, _) in monitor.get_all_current_outbound_htlcs() {
7201+
if *channel_htlc_source == monitor_htlc_source { found_htlc = true; break; }
7202+
}
7203+
if !found_htlc {
7204+
// If we have some HTLCs in the channel which are not present in the newer
7205+
// ChannelMonitor, they have been removed and should be failed back to
7206+
// ensure we don't forget them entirely. Note that if the missing HTLC(s)
7207+
// were actually claimed we'd have generated and ensured the previous-hop
7208+
// claim update ChannelMonitor updates were persisted prior to persising
7209+
// the ChannelMonitor update for the forward leg, so attempting to fail the
7210+
// backwards leg of the HTLC will simply be rejected.
7211+
log_info!(args.logger,
7212+
"Failing HTLC with hash {} as it is missing in the ChannelMonitor for channel {} but was present in the (stale) ChannelManager",
7213+
log_bytes!(channel.channel_id()), log_bytes!(payment_hash.0));
7214+
failed_htlcs.push((channel_htlc_source.clone(), *payment_hash, channel.get_counterparty_node_id(), channel.channel_id()));
7215+
}
7216+
}
71927217
} else {
71937218
log_info!(args.logger, "Successfully loaded channel {}", log_bytes!(channel.channel_id()));
71947219
if let Some(short_channel_id) = channel.get_short_channel_id() {

lightning/src/ln/reload_tests.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,3 +933,72 @@ fn forwarded_payment_no_manager_persistence() {
933933
do_forwarded_payment_no_manager_persistence(true, false);
934934
do_forwarded_payment_no_manager_persistence(false, false);
935935
}
936+
937+
#[test]
938+
fn removed_payment_no_manager_persistence() {
939+
// If an HTLC is failed to us ona channel, and the ChannelMonitor persistence completes, but
940+
// the corresponding ChannelManager persistence does not, we need to ensure that the HTLC is
941+
// still failed back to the previous hop even though the ChannelMonitor now no longer is aware
942+
// of the HTLC. This was previously broken as no attempt was made to figure out which HTLCs
943+
// were left dangling when a channel was force-closed due to a stale ChannelManager.
944+
let chanmon_cfgs = create_chanmon_cfgs(3);
945+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
946+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
947+
948+
let persister;
949+
let new_chain_monitor;
950+
let nodes_1_deserialized;
951+
952+
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
953+
954+
let chan_id_1 = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
955+
let chan_id_2 = create_announced_chan_between_nodes(&nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()).2;
956+
957+
let (_, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000);
958+
959+
let node_encoded = nodes[1].node.encode();
960+
961+
nodes[2].node.fail_htlc_backwards(&payment_hash);
962+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[2], [HTLCDestination::FailedPayment { payment_hash }]);
963+
check_added_monitors!(nodes[2], 1);
964+
let events = nodes[2].node.get_and_clear_pending_msg_events();
965+
assert_eq!(events.len(), 1);
966+
match &events[0] {
967+
MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { update_fail_htlcs, commitment_signed, .. }, .. } => {
968+
nodes[1].node.handle_update_fail_htlc(&nodes[2].node.get_our_node_id(), &update_fail_htlcs[0]);
969+
commitment_signed_dance!(nodes[1], nodes[2], commitment_signed, false);
970+
},
971+
_ => panic!("Unexpected event"),
972+
}
973+
974+
let chan_0_monitor_serialized = get_monitor!(nodes[1], chan_id_1).encode();
975+
let chan_1_monitor_serialized = get_monitor!(nodes[1], chan_id_2).encode();
976+
reload_node!(nodes[1], node_encoded, &[&chan_0_monitor_serialized, &chan_1_monitor_serialized], persister, new_chain_monitor, nodes_1_deserialized);
977+
978+
match nodes[1].node.pop_pending_event().unwrap() {
979+
Event::ChannelClosed { ref reason, .. } => {
980+
assert_eq!(*reason, ClosureReason::OutdatedChannelManager);
981+
},
982+
_ => panic!("Unexpected event"),
983+
}
984+
985+
// Now that the ChannelManager has force-closed the channel which had the HTLC removed, it is
986+
// now forgotten everywhere. The ChannelManager should have, as a side-effect of reload,
987+
// learned that the HTLC is gone from the ChannelMonitor and added it to the to-fail-back set.
988+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), true);
989+
reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
990+
991+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], [HTLCDestination::NextHopChannel { node_id: Some(nodes[2].node.get_our_node_id()), channel_id: chan_id_2 }]);
992+
check_added_monitors!(nodes[1], 1);
993+
let events = nodes[1].node.get_and_clear_pending_msg_events();
994+
assert_eq!(events.len(), 1);
995+
match &events[0] {
996+
MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { update_fail_htlcs, commitment_signed, .. }, .. } => {
997+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &update_fail_htlcs[0]);
998+
commitment_signed_dance!(nodes[0], nodes[1], commitment_signed, false);
999+
},
1000+
_ => panic!("Unexpected event"),
1001+
}
1002+
1003+
expect_payment_failed!(nodes[0], payment_hash, false);
1004+
}

0 commit comments

Comments
 (0)