Skip to content

Commit e77c83d

Browse files
Add the blamed HTLC payment hash to ClosureReason::HTLCsTimedOut
When an HTLC timing out causes a channel to force-close, its useful to have the payment hash available in a programatic way so that it is always available for debugging. Thus, here, it is added to `ClosureReason::HTLCsTimedOut` for inclusion in `Event::ChanelClosed`. Co-authored-by: Matt Corallo <[email protected]>
1 parent 874b9c7 commit e77c83d

File tree

5 files changed

+61
-23
lines changed

5 files changed

+61
-23
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5211,8 +5211,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
52115211
debug_assert!(self.best_block.height >= conf_height);
52125212

52135213
let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
5214-
if should_broadcast {
5215-
let (mut new_outpoints, mut new_outputs) = self.generate_claimable_outpoints_and_watch_outputs(Some(ClosureReason::HTLCsTimedOut));
5214+
if let Some(payment_hash) = should_broadcast {
5215+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
5216+
let (mut new_outpoints, mut new_outputs) =
5217+
self.generate_claimable_outpoints_and_watch_outputs(Some(reason));
52165218
claimable_outpoints.append(&mut new_outpoints);
52175219
watch_outputs.append(&mut new_outputs);
52185220
}
@@ -5560,7 +5562,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
55605562
#[rustfmt::skip]
55615563
fn should_broadcast_holder_commitment_txn<L: Deref>(
55625564
&self, logger: &WithChannelMonitor<L>
5563-
) -> bool where L::Target: Logger {
5565+
) -> Option<PaymentHash> where L::Target: Logger {
55645566
// There's no need to broadcast our commitment transaction if we've seen one confirmed (even
55655567
// with 1 confirmation) as it'll be rejected as duplicate/conflicting.
55665568
if self.funding_spend_confirmed.is_some() ||
@@ -5569,7 +5571,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
55695571
_ => false,
55705572
}).is_some()
55715573
{
5572-
return false;
5574+
return None;
55735575
}
55745576
// We need to consider all HTLCs which are:
55755577
// * in any unrevoked counterparty commitment transaction, as they could broadcast said
@@ -5600,7 +5602,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
56005602
if ( htlc_outbound && htlc.cltv_expiry + LATENCY_GRACE_PERIOD_BLOCKS <= height) ||
56015603
(!htlc_outbound && htlc.cltv_expiry <= height + CLTV_CLAIM_BUFFER && self.payment_preimages.contains_key(&htlc.payment_hash)) {
56025604
log_info!(logger, "Force-closing channel due to {} HTLC timeout - HTLC with payment hash {} expires at {}", if htlc_outbound { "outbound" } else { "inbound"}, htlc.payment_hash, htlc.cltv_expiry);
5603-
return true;
5605+
return Some(htlc.payment_hash);
56045606
}
56055607
}
56065608
}
@@ -5619,7 +5621,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
56195621
}
56205622
}
56215623

5622-
false
5624+
None
56235625
}
56245626

56255627
/// Check if any transaction broadcasted is resolving HTLC output by a success or timeout on a holder

lightning/src/events/mod.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,12 @@ pub enum ClosureReason {
406406
/// was ready to be broadcast.
407407
FundingBatchClosure,
408408
/// One of our HTLCs timed out in a channel, causing us to force close the channel.
409-
HTLCsTimedOut,
409+
HTLCsTimedOut {
410+
/// The payment hash of an HTLC that timed out.
411+
///
412+
/// Will be `None` for any event serialized by LDK prior to 0.2.
413+
payment_hash: Option<PaymentHash>,
414+
},
410415
/// Our peer provided a feerate which violated our required minimum (fetched from our
411416
/// [`FeeEstimator`] either as [`ConfirmationTarget::MinAllowedAnchorChannelRemoteFee`] or
412417
/// [`ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee`]).
@@ -480,7 +485,12 @@ impl core::fmt::Display for ClosureReason {
480485
ClosureReason::FundingBatchClosure => {
481486
f.write_str("another channel in the same funding batch closed")
482487
},
483-
ClosureReason::HTLCsTimedOut => f.write_str("htlcs on the channel timed out"),
488+
ClosureReason::HTLCsTimedOut { payment_hash: Some(hash) } => f.write_fmt(format_args!(
489+
"HTLC(s) on the channel timed out (including the HTLC with payment hash {hash})",
490+
)),
491+
ClosureReason::HTLCsTimedOut { payment_hash: None } => {
492+
f.write_fmt(format_args!("HTLC(s) on the channel timed out"))
493+
},
484494
ClosureReason::PeerFeerateTooLow {
485495
peer_feerate_sat_per_kw,
486496
required_feerate_sat_per_kw,
@@ -508,7 +518,9 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
508518
(15, FundingBatchClosure) => {},
509519
(17, CounterpartyInitiatedCooperativeClosure) => {},
510520
(19, LocallyInitiatedCooperativeClosure) => {},
511-
(21, HTLCsTimedOut) => {},
521+
(21, HTLCsTimedOut) => {
522+
(1, payment_hash, option),
523+
},
512524
(23, PeerFeerateTooLow) => {
513525
(0, peer_feerate_sat_per_kw, required),
514526
(2, required_feerate_sat_per_kw, required),

lightning/src/ln/functional_tests.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,8 @@ fn do_test_fail_back_before_backwards_timeout(post_fail_back_action: PostFailBac
856856
let timeout_blocks = TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1;
857857
connect_blocks(&nodes[1], timeout_blocks);
858858
let node_1_txn = test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::TIMEOUT);
859-
check_closed_event(&nodes[1], 1, ClosureReason::HTLCsTimedOut, false, &[node_c_id], 100_000);
859+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
860+
check_closed_event(&nodes[1], 1, reason, false, &[node_c_id], 100_000);
860861
check_closed_broadcast(&nodes[1], 1, true);
861862
check_added_monitors(&nodes[1], 1);
862863

@@ -910,7 +911,7 @@ fn do_test_fail_back_before_backwards_timeout(post_fail_back_action: PostFailBac
910911
connect_blocks(&nodes[2], TEST_FINAL_CLTV - CLTV_CLAIM_BUFFER + 2);
911912
let node_2_txn = test_txn_broadcast(&nodes[2], &chan_2, None, HTLCType::SUCCESS);
912913
check_closed_broadcast!(nodes[2], true);
913-
let reason = ClosureReason::HTLCsTimedOut;
914+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
914915
check_closed_event(&nodes[2], 1, reason, false, &[node_b_id], 100_000);
915916
check_added_monitors(&nodes[2], 1);
916917

@@ -1160,7 +1161,8 @@ pub fn channel_monitor_network_test() {
11601161
}
11611162
check_added_monitors(&nodes[4], 1);
11621163
test_txn_broadcast(&nodes[4], &chan_4, None, HTLCType::SUCCESS);
1163-
check_closed_event!(nodes[4], 1, ClosureReason::HTLCsTimedOut, [node_d_id], 100000);
1164+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash_2) };
1165+
check_closed_event!(nodes[4], 1, reason, [node_d_id], 100000);
11641166

11651167
mine_transaction(&nodes[4], &node_txn[0]);
11661168
check_preimage_claim(&nodes[4], &node_txn);
@@ -1177,7 +1179,8 @@ pub fn channel_monitor_network_test() {
11771179
nodes[3].chain_monitor.chain_monitor.watch_channel(chan_3.2, chan_3_mon),
11781180
Ok(ChannelMonitorUpdateStatus::Completed)
11791181
);
1180-
check_closed_event!(nodes[3], 1, ClosureReason::HTLCsTimedOut, [node_id_4], 100000);
1182+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash_2) };
1183+
check_closed_event!(nodes[3], 1, reason, [node_id_4], 100000);
11811184
}
11821185

11831186
#[xtest(feature = "_externalize_tests")]
@@ -5321,7 +5324,8 @@ fn do_htlc_claim_local_commitment_only(use_dust: bool) {
53215324
test_txn_broadcast(&nodes[1], &chan, None, htlc_type);
53225325
check_closed_broadcast!(nodes[1], true);
53235326
check_added_monitors(&nodes[1], 1);
5324-
check_closed_event!(nodes[1], 1, ClosureReason::HTLCsTimedOut, [node_a_id], 100000);
5327+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
5328+
check_closed_event!(nodes[1], 1, reason, [node_a_id], 100000);
53255329
}
53265330

53275331
fn do_htlc_claim_current_remote_commitment_only(use_dust: bool) {
@@ -5359,7 +5363,8 @@ fn do_htlc_claim_current_remote_commitment_only(use_dust: bool) {
53595363
test_txn_broadcast(&nodes[0], &chan, None, HTLCType::NONE);
53605364
check_closed_broadcast!(nodes[0], true);
53615365
check_added_monitors(&nodes[0], 1);
5362-
check_closed_event!(nodes[0], 1, ClosureReason::HTLCsTimedOut, [node_b_id], 100000);
5366+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
5367+
check_closed_event!(nodes[0], 1, reason, [node_b_id], 100000);
53635368
}
53645369

53655370
fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no_close: bool) {
@@ -5414,7 +5419,8 @@ fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no
54145419
test_txn_broadcast(&nodes[0], &chan, None, HTLCType::NONE);
54155420
check_closed_broadcast!(nodes[0], true);
54165421
check_added_monitors(&nodes[0], 1);
5417-
check_closed_event!(nodes[0], 1, ClosureReason::HTLCsTimedOut, [node_b_id], 100000);
5422+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(our_payment_hash) };
5423+
check_closed_event!(nodes[0], 1, reason, [node_b_id], 100000);
54185424
} else {
54195425
expect_payment_failed!(nodes[0], our_payment_hash, true);
54205426
}
@@ -8160,7 +8166,7 @@ pub fn test_concurrent_monitor_claim() {
81608166
send_payment(&nodes[0], &[&nodes[1]], 10_000_000);
81618167

81628168
// Route a HTLC from node 0 to node 1 (but don't settle)
8163-
route_payment(&nodes[0], &[&nodes[1]], 9_000_000);
8169+
let (_, payment_hash_timeout, ..) = route_payment(&nodes[0], &[&nodes[1]], 9_000_000);
81648170

81658171
// Copy ChainMonitor to simulate watchtower Alice and update block height her ChannelMonitor timeout HTLC onchain
81668172
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
@@ -8311,7 +8317,8 @@ pub fn test_concurrent_monitor_claim() {
83118317
let height = HTLC_TIMEOUT_BROADCAST + 1;
83128318
connect_blocks(&nodes[0], height - nodes[0].best_block_info().1);
83138319
check_closed_broadcast(&nodes[0], 1, true);
8314-
check_closed_event!(&nodes[0], 1, ClosureReason::HTLCsTimedOut, false, [node_b_id], 100000);
8320+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash_timeout) };
8321+
check_closed_event!(&nodes[0], 1, reason, false, [node_b_id], 100000);
83158322
watchtower_alice.chain_monitor.block_connected(
83168323
&create_dummy_block(BlockHash::all_zeros(), 42, vec![bob_state_y.clone()]),
83178324
height,

lightning/src/ln/monitor_tests.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,14 +1407,22 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_
14071407
});
14081408
assert!(failed_payments.is_empty());
14091409
match &events[0] {
1410-
Event::ChannelClosed { reason: ClosureReason::HTLCsTimedOut, .. } => {},
1410+
Event::ChannelClosed { reason: ClosureReason::HTLCsTimedOut { .. }, .. } => {},
14111411
_ => panic!(),
14121412
}
14131413

14141414
connect_blocks(&nodes[1], htlc_cltv_timeout + 1 - 10);
14151415
check_closed_broadcast!(nodes[1], true);
14161416
check_added_monitors!(nodes[1], 1);
1417-
check_closed_event!(nodes[1], 1, ClosureReason::HTLCsTimedOut, [nodes[0].node.get_our_node_id()], 1000000);
1417+
check_closed_events(&nodes[1], &[ExpectedCloseEvent {
1418+
channel_capacity_sats: Some(1_000_000),
1419+
channel_id: Some(chan_id),
1420+
counterparty_node_id: Some(nodes[0].node.get_our_node_id()),
1421+
discard_funding: false,
1422+
reason: None, // Could be due to any HTLC timing out, so don't bother checking
1423+
channel_funding_txo: None,
1424+
user_channel_id: None,
1425+
}]);
14181426

14191427
// Prior to channel closure, B considers the preimage HTLC as its own, and otherwise only
14201428
// lists the two on-chain timeout-able HTLCs as claimable balances.

lightning/src/ln/reorg_tests.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,15 @@ fn test_set_outpoints_partial_claiming() {
487487
// Connect blocks on node B
488488
connect_blocks(&nodes[1], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
489489
check_closed_broadcast!(nodes[1], true);
490-
check_closed_event!(nodes[1], 1, ClosureReason::HTLCsTimedOut, [nodes[0].node.get_our_node_id()], 1000000);
490+
check_closed_events(&nodes[1], &[ExpectedCloseEvent {
491+
channel_capacity_sats: Some(1_000_000),
492+
channel_id: Some(chan.2),
493+
counterparty_node_id: Some(nodes[0].node.get_our_node_id()),
494+
discard_funding: false,
495+
reason: None, // Could be due to either HTLC timing out, so don't bother checking
496+
channel_funding_txo: None,
497+
user_channel_id: None,
498+
}]);
491499
check_added_monitors!(nodes[1], 1);
492500
// Verify node B broadcast 2 HTLC-timeout txn
493501
let partial_claim_tx = {
@@ -818,7 +826,7 @@ fn do_test_retries_own_commitment_broadcast_after_reorg(anchors: bool, revoked_c
818826
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
819827

820828
// Route a payment so we have an HTLC to claim as well.
821-
let _ = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
829+
let (_, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
822830

823831
if revoked_counterparty_commitment {
824832
// Trigger a fee update such that we advance the state. We will have B broadcast its state
@@ -843,7 +851,8 @@ fn do_test_retries_own_commitment_broadcast_after_reorg(anchors: bool, revoked_c
843851
connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
844852
check_closed_broadcast(&nodes[0], 1, true);
845853
check_added_monitors(&nodes[0], 1);
846-
check_closed_event(&nodes[0], 1, ClosureReason::HTLCsTimedOut, false, &[nodes[1].node.get_our_node_id()], 100_000);
854+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
855+
check_closed_event(&nodes[0], 1, reason, false, &[nodes[1].node.get_our_node_id()], 100_000);
847856
if anchors {
848857
handle_bump_close_event(&nodes[0]);
849858
}

0 commit comments

Comments
 (0)