Skip to content

Commit 6963742

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 b88a403 commit 6963742

File tree

2 files changed

+224
-8
lines changed

2 files changed

+224
-8
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 74 additions & 0 deletions
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

Lines changed: 150 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,6 +2277,138 @@ fn channel_reserve_in_flight_removes() {
22772277
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_3);
22782278
}
22792279

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

@@ -3319,8 +3451,8 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) {
33193451
// Broadcast timeout transaction by B on received output from C's commitment tx on B's chain
33203452
// Verify that B's ChannelManager is able to detect that HTLC is timeout by its own tx and react backward in consequence
33213453
mine_transaction(&nodes[1], &commitment_tx[0]);
3322-
check_closed_event!(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, false
3323-
, [nodes[2].node.get_our_node_id()], 100000);
3454+
check_closed_event(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, false,
3455+
&[nodes[2].node.get_our_node_id()], 100000);
33243456
let htlc_expiry = get_monitor!(nodes[1], chan_2.2).get_claimable_balances().iter().filter_map(|bal|
33253457
if let Balance::MaybeTimeoutClaimableHTLC { claimable_height, .. } = bal {
33263458
Some(*claimable_height)
@@ -9792,6 +9924,8 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
97929924
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
97939925
*nodes[0].connect_style.borrow_mut() = ConnectStyle::BestBlockFirstSkippingBlocks;
97949926

9927+
let node_c_id = nodes[2].node.get_our_node_id();
9928+
97959929
create_announced_chan_between_nodes(&nodes, 0, 1);
97969930
let (chan_announce, _, channel_id, _) = create_announced_chan_between_nodes(&nodes, 1, 2);
97979931
let (_, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000);
@@ -9807,7 +9941,7 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
98079941

98089942
let conf_height = nodes[1].best_block_info().1;
98099943
if !test_height_before_timelock {
9810-
connect_blocks(&nodes[1], 24 * 6);
9944+
connect_blocks(&nodes[1], TEST_FINAL_CLTV - LATENCY_GRACE_PERIOD_BLOCKS);
98119945
}
98129946
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(
98139947
&nodes[1].get_block_header(conf_height), &[(0, &node_txn[0])], conf_height);
@@ -9826,10 +9960,6 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
98269960
&spending_txn[0]
98279961
};
98289962
check_spends!(htlc_tx, node_txn[0]);
9829-
// We should also generate a SpendableOutputs event with the to_self output (as its
9830-
// timelock is up).
9831-
let descriptor_spend_txn = check_spendable_outputs!(nodes[1], node_cfgs[1].keys_manager);
9832-
assert_eq!(descriptor_spend_txn.len(), 1);
98339963

98349964
// If we also discover that the HTLC-Timeout transaction was confirmed some time ago, we
98359965
// should immediately fail-backwards the HTLC to the previous hop, without waiting for an
@@ -9848,6 +9978,18 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t
98489978
nodes[0].node.handle_update_fail_htlc(nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
98499979
commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, true, true);
98509980
expect_payment_failed_with_update!(nodes[0], payment_hash, false, chan_announce.contents.short_channel_id, true);
9981+
9982+
// We should also generate a SpendableOutputs event with the to_self output (once the
9983+
// timelock is up).
9984+
connect_blocks(&nodes[1], (BREAKDOWN_TIMEOUT as u32) - TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS - 1);
9985+
let descriptor_spend_txn = check_spendable_outputs!(nodes[1], node_cfgs[1].keys_manager);
9986+
assert_eq!(descriptor_spend_txn.len(), 1);
9987+
9988+
// When the HTLC times out on the A<->B edge, the B<->C channel will fail the HTLC back to
9989+
// avoid the A<->B channel closing (even though it already has). This will generate a
9990+
// spurious HTLCHandlingFailed event.
9991+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1],
9992+
vec![HTLCDestination::NextHopChannel { node_id: Some(node_c_id), channel_id }]);
98519993
}
98529994
}
98539995

0 commit comments

Comments
 (0)