Skip to content

Commit 80df48d

Browse files
committed
Add HTLCsTimedOut closing reason
1 parent d70124c commit 80df48d

File tree

6 files changed

+54
-16
lines changed

6 files changed

+54
-16
lines changed

lightning/src/chain/channelmonitor.rs

+33-4
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use crate::chain::Filter;
5050
use crate::util::logger::{Logger, Record};
5151
use crate::util::ser::{Readable, ReadableArgs, RequiredWrapper, MaybeReadable, UpgradableRequired, Writer, Writeable, U48};
5252
use crate::util::byte_utils;
53-
use crate::events::{Event, EventHandler};
53+
use crate::events::{ClosureReason, Event, EventHandler};
5454
use crate::events::bump_transaction::{AnchorDescriptor, BumpTransactionEvent};
5555

5656
use crate::prelude::*;
@@ -155,6 +155,17 @@ pub enum MonitorEvent {
155155
/// A monitor event containing an HTLCUpdate.
156156
HTLCEvent(HTLCUpdate),
157157

158+
/// Indicates we broadcasted the channel's latest commitment transaction and thus closed the
159+
/// channel. Holds information the channel and why it was closed.
160+
HolderForceClosedWithInfo {
161+
/// The reason the channel was closed.
162+
reason: ClosureReason,
163+
/// The funding outpoint of the channel.
164+
outpoint: OutPoint,
165+
/// The channel ID of the channel.
166+
channel_id: ChannelId,
167+
},
168+
158169
/// Indicates we broadcasted the channel's latest commitment transaction and thus closed the
159170
/// channel.
160171
HolderForceClosed(OutPoint),
@@ -184,6 +195,11 @@ impl_writeable_tlv_based_enum_upgradable!(MonitorEvent,
184195
(2, monitor_update_id, required),
185196
(4, channel_id, required),
186197
},
198+
(5, HolderForceClosedWithInfo) => {
199+
(0, reason, upgradable_required),
200+
(2, outpoint, required),
201+
(4, channel_id, required),
202+
},
187203
;
188204
(2, HTLCEvent),
189205
(4, HolderForceClosed),
@@ -2700,7 +2716,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
27002716
}
27012717
}
27022718

2703-
fn generate_claimable_outpoints_and_watch_outputs(&mut self) -> (Vec<PackageTemplate>, Vec<TransactionOutputs>) {
2719+
fn generate_claimable_outpoints_and_watch_outputs(&mut self, is_htlc_timeout: bool) -> (Vec<PackageTemplate>, Vec<TransactionOutputs>) {
27042720
let funding_outp = HolderFundingOutput::build(
27052721
self.funding_redeemscript.clone(),
27062722
self.channel_value_satoshis,
@@ -2712,7 +2728,20 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
27122728
self.best_block.height(), self.best_block.height()
27132729
);
27142730
let mut claimable_outpoints = vec![commitment_package];
2731+
let reason = if is_htlc_timeout {
2732+
ClosureReason::HTLCsTimedOut
2733+
} else {
2734+
ClosureReason::HolderForceClosed
2735+
};
2736+
let event = MonitorEvent::HolderForceClosedWithInfo {
2737+
reason,
2738+
outpoint: self.funding_info.0,
2739+
channel_id: self.channel_id,
2740+
};
2741+
self.pending_monitor_events.push(event);
2742+
// add old version as well for backwards compatability
27152743
self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
2744+
27162745
// Although we aren't signing the transaction directly here, the transaction will be signed
27172746
// in the claim that is queued to OnchainTxHandler. We set holder_tx_signed here to reject
27182747
// new channel updates.
@@ -2748,7 +2777,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
27482777
F::Target: FeeEstimator,
27492778
L::Target: Logger,
27502779
{
2751-
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs();
2780+
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(false);
27522781
self.onchain_tx_handler.update_claims_view_from_requests(
27532782
claimable_outpoints, self.best_block.height(), self.best_block.height(), broadcaster,
27542783
fee_estimator, logger
@@ -3787,7 +3816,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
37873816

37883817
let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
37893818
if should_broadcast {
3790-
let (mut new_outpoints, mut new_outputs) = self.generate_claimable_outpoints_and_watch_outputs();
3819+
let (mut new_outpoints, mut new_outputs) = self.generate_claimable_outpoints_and_watch_outputs(true);
37913820
claimable_outpoints.append(&mut new_outpoints);
37923821
watch_outputs.append(&mut new_outputs);
37933822
}

lightning/src/events/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ pub enum ClosureReason {
232232
/// Another channel in the same funding batch closed before the funding transaction
233233
/// was ready to be broadcast.
234234
FundingBatchClosure,
235+
/// One of our HTLCs timed out in a channel, causing us to force close the channel.
236+
HTLCsTimedOut,
235237
}
236238

237239
impl core::fmt::Display for ClosureReason {
@@ -255,6 +257,7 @@ impl core::fmt::Display for ClosureReason {
255257
ClosureReason::OutdatedChannelManager => f.write_str("the ChannelManager read from disk was stale compared to ChannelMonitor(s)"),
256258
ClosureReason::CounterpartyCoopClosedUnfundedChannel => f.write_str("the peer requested the unfunded channel be closed"),
257259
ClosureReason::FundingBatchClosure => f.write_str("another channel in the same funding batch closed"),
260+
ClosureReason::HTLCsTimedOut => f.write_str("htlcs on the channel timed out"),
258261
}
259262
}
260263
}
@@ -272,6 +275,7 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
272275
(15, FundingBatchClosure) => {},
273276
(17, CounterpartyInitiatedCooperativeClosure) => {},
274277
(19, LocallyInitiatedCooperativeClosure) => {},
278+
(21, HTLCsTimedOut) => {},
275279
);
276280

277281
/// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].

lightning/src/ln/channelmanager.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -7315,7 +7315,7 @@ where
73157315
self.fail_htlc_backwards_internal(&htlc_update.source, &htlc_update.payment_hash, &reason, receiver);
73167316
}
73177317
},
7318-
MonitorEvent::HolderForceClosed(_funding_outpoint) => {
7318+
MonitorEvent::HolderForceClosed(_) | MonitorEvent::HolderForceClosedWithInfo { .. } => {
73197319
let counterparty_node_id_opt = match counterparty_node_id {
73207320
Some(cp_id) => Some(cp_id),
73217321
None => {
@@ -7333,7 +7333,12 @@ where
73337333
let pending_msg_events = &mut peer_state.pending_msg_events;
73347334
if let hash_map::Entry::Occupied(chan_phase_entry) = peer_state.channel_by_id.entry(channel_id) {
73357335
if let ChannelPhase::Funded(mut chan) = remove_channel_phase!(self, chan_phase_entry) {
7336-
failed_channels.push(chan.context.force_shutdown(false, ClosureReason::HolderForceClosed));
7336+
let reason = if let MonitorEvent::HolderForceClosedWithInfo { reason, ..} = monitor_event {
7337+
reason
7338+
} else {
7339+
ClosureReason::HolderForceClosed
7340+
};
7341+
failed_channels.push(chan.context.force_shutdown(false, reason));
73377342
if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
73387343
pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
73397344
msg: update

lightning/src/ln/functional_tests.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -2417,7 +2417,7 @@ fn channel_monitor_network_test() {
24172417
}
24182418
check_added_monitors!(nodes[4], 1);
24192419
test_txn_broadcast(&nodes[4], &chan_4, None, HTLCType::SUCCESS);
2420-
check_closed_event!(nodes[4], 1, ClosureReason::HolderForceClosed, [nodes[3].node.get_our_node_id()], 100000);
2420+
check_closed_event!(nodes[4], 1, ClosureReason::HTLCsTimedOut, [nodes[3].node.get_our_node_id()], 100000);
24212421

24222422
mine_transaction(&nodes[4], &node_txn[0]);
24232423
check_preimage_claim(&nodes[4], &node_txn);
@@ -2430,7 +2430,7 @@ fn channel_monitor_network_test() {
24302430

24312431
assert_eq!(nodes[3].chain_monitor.chain_monitor.watch_channel(OutPoint { txid: chan_3.3.txid(), index: 0 }, chan_3_mon),
24322432
Ok(ChannelMonitorUpdateStatus::Completed));
2433-
check_closed_event!(nodes[3], 1, ClosureReason::HolderForceClosed, [nodes[4].node.get_our_node_id()], 100000);
2433+
check_closed_event!(nodes[3], 1, ClosureReason::HTLCsTimedOut, [nodes[4].node.get_our_node_id()], 100000);
24342434
}
24352435

24362436
#[test]
@@ -5682,7 +5682,7 @@ fn do_htlc_claim_local_commitment_only(use_dust: bool) {
56825682
test_txn_broadcast(&nodes[1], &chan, None, if use_dust { HTLCType::NONE } else { HTLCType::SUCCESS });
56835683
check_closed_broadcast!(nodes[1], true);
56845684
check_added_monitors!(nodes[1], 1);
5685-
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 100000);
5685+
check_closed_event!(nodes[1], 1, ClosureReason::HTLCsTimedOut, [nodes[0].node.get_our_node_id()], 100000);
56865686
}
56875687

56885688
fn do_htlc_claim_current_remote_commitment_only(use_dust: bool) {
@@ -5713,7 +5713,7 @@ fn do_htlc_claim_current_remote_commitment_only(use_dust: bool) {
57135713
test_txn_broadcast(&nodes[0], &chan, None, HTLCType::NONE);
57145714
check_closed_broadcast!(nodes[0], true);
57155715
check_added_monitors!(nodes[0], 1);
5716-
check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
5716+
check_closed_event!(nodes[0], 1, ClosureReason::HTLCsTimedOut, [nodes[1].node.get_our_node_id()], 100000);
57175717
}
57185718

57195719
fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no_close: bool) {
@@ -5759,7 +5759,7 @@ fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no
57595759
test_txn_broadcast(&nodes[0], &chan, None, HTLCType::NONE);
57605760
check_closed_broadcast!(nodes[0], true);
57615761
check_added_monitors!(nodes[0], 1);
5762-
check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
5762+
check_closed_event!(nodes[0], 1, ClosureReason::HTLCsTimedOut, [nodes[1].node.get_our_node_id()], 100000);
57635763
} else {
57645764
expect_payment_failed!(nodes[0], our_payment_hash, true);
57655765
}
@@ -8654,7 +8654,7 @@ fn test_concurrent_monitor_claim() {
86548654
let height = HTLC_TIMEOUT_BROADCAST + 1;
86558655
connect_blocks(&nodes[0], height - nodes[0].best_block_info().1);
86568656
check_closed_broadcast(&nodes[0], 1, true);
8657-
check_closed_event!(&nodes[0], 1, ClosureReason::HolderForceClosed, false,
8657+
check_closed_event!(&nodes[0], 1, ClosureReason::HTLCsTimedOut, false,
86588658
[nodes[1].node.get_our_node_id()], 100000);
86598659
watchtower_alice.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, vec![bob_state_y.clone()]), height);
86608660
check_added_monitors(&nodes[0], 1);

lightning/src/ln/monitor_tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1188,14 +1188,14 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_
11881188
assert!(failed_payments.is_empty());
11891189
if let Event::PendingHTLCsForwardable { .. } = events[0] {} else { panic!(); }
11901190
match &events[1] {
1191-
Event::ChannelClosed { reason: ClosureReason::HolderForceClosed, .. } => {},
1191+
Event::ChannelClosed { reason: ClosureReason::HTLCsTimedOut, .. } => {},
11921192
_ => panic!(),
11931193
}
11941194

11951195
connect_blocks(&nodes[1], htlc_cltv_timeout + 1 - 10);
11961196
check_closed_broadcast!(nodes[1], true);
11971197
check_added_monitors!(nodes[1], 1);
1198-
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 1000000);
1198+
check_closed_event!(nodes[1], 1, ClosureReason::HTLCsTimedOut, [nodes[0].node.get_our_node_id()], 1000000);
11991199

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

lightning/src/ln/reorg_tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ fn test_set_outpoints_partial_claiming() {
465465
// Connect blocks on node B
466466
connect_blocks(&nodes[1], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
467467
check_closed_broadcast!(nodes[1], true);
468-
check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed, [nodes[0].node.get_our_node_id()], 1000000);
468+
check_closed_event!(nodes[1], 1, ClosureReason::HTLCsTimedOut, [nodes[0].node.get_our_node_id()], 1000000);
469469
check_added_monitors!(nodes[1], 1);
470470
// Verify node B broadcast 2 HTLC-timeout txn
471471
let partial_claim_tx = {
@@ -807,7 +807,7 @@ fn do_test_retries_own_commitment_broadcast_after_reorg(anchors: bool, revoked_c
807807
connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
808808
check_closed_broadcast(&nodes[0], 1, true);
809809
check_added_monitors(&nodes[0], 1);
810-
check_closed_event(&nodes[0], 1, ClosureReason::HolderForceClosed, false, &[nodes[1].node.get_our_node_id()], 100_000);
810+
check_closed_event(&nodes[0], 1, ClosureReason::HTLCsTimedOut, false, &[nodes[1].node.get_our_node_id()], 100_000);
811811

812812
{
813813
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();

0 commit comments

Comments
 (0)