Skip to content

Commit 6a5574d

Browse files
Fail blinded received HTLCs if they violate PaymentConstraints
.. contained within their encrypted payload.
1 parent 5b509c5 commit 6a5574d

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

lightning/src/ln/blinded_payment_tests.rs

+29-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::ln::onion_utils;
2222
use crate::ln::onion_utils::INVALID_ONION_BLINDING;
2323
use crate::ln::outbound_payment::Retry;
2424
use crate::prelude::*;
25-
use crate::routing::router::{PaymentParameters, RouteParameters};
25+
use crate::routing::router::{Payee, PaymentParameters, RouteParameters};
2626
use crate::util::config::UserConfig;
2727
use crate::util::test_utils;
2828

@@ -505,6 +505,8 @@ enum ReceiveCheckFail {
505505
// The HTLC is successfully added to the inbound channel but fails receive checks in
506506
// process_pending_htlc_forwards.
507507
ProcessPendingHTLCsCheck,
508+
// The HTLC violates the `PaymentConstraints` contained within the receiver's encrypted payload.
509+
PaymentConstraints,
508510
}
509511

510512
#[test]
@@ -514,6 +516,7 @@ fn multi_hop_receiver_fail() {
514516
do_multi_hop_receiver_fail(ReceiveCheckFail::ReceiveRequirements);
515517
do_multi_hop_receiver_fail(ReceiveCheckFail::ChannelCheck);
516518
do_multi_hop_receiver_fail(ReceiveCheckFail::ProcessPendingHTLCsCheck);
519+
do_multi_hop_receiver_fail(ReceiveCheckFail::PaymentConstraints);
517520
}
518521

519522
fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) {
@@ -539,7 +542,7 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) {
539542
Some(TEST_FINAL_CLTV as u16 - 2)
540543
} else { None };
541544
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
542-
let route_params = get_blinded_route_parameters(amt_msat, payment_secret,
545+
let mut route_params = get_blinded_route_parameters(amt_msat, payment_secret,
543546
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(), &[&chan_upd_1_2],
544547
&chanmon_cfgs[2].keys_manager);
545548

@@ -548,7 +551,25 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) {
548551
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
549552
route.paths[0].blinded_tail.as_mut().map(|bt| bt.excess_final_cltv_expiry_delta = TEST_FINAL_CLTV - 2);
550553
route
551-
} else {
554+
} else if check == ReceiveCheckFail::PaymentConstraints {
555+
// Create a blinded path where the receiver's encrypted payload has an htlc_minimum_msat that is
556+
// violated by `amt_msat`, and stick it in the route_params without changing the corresponding
557+
// BlindedPayInfo (to ensure pathfinding still succeeds).
558+
let high_htlc_min_bp = {
559+
let mut high_htlc_minimum_upd = chan_upd_1_2.clone();
560+
high_htlc_minimum_upd.htlc_minimum_msat = amt_msat + 1000;
561+
let high_htlc_min_params = get_blinded_route_parameters(amt_msat, payment_secret,
562+
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(), &[&high_htlc_minimum_upd],
563+
&chanmon_cfgs[2].keys_manager);
564+
if let Payee::Blinded { route_hints, .. } = high_htlc_min_params.payment_params.payee {
565+
route_hints[0].1.clone()
566+
} else { panic!() }
567+
};
568+
if let Payee::Blinded { ref mut route_hints, .. } = route_params.payment_params.payee {
569+
route_hints[0].1 = high_htlc_min_bp;
570+
} else { panic!() }
571+
find_route(&nodes[0], &route_params).unwrap()
572+
} else {
552573
find_route(&nodes[0], &route_params).unwrap()
553574
};
554575
node_cfgs[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
@@ -643,6 +664,11 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) {
643664
expect_pending_htlcs_forwardable_and_htlc_handling_failed_ignore!(nodes[2],
644665
vec![HTLCDestination::FailedPayment { payment_hash }]);
645666
check_added_monitors!(nodes[2], 1);
667+
},
668+
ReceiveCheckFail::PaymentConstraints => {
669+
nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event_1_2.msgs[0]);
670+
check_added_monitors!(nodes[2], 0);
671+
do_commitment_signed_dance(&nodes[2], &nodes[1], &payment_event_1_2.commitment_msg, true, true);
646672
}
647673
}
648674

lightning/src/ln/channelmanager.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -3026,8 +3026,18 @@ where
30263026
(payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value,
30273027
payment_metadata, None),
30283028
msgs::InboundOnionPayload::BlindedReceive {
3029-
amt_msat, total_msat, outgoing_cltv_value, payment_secret, intro_node_blinding_point, ..
3029+
amt_msat, total_msat, outgoing_cltv_value, payment_secret, intro_node_blinding_point,
3030+
payment_constraints, ..
30303031
} => {
3032+
if amt_msat < payment_constraints.htlc_minimum_msat ||
3033+
cltv_expiry > payment_constraints.max_cltv_expiry
3034+
{
3035+
return Err(InboundOnionErr {
3036+
err_code: INVALID_ONION_BLINDING,
3037+
err_data: vec![0; 32],
3038+
msg: "Amount or cltv_expiry violated blinded payment constraints",
3039+
})
3040+
}
30313041
let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
30323042
let blinded = if intro_node_blinding_point.is_some() { None } else { Some(()) };
30333043
(Some(payment_data), None, Vec::new(), amt_msat, outgoing_cltv_value, None, blinded)

0 commit comments

Comments
 (0)