Skip to content

Commit d593d6f

Browse files
Correctly fail back blinded HTLCs on initial forwarding check fail
1 parent 0ca544e commit d593d6f

File tree

2 files changed

+118
-3
lines changed

2 files changed

+118
-3
lines changed

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,3 +562,115 @@ fn fail_blinded_payment() {
562562
_ => panic!("Unexpected event"),
563563
}
564564
}
565+
566+
#[test]
567+
fn outbound_checks_failure() {
568+
do_outbound_checks_failure(true);
569+
do_outbound_checks_failure(false);
570+
}
571+
572+
fn do_outbound_checks_failure(intro_node_fails: bool) {
573+
// Ensure we'll fail backwards properly if a forwarding check fails on initial update_add
574+
// receipt.
575+
let chanmon_cfgs = create_chanmon_cfgs(4);
576+
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
577+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
578+
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
579+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
580+
let chan_upd_1_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0).0.contents;
581+
let chan_upd_2_3 = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0).0.contents;
582+
583+
let amt_msat = 5000;
584+
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None);
585+
let intermediate_nodes = vec![(nodes[1].node.get_our_node_id(), ForwardTlvs {
586+
short_channel_id: chan_upd_1_2.short_channel_id,
587+
payment_relay: PaymentRelay {
588+
cltv_expiry_delta: chan_upd_1_2.cltv_expiry_delta,
589+
fee_proportional_millionths: chan_upd_1_2.fee_proportional_millionths,
590+
fee_base_msat: chan_upd_1_2.fee_base_msat,
591+
},
592+
payment_constraints: PaymentConstraints {
593+
max_cltv_expiry: u32::max_value(),
594+
htlc_minimum_msat: chan_upd_1_2.htlc_minimum_msat,
595+
},
596+
features: BlindedHopFeatures::empty(),
597+
}), (nodes[2].node.get_our_node_id(), ForwardTlvs {
598+
short_channel_id: chan_upd_2_3.short_channel_id,
599+
payment_relay: PaymentRelay {
600+
cltv_expiry_delta: chan_upd_2_3.cltv_expiry_delta,
601+
fee_proportional_millionths: chan_upd_2_3.fee_proportional_millionths,
602+
fee_base_msat: chan_upd_2_3.fee_base_msat,
603+
},
604+
payment_constraints: PaymentConstraints {
605+
max_cltv_expiry: u32::max_value(),
606+
htlc_minimum_msat: chan_upd_2_3.htlc_minimum_msat,
607+
},
608+
features: BlindedHopFeatures::empty(),
609+
})];
610+
let payee_tlvs = ReceiveTlvs {
611+
payment_secret,
612+
payment_constraints: PaymentConstraints {
613+
max_cltv_expiry: u32::max_value(),
614+
htlc_minimum_msat: chan_upd_2_3.htlc_minimum_msat,
615+
},
616+
};
617+
let mut secp_ctx = Secp256k1::new();
618+
let blinded_path = BlindedPath::new_for_payment(
619+
&intermediate_nodes[..], nodes[3].node.get_our_node_id(), payee_tlvs,
620+
chan_upd_2_3.htlc_maximum_msat, &chanmon_cfgs[3].keys_manager, &secp_ctx
621+
).unwrap();
622+
623+
let route_params = RouteParameters {
624+
payment_params: PaymentParameters::blinded(vec![blinded_path]),
625+
final_value_msat: amt_msat
626+
};
627+
nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(),
628+
PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap();
629+
check_added_monitors(&nodes[0], 1);
630+
631+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
632+
assert_eq!(events.len(), 1);
633+
let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
634+
let payment_event = SendEvent::from_event(ev);
635+
636+
if intro_node_fails {
637+
// The intro node will see that the next-hop peer is disconnected and fail the HTLC backwards.
638+
nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id());
639+
}
640+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
641+
check_added_monitors!(nodes[1], 0);
642+
do_commitment_signed_dance(&nodes[1], &nodes[0], &payment_event.commitment_msg, true, true);
643+
644+
if intro_node_fails {
645+
let mut updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
646+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
647+
do_commitment_signed_dance(&nodes[0], &nodes[1], &updates.commitment_signed, false, false);
648+
expect_payment_failed_conditions(&nodes[0], payment_hash, false,
649+
PaymentFailedConditions::new().expected_htlc_error_data(INVALID_ONION_BLINDING, &[0; 32]));
650+
return
651+
}
652+
653+
expect_pending_htlcs_forwardable!(nodes[1]);
654+
check_added_monitors!(nodes[1], 1);
655+
let mut events = nodes[1].node.get_and_clear_pending_msg_events();
656+
assert_eq!(events.len(), 1);
657+
let ev = remove_first_msg_event_to_node(&nodes[2].node.get_our_node_id(), &mut events);
658+
let payment_event = SendEvent::from_event(ev);
659+
660+
nodes[2].node.peer_disconnected(&nodes[3].node.get_our_node_id());
661+
nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]);
662+
check_added_monitors!(nodes[2], 0);
663+
do_commitment_signed_dance(&nodes[2], &nodes[1], &payment_event.commitment_msg, true, true);
664+
665+
let mut updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
666+
assert_eq!(updates.update_fail_malformed_htlcs[0].failure_code, INVALID_ONION_BLINDING);
667+
assert_eq!(updates.update_fail_malformed_htlcs[0].sha256_of_onion, [0; 32]);
668+
nodes[1].node.handle_update_fail_malformed_htlc(&nodes[2].node.get_our_node_id(), &updates.update_fail_malformed_htlcs[0]);
669+
do_commitment_signed_dance(&nodes[1], &nodes[2], &updates.commitment_signed, true, false);
670+
671+
let mut updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
672+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
673+
do_commitment_signed_dance(&nodes[0], &nodes[1], &updates.commitment_signed, false, false);
674+
expect_payment_failed_conditions(&nodes[0], payment_hash, false,
675+
PaymentFailedConditions::new().expected_htlc_error_data(INVALID_ONION_BLINDING, &[0; 32]));
676+
}

lightning/src/ln/channelmanager.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3007,15 +3007,17 @@ where
30073007
return_err!(err_msg, err_code, &[0; 0]);
30083008
},
30093009
};
3010-
let (outgoing_scid, outgoing_amt_msat, outgoing_cltv_value, next_packet_pk_opt) = match next_hop {
3010+
let (outgoing_scid, outgoing_amt_msat, outgoing_cltv_value, next_packet_pk_opt, blinded)
3011+
= match next_hop
3012+
{
30113013
onion_utils::Hop::Forward {
30123014
next_hop_data: msgs::InboundOnionPayload::Forward {
30133015
short_channel_id, amt_to_forward, outgoing_cltv_value
30143016
}, ..
30153017
} => {
30163018
let next_packet_pk = onion_utils::next_hop_pubkey(&self.secp_ctx,
30173019
msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
3018-
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk))
3020+
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk), false)
30193021
},
30203022
onion_utils::Hop::Forward {
30213023
next_hop_data: msgs::InboundOnionPayload::BlindedForward {
@@ -3048,7 +3050,7 @@ where
30483050
}
30493051
let next_packet_pk = onion_utils::next_hop_pubkey(&self.secp_ctx,
30503052
msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
3051-
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk))
3053+
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk), true)
30523054
},
30533055
// We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
30543056
// inbound channel's state.
@@ -3172,6 +3174,7 @@ where
31723174
break None;
31733175
}
31743176
{
3177+
if blinded { return_blinded_htlc_err!(err); }
31753178
let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 2 + 8 + 2));
31763179
if let Some(chan_update) = chan_update {
31773180
if code == 0x1000 | 11 || code == 0x1000 | 12 {

0 commit comments

Comments
 (0)