Skip to content

Commit be57e82

Browse files
committed
Fix a debug panic caused by receiving MPP parts after a failure
Prior to cryptographic payment secrets, when we process a received payment in `process_pending_htlc_fowards` we'd remove its entry from the `pending_inbound_payments` map and give the user a `PaymentReceived` event. Thereafter, if a second HTLC came in with the same payment hash, it would find no entry in the `pending_inbound_payments` map and be immediately failed in `process_pending_htlc_forwards`. Thus, each HTLC will either result in a `PaymentReceived` event or be failed, with no possibility for both. As of 8464875, we no longer materially have a pending-inbound-payments map, and thus more-than-happily accept a second payment with the same payment hash even if we just failed a previous one for having mis-matched payment data. This can cause an issue if the two HTLCs are received back-to-back, with the first being accepted as valid, generating a `PaymentReceived` event. Then, when the second comes in we'll hit the "total value {} ran over expected value" condition and fail *all* pending HTLCs with the same payment hash. At this point, we'll have a pending failure for both HTLCs, as well as a `PaymentReceived` event for the user. Thereafter, if the user attempts to fail the HTLC in response to the `PaymentReceived`, they'll get a debug panic at channel.rs:1657 'Tried to fail an HTLC that was already failed'. The solution is to avoid bulk-failing all pending HTLCs for a payment. This feels like the right thing to do anyway - if a sender accidentally sends an extra HTLC after a payment has ben fully paid, we shouldn't fail the entire payment. Found by the `chanmon_consistency` fuzz test.
1 parent 0df247d commit be57e82

File tree

2 files changed

+75
-5
lines changed

2 files changed

+75
-5
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3191,7 +3191,6 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
31913191

31923192
macro_rules! check_total_value {
31933193
($payment_data_total_msat: expr, $payment_secret: expr, $payment_preimage: expr) => {{
3194-
let mut total_value = 0;
31953194
let mut payment_received_generated = false;
31963195
let htlcs = channel_state.claimable_htlcs.entry(payment_hash)
31973196
.or_insert(Vec::new());
@@ -3202,7 +3201,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32023201
continue
32033202
}
32043203
}
3205-
htlcs.push(claimable_htlc);
3204+
let mut total_value = claimable_htlc.value;
32063205
for htlc in htlcs.iter() {
32073206
total_value += htlc.value;
32083207
match &htlc.onion_payload {
@@ -3220,10 +3219,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32203219
if total_value >= msgs::MAX_VALUE_MSAT || total_value > $payment_data_total_msat {
32213220
log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the total value {} ran over expected value {} (or HTLCs were inconsistent)",
32223221
log_bytes!(payment_hash.0), total_value, $payment_data_total_msat);
3223-
for htlc in htlcs.iter() {
3224-
fail_htlc!(htlc);
3225-
}
3222+
fail_htlc!(claimable_htlc);
32263223
} else if total_value == $payment_data_total_msat {
3224+
htlcs.push(claimable_htlc);
32273225
new_events.push(events::Event::PaymentReceived {
32283226
payment_hash,
32293227
purpose: events::PaymentPurpose::InvoicePayment {
@@ -3237,6 +3235,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32373235
// Nothing to do - we haven't reached the total
32383236
// payment value yet, wait until we receive more
32393237
// MPP parts.
3238+
htlcs.push(claimable_htlc);
32403239
}
32413240
payment_received_generated
32423241
}}

lightning/src/ln/functional_tests.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9601,6 +9601,77 @@ fn test_forwardable_regen() {
96019601
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage_2);
96029602
}
96039603

9604+
#[test]
9605+
fn test_dup_htlc_second_fail_panic() {
9606+
// Previously, if we received two HTLCs back-to-back, where the second overran the expected
9607+
// value for the payment, we'd fail back both HTLCs after generating a `PaymentReceived` event.
9608+
// Then, if the user failed the second payment, they'd hit a "tried to fail an already failed
9609+
// HTLC" debug panic. This tests for this behavior, checking that only one HTLC is auto-failed.
9610+
let chanmon_cfgs = create_chanmon_cfgs(2);
9611+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
9612+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
9613+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
9614+
9615+
let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
9616+
9617+
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
9618+
.with_features(InvoiceFeatures::known());
9619+
let scorer = test_utils::TestScorer::with_penalty(0);
9620+
let route = get_route(
9621+
&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph,
9622+
Some(&nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()),
9623+
10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer).unwrap();
9624+
9625+
let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(&nodes[1]);
9626+
9627+
{
9628+
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
9629+
check_added_monitors!(nodes[0], 1);
9630+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
9631+
assert_eq!(events.len(), 1);
9632+
let mut payment_event = SendEvent::from_event(events.pop().unwrap());
9633+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
9634+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
9635+
}
9636+
expect_pending_htlcs_forwardable!(nodes[1]);
9637+
expect_payment_received!(nodes[1], our_payment_hash, our_payment_secret, 10_000);
9638+
9639+
{
9640+
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
9641+
check_added_monitors!(nodes[0], 1);
9642+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
9643+
assert_eq!(events.len(), 1);
9644+
let mut payment_event = SendEvent::from_event(events.pop().unwrap());
9645+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
9646+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
9647+
// At this point, nodes[1] would notice it has too much value for the payment. It will
9648+
// assume the second is a privacy attack (no longer particularly relevant
9649+
// post-payment_secrets) and fail back the new HTLC. Previously, it'd also have failed back
9650+
// the first HTLC delivered above.
9651+
}
9652+
9653+
// Now we go fail back the first HTLC from the user end.
9654+
expect_pending_htlcs_forwardable_ignore!(nodes[1]);
9655+
nodes[1].node.process_pending_htlc_forwards();
9656+
nodes[1].node.fail_htlc_backwards(&our_payment_hash);
9657+
9658+
expect_pending_htlcs_forwardable_ignore!(nodes[1]);
9659+
nodes[1].node.process_pending_htlc_forwards();
9660+
9661+
check_added_monitors!(nodes[1], 1);
9662+
let fail_updates_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
9663+
assert_eq!(fail_updates_1.update_fail_htlcs.len(), 2);
9664+
9665+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_updates_1.update_fail_htlcs[0]);
9666+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_updates_1.update_fail_htlcs[1]);
9667+
commitment_signed_dance!(nodes[0], nodes[1], fail_updates_1.commitment_signed, false);
9668+
9669+
let failure_events = nodes[0].node.get_and_clear_pending_events();
9670+
assert_eq!(failure_events.len(), 2);
9671+
if let Event::PaymentPathFailed { .. } = failure_events[0] {} else { panic!(); }
9672+
if let Event::PaymentPathFailed { .. } = failure_events[1] {} else { panic!(); }
9673+
}
9674+
96049675
#[test]
96059676
fn test_keysend_payments_to_public_node() {
96069677
let chanmon_cfgs = create_chanmon_cfgs(2);

0 commit comments

Comments
 (0)