Skip to content

Commit ff344b4

Browse files
Fail HTLC backwards before upstream claims on-chain
Fail inbound HTLCs if they expire within a certain number of blocks from the current height. If we haven't seen the preimage for an HTLC by the time the previous hop's timeout expires, we've lost that HTLC, so we might as well fail it back instead of having our counterparty force-close the channel. Co-authored-by: Matt Corallo <[email protected]>
1 parent 4c8d59f commit ff344b4

File tree

2 files changed

+224
-8
lines changed

2 files changed

+224
-8
lines changed

lightning/src/chain/channelmonitor.rs

+74
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,12 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
10231023

10241024
/// The first block height at which we had no remaining claimable balances.
10251025
balances_empty_height: Option<u32>,
1026+
1027+
/// In-memory only HTLC ids used to track upstream HTLCs that have been failed backwards due to
1028+
/// a downstream channel force-close remaining unconfirmed by the time the upstream timeout
1029+
/// expires. This is used to tell us we already generated an event to fail this HTLC back
1030+
/// during a previous block scan.
1031+
failed_back_htlc_ids: HashSet<SentHTLCId>,
10261032
}
10271033

10281034
/// Transaction outputs to watch for on-chain spends.
@@ -1445,6 +1451,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
14451451
counterparty_node_id: Some(counterparty_node_id),
14461452
initial_counterparty_commitment_info: None,
14471453
balances_empty_height: None,
1454+
1455+
failed_back_htlc_ids: new_hash_set(),
14481456
})
14491457
}
14501458

@@ -4221,6 +4229,71 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
42214229
}
42224230
}
42234231

4232+
if self.lockdown_from_offchain || self.funding_spend_seen || self.holder_tx_signed {
4233+
// Fail back HTLCs on backwards channels if they expire within
4234+
// `LATENCY_GRACE_PERIOD_BLOCKS` blocks and the channel is closed (i.e. we're at a
4235+
// point where no further off-chain updates will be accepted). If we haven't seen the
4236+
// preimage for an HTLC by the time the previous hop's timeout expires, we've lost that
4237+
// HTLC, so we might as well fail it back instead of having our counterparty force-close
4238+
// the inbound channel.
4239+
let current_holder_htlcs = self.current_holder_commitment_tx.htlc_outputs.iter()
4240+
.map(|&(ref a, _, ref b)| (a, b.as_ref()));
4241+
4242+
let current_counterparty_htlcs = if let Some(txid) = self.current_counterparty_commitment_txid {
4243+
if let Some(htlc_outputs) = self.counterparty_claimable_outpoints.get(&txid) {
4244+
Some(htlc_outputs.iter().map(|&(ref a, ref b)| (a, b.as_ref().map(|boxed| &**boxed))))
4245+
} else { None }
4246+
} else { None }.into_iter().flatten();
4247+
4248+
let prev_counterparty_htlcs = if let Some(txid) = self.prev_counterparty_commitment_txid {
4249+
if let Some(htlc_outputs) = self.counterparty_claimable_outpoints.get(&txid) {
4250+
Some(htlc_outputs.iter().map(|&(ref a, ref b)| (a, b.as_ref().map(|boxed| &**boxed))))
4251+
} else { None }
4252+
} else { None }.into_iter().flatten();
4253+
4254+
let htlcs = current_holder_htlcs
4255+
.chain(current_counterparty_htlcs)
4256+
.chain(prev_counterparty_htlcs);
4257+
4258+
let height = self.best_block.height;
4259+
for (htlc, source_opt) in htlcs {
4260+
// Only check forwarded HTLCs' previous hops
4261+
let source = match source_opt {
4262+
Some(source) => source,
4263+
None => continue,
4264+
};
4265+
let inbound_htlc_expiry = match source.inbound_htlc_expiry() {
4266+
Some(cltv_expiry) => cltv_expiry,
4267+
None => continue,
4268+
};
4269+
let max_expiry_height = height.saturating_add(LATENCY_GRACE_PERIOD_BLOCKS);
4270+
if inbound_htlc_expiry > max_expiry_height {
4271+
continue;
4272+
}
4273+
let duplicate_event = self.pending_monitor_events.iter().any(
4274+
|update| if let &MonitorEvent::HTLCEvent(ref upd) = update {
4275+
upd.source == *source
4276+
} else { false });
4277+
if duplicate_event {
4278+
continue;
4279+
}
4280+
if !self.failed_back_htlc_ids.insert(SentHTLCId::from_source(source)) {
4281+
continue;
4282+
}
4283+
if !duplicate_event {
4284+
log_error!(logger, "Failing back HTLC {} upstream to preserve the \
4285+
channel as the forward HTLC hasn't resolved and our backward HTLC \
4286+
expires soon at {}", log_bytes!(htlc.payment_hash.0), inbound_htlc_expiry);
4287+
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
4288+
source: source.clone(),
4289+
payment_preimage: None,
4290+
payment_hash: htlc.payment_hash,
4291+
htlc_value_satoshis: Some(htlc.amount_msat / 1000),
4292+
}));
4293+
}
4294+
}
4295+
}
4296+
42244297
let conf_target = self.closure_conf_target();
42254298
self.onchain_tx_handler.update_claims_view_from_requests(claimable_outpoints, conf_height, self.best_block.height, broadcaster, conf_target, fee_estimator, logger);
42264299
self.onchain_tx_handler.update_claims_view_from_matched_txn(&txn_matched, conf_height, conf_hash, self.best_block.height, broadcaster, conf_target, fee_estimator, logger);
@@ -5066,6 +5139,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
50665139
counterparty_node_id,
50675140
initial_counterparty_commitment_info,
50685141
balances_empty_height,
5142+
failed_back_htlc_ids: new_hash_set(),
50695143
})))
50705144
}
50715145
}

lightning/src/ln/functional_tests.rs

+150-8
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,138 @@ fn channel_reserve_in_flight_removes() {
22702270
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_3);
22712271
}
22722272

2273+
enum PostFailBackAction {
2274+
TimeoutOnChain,
2275+
ClaimOnChain,
2276+
FailOffChain,
2277+
ClaimOffChain,
2278+
}
2279+
2280+
#[test]
2281+
fn test_fail_back_before_backwards_timeout() {
2282+
do_test_fail_back_before_backwards_timeout(PostFailBackAction::TimeoutOnChain);
2283+
do_test_fail_back_before_backwards_timeout(PostFailBackAction::ClaimOnChain);
2284+
do_test_fail_back_before_backwards_timeout(PostFailBackAction::FailOffChain);
2285+
do_test_fail_back_before_backwards_timeout(PostFailBackAction::ClaimOffChain);
2286+
}
2287+
2288+
fn do_test_fail_back_before_backwards_timeout(post_fail_back_action: PostFailBackAction) {
2289+
// Test that we fail an HTLC upstream if we are still waiting for confirmation downstream
2290+
// just before the upstream timeout expires
2291+
let chanmon_cfgs = create_chanmon_cfgs(3);
2292+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
2293+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
2294+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
2295+
for node in nodes.iter() {
2296+
*node.fee_estimator.sat_per_kw.lock().unwrap() = 2000;
2297+
}
2298+
2299+
let node_b_id = nodes[1].node.get_our_node_id();
2300+
let node_c_id = nodes[2].node.get_our_node_id();
2301+
2302+
create_announced_chan_between_nodes(&nodes, 0, 1);
2303+
let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
2304+
2305+
// Start every node on the same block height to make reasoning about timeouts easier
2306+
connect_blocks(&nodes[0], 2*CHAN_CONFIRM_DEPTH + 1 - nodes[0].best_block_info().1);
2307+
connect_blocks(&nodes[1], 2*CHAN_CONFIRM_DEPTH + 1 - nodes[1].best_block_info().1);
2308+
connect_blocks(&nodes[2], 2*CHAN_CONFIRM_DEPTH + 1 - nodes[2].best_block_info().1);
2309+
2310+
let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 3_000_000);
2311+
2312+
// Force close the B<->C channel by timing out the HTLC
2313+
let timeout_blocks = TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1;
2314+
connect_blocks(&nodes[1], timeout_blocks);
2315+
let node_1_txn = test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::TIMEOUT);
2316+
check_closed_event(&nodes[1], 1, ClosureReason::HTLCsTimedOut, false, &[node_c_id], 100_000);
2317+
check_closed_broadcast(&nodes[1], 1, true);
2318+
check_added_monitors(&nodes[1], 1);
2319+
2320+
// After the A<->B HTLC gets within LATENCY_GRACE_PERIOD_BLOCKS we will fail the HTLC to avoid
2321+
// the channel force-closing. Note that we already connected `TEST_FINAL_CLTV +
2322+
// LATENCY_GRACE_PERIOD_BLOCKS` blocks above, so we subtract that from the HTLC expiry (which
2323+
// is `TEST_FINAL_CLTV` + `MIN_CLTV_EXPIRY_DELTA`).
2324+
let upstream_timeout_blocks = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS * 2;
2325+
connect_blocks(&nodes[1], upstream_timeout_blocks);
2326+
2327+
// Connect blocks for nodes[0] to make sure they don't go on-chain
2328+
connect_blocks(&nodes[0], timeout_blocks + upstream_timeout_blocks);
2329+
2330+
// Check that nodes[1] fails the HTLC upstream
2331+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1],
2332+
vec![HTLCDestination::NextHopChannel {
2333+
node_id: Some(nodes[2].node.get_our_node_id()),
2334+
channel_id: chan_2.2
2335+
}]);
2336+
check_added_monitors!(nodes[1], 1);
2337+
let htlc_updates = get_htlc_update_msgs(&nodes[1], &nodes[0].node.get_our_node_id());
2338+
let msgs::CommitmentUpdate { update_fail_htlcs, commitment_signed, .. } = htlc_updates;
2339+
2340+
nodes[0].node.handle_update_fail_htlc(nodes[1].node.get_our_node_id(), &update_fail_htlcs[0]);
2341+
commitment_signed_dance!(nodes[0], nodes[1], commitment_signed, false);
2342+
expect_payment_failed_conditions(&nodes[0], payment_hash, false,
2343+
PaymentFailedConditions::new().blamed_chan_closed(true));
2344+
2345+
// Make sure we handle possible duplicate fails or extra messages after failing back
2346+
match post_fail_back_action {
2347+
PostFailBackAction::TimeoutOnChain => {
2348+
// Confirm nodes[1]'s claim with timeout, make sure we don't fail upstream again
2349+
mine_transaction(&nodes[1], &node_1_txn[0]); // Commitment
2350+
mine_transaction(&nodes[1], &node_1_txn[1]); // HTLC timeout
2351+
connect_blocks(&nodes[1], ANTI_REORG_DELAY);
2352+
// Expect handling another fail back event, but the HTLC is already gone
2353+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1],
2354+
vec![HTLCDestination::NextHopChannel {
2355+
node_id: Some(nodes[2].node.get_our_node_id()),
2356+
channel_id: chan_2.2
2357+
}]);
2358+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
2359+
},
2360+
PostFailBackAction::ClaimOnChain => {
2361+
nodes[2].node.claim_funds(payment_preimage);
2362+
expect_payment_claimed!(nodes[2], payment_hash, 3_000_000);
2363+
check_added_monitors!(nodes[2], 1);
2364+
get_htlc_update_msgs(&nodes[2], &nodes[1].node.get_our_node_id());
2365+
2366+
connect_blocks(&nodes[2], TEST_FINAL_CLTV - CLTV_CLAIM_BUFFER + 2);
2367+
let node_2_txn = test_txn_broadcast(&nodes[2], &chan_2, None, HTLCType::SUCCESS);
2368+
check_closed_broadcast!(nodes[2], true);
2369+
check_closed_event(&nodes[2], 1, ClosureReason::HTLCsTimedOut, false, &[node_b_id], 100_000);
2370+
check_added_monitors!(nodes[2], 1);
2371+
2372+
mine_transaction(&nodes[1], &node_2_txn[0]); // Commitment
2373+
mine_transaction(&nodes[1], &node_2_txn[1]); // HTLC success
2374+
connect_blocks(&nodes[1], ANTI_REORG_DELAY);
2375+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
2376+
},
2377+
PostFailBackAction::FailOffChain => {
2378+
nodes[2].node.fail_htlc_backwards(&payment_hash);
2379+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[2],
2380+
vec![HTLCDestination::FailedPayment { payment_hash }]);
2381+
check_added_monitors!(nodes[2], 1);
2382+
let commitment_update = get_htlc_update_msgs(&nodes[2], &nodes[1].node.get_our_node_id());
2383+
let update_fail = commitment_update.update_fail_htlcs[0].clone();
2384+
2385+
nodes[1].node.handle_update_fail_htlc(nodes[2].node.get_our_node_id(), &update_fail);
2386+
let err_msg = get_err_msg(&nodes[1], &nodes[2].node.get_our_node_id());
2387+
assert_eq!(err_msg.channel_id, chan_2.2);
2388+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
2389+
},
2390+
PostFailBackAction::ClaimOffChain => {
2391+
nodes[2].node.claim_funds(payment_preimage);
2392+
expect_payment_claimed!(nodes[2], payment_hash, 3_000_000);
2393+
check_added_monitors!(nodes[2], 1);
2394+
let commitment_update = get_htlc_update_msgs(&nodes[2], &nodes[1].node.get_our_node_id());
2395+
let update_fulfill = commitment_update.update_fulfill_htlcs[0].clone();
2396+
2397+
nodes[1].node.handle_update_fulfill_htlc(nodes[2].node.get_our_node_id(), &update_fulfill);
2398+
let err_msg = get_err_msg(&nodes[1], &nodes[2].node.get_our_node_id());
2399+
assert_eq!(err_msg.channel_id, chan_2.2);
2400+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
2401+
},
2402+
};
2403+
}
2404+
22732405
#[test]
22742406
fn channel_monitor_network_test() {
22752407
// Simple test which builds a network of ChannelManagers, connects them to each other, and
@@ -2374,7 +2506,7 @@ fn channel_monitor_network_test() {
23742506
let node2_commitment_txid;
23752507
{
23762508
let node_txn = test_txn_broadcast(&nodes[2], &chan_3, None, HTLCType::NONE);
2377-
connect_blocks(&nodes[2], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + MIN_CLTV_EXPIRY_DELTA as u32 + 1);
2509+
connect_blocks(&nodes[2], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
23782510
test_txn_broadcast(&nodes[2], &chan_3, None, HTLCType::TIMEOUT);
23792511
node2_commitment_txid = node_txn[0].compute_txid();
23802512

@@ -3312,8 +3444,8 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) {
33123444
// Broadcast timeout transaction by B on received output from C's commitment tx on B's chain
33133445
// Verify that B's ChannelManager is able to detect that HTLC is timeout by its own tx and react backward in consequence
33143446
mine_transaction(&nodes[1], &commitment_tx[0]);
3315-
check_closed_event!(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, false
3316-
, [nodes[2].node.get_our_node_id()], 100000);
3447+
check_closed_event(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, false,
3448+
&[nodes[2].node.get_our_node_id()], 100000);
33173449
let htlc_expiry = get_monitor!(nodes[1], chan_2.2).get_claimable_balances().iter().filter_map(|bal|
33183450
if let Balance::MaybeTimeoutClaimableHTLC { claimable_height, .. } = bal {
33193451
Some(*claimable_height)
@@ -9774,6 +9906,8 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
97749906
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
97759907
*nodes[0].connect_style.borrow_mut() = ConnectStyle::BestBlockFirstSkippingBlocks;
97769908

9909+
let node_c_id = nodes[2].node.get_our_node_id();
9910+
97779911
create_announced_chan_between_nodes(&nodes, 0, 1);
97789912
let (chan_announce, _, channel_id, _) = create_announced_chan_between_nodes(&nodes, 1, 2);
97799913
let (_, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000);
@@ -9789,7 +9923,7 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
97899923

97909924
let conf_height = nodes[1].best_block_info().1;
97919925
if !test_height_before_timelock {
9792-
connect_blocks(&nodes[1], 24 * 6);
9926+
connect_blocks(&nodes[1], TEST_FINAL_CLTV - LATENCY_GRACE_PERIOD_BLOCKS);
97939927
}
97949928
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(
97959929
&nodes[1].get_block_header(conf_height), &[(0, &node_txn[0])], conf_height);
@@ -9808,10 +9942,6 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
98089942
&spending_txn[0]
98099943
};
98109944
check_spends!(htlc_tx, node_txn[0]);
9811-
// We should also generate a SpendableOutputs event with the to_self output (as its
9812-
// timelock is up).
9813-
let descriptor_spend_txn = check_spendable_outputs!(nodes[1], node_cfgs[1].keys_manager);
9814-
assert_eq!(descriptor_spend_txn.len(), 1);
98159945

98169946
// If we also discover that the HTLC-Timeout transaction was confirmed some time ago, we
98179947
// should immediately fail-backwards the HTLC to the previous hop, without waiting for an
@@ -9830,6 +9960,18 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
98309960
nodes[0].node.handle_update_fail_htlc(nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
98319961
commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, true, true);
98329962
expect_payment_failed_with_update!(nodes[0], payment_hash, false, chan_announce.contents.short_channel_id, true);
9963+
9964+
// We should also generate a SpendableOutputs event with the to_self output (once the
9965+
// timelock is up).
9966+
connect_blocks(&nodes[1], (BREAKDOWN_TIMEOUT as u32) - TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS - 1);
9967+
let descriptor_spend_txn = check_spendable_outputs!(nodes[1], node_cfgs[1].keys_manager);
9968+
assert_eq!(descriptor_spend_txn.len(), 1);
9969+
9970+
// When the HTLC times out on the A<->B edge, the B<->C channel will fail the HTLC back to
9971+
// avoid the A<->B channel closing (even though it already has). This will generate a
9972+
// spurious HTLCHandlingFailed event.
9973+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1],
9974+
vec![HTLCDestination::NextHopChannel { node_id: Some(node_c_id), channel_id }]);
98339975
}
98349976
}
98359977

0 commit comments

Comments
 (0)