Skip to content

Commit fff9f22

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 7b6a7bb commit fff9f22

File tree

2 files changed

+70
-5
lines changed

2 files changed

+70
-5
lines changed

lightning/src/ln/channelmanager.rs

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

32133213
macro_rules! check_total_value {
32143214
($payment_data_total_msat: expr, $payment_secret: expr, $payment_preimage: expr) => {{
3215-
let mut total_value = 0;
32163215
let mut payment_received_generated = false;
32173216
let htlcs = channel_state.claimable_htlcs.entry(payment_hash)
32183217
.or_insert(Vec::new());
@@ -3223,7 +3222,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32233222
continue
32243223
}
32253224
}
3226-
htlcs.push(claimable_htlc);
3225+
let mut total_value = claimable_htlc.value;
32273226
for htlc in htlcs.iter() {
32283227
total_value += htlc.value;
32293228
match &htlc.onion_payload {
@@ -3241,10 +3240,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32413240
if total_value >= msgs::MAX_VALUE_MSAT || total_value > $payment_data_total_msat {
32423241
log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the total value {} ran over expected value {} (or HTLCs were inconsistent)",
32433242
log_bytes!(payment_hash.0), total_value, $payment_data_total_msat);
3244-
for htlc in htlcs.iter() {
3245-
fail_htlc!(htlc);
3246-
}
3243+
fail_htlc!(claimable_htlc);
32473244
} else if total_value == $payment_data_total_msat {
3245+
htlcs.push(claimable_htlc);
32483246
new_events.push(events::Event::PaymentReceived {
32493247
payment_hash,
32503248
purpose: events::PaymentPurpose::InvoicePayment {
@@ -3258,6 +3256,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32583256
// Nothing to do - we haven't reached the total
32593257
// payment value yet, wait until we receive more
32603258
// MPP parts.
3259+
htlcs.push(claimable_htlc);
32613260
}
32623261
payment_received_generated
32633262
}}

lightning/src/ln/functional_tests.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9274,6 +9274,72 @@ fn test_forwardable_regen() {
92749274
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage_2);
92759275
}
92769276

9277+
#[test]
9278+
fn test_dup_htlc_second_fail_panic() {
9279+
// Previously, if we received two HTLCs back-to-back, where the second overran the expected
9280+
// value for the payment, we'd fail back both HTLCs after generating a `PaymentReceived` event.
9281+
// Then, if the user failed the second payment, they'd hit a "tried to fail an already failed
9282+
// HTLC" debug panic. This tests for this behavior, checking that only one HTLC is auto-failed.
9283+
let chanmon_cfgs = create_chanmon_cfgs(2);
9284+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
9285+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
9286+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
9287+
9288+
let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
9289+
9290+
let payee = Payee::from_node_id(nodes[1].node.get_our_node_id())
9291+
.with_features(InvoiceFeatures::known());
9292+
let scorer = test_utils::TestScorer::with_fixed_penalty(0);
9293+
let route = get_route(
9294+
&nodes[0].node.get_our_node_id(), &payee, &nodes[0].network_graph,
9295+
Some(&nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()),
9296+
10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer).unwrap();
9297+
9298+
let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(&nodes[1]);
9299+
9300+
{
9301+
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
9302+
check_added_monitors!(nodes[0], 1);
9303+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
9304+
assert_eq!(events.len(), 1);
9305+
let mut payment_event = SendEvent::from_event(events.pop().unwrap());
9306+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
9307+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
9308+
}
9309+
expect_pending_htlcs_forwardable!(nodes[1]);
9310+
expect_payment_received!(nodes[1], our_payment_hash, our_payment_secret, 10_000);
9311+
9312+
{
9313+
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
9314+
check_added_monitors!(nodes[0], 1);
9315+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
9316+
assert_eq!(events.len(), 1);
9317+
let mut payment_event = SendEvent::from_event(events.pop().unwrap());
9318+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
9319+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
9320+
}
9321+
9322+
expect_pending_htlcs_forwardable_ignore!(nodes[1]);
9323+
nodes[1].node.process_pending_htlc_forwards();
9324+
nodes[1].node.fail_htlc_backwards(&our_payment_hash);
9325+
9326+
expect_pending_htlcs_forwardable_ignore!(nodes[1]);
9327+
nodes[1].node.process_pending_htlc_forwards();
9328+
9329+
check_added_monitors!(nodes[1], 1);
9330+
let fail_updates_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
9331+
assert_eq!(fail_updates_1.update_fail_htlcs.len(), 2);
9332+
9333+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_updates_1.update_fail_htlcs[0]);
9334+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_updates_1.update_fail_htlcs[1]);
9335+
commitment_signed_dance!(nodes[0], nodes[1], fail_updates_1.commitment_signed, false);
9336+
9337+
let failure_events = nodes[0].node.get_and_clear_pending_events();
9338+
assert_eq!(failure_events.len(), 2);
9339+
if let Event::PaymentPathFailed { .. } = failure_events[0] {} else { panic!(); }
9340+
if let Event::PaymentPathFailed { .. } = failure_events[1] {} else { panic!(); }
9341+
}
9342+
92779343
#[test]
92789344
fn test_keysend_payments_to_public_node() {
92799345
let chanmon_cfgs = create_chanmon_cfgs(2);

0 commit comments

Comments
 (0)