Skip to content

Commit 0bc4aa9

Browse files
Correctly fail back blinded HTLCs on initial forwarding check fail
1 parent 3ccdf2f commit 0bc4aa9

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
@@ -689,3 +689,115 @@ fn fail_blinded_payment() {
689689
_ => panic!("Unexpected event"),
690690
}
691691
}
692+
693+
#[test]
694+
fn outbound_checks_failure() {
695+
do_outbound_checks_failure(true);
696+
do_outbound_checks_failure(false);
697+
}
698+
699+
fn do_outbound_checks_failure(intro_node_fails: bool) {
700+
// Ensure we'll fail backwards properly if a forwarding check fails on initial update_add
701+
// receipt.
702+
let chanmon_cfgs = create_chanmon_cfgs(4);
703+
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
704+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
705+
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
706+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
707+
let chan_upd_1_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0).0.contents;
708+
let chan_upd_2_3 = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0).0.contents;
709+
710+
let amt_msat = 5000;
711+
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None);
712+
let intermediate_nodes = vec![(nodes[1].node.get_our_node_id(), ForwardTlvs {
713+
short_channel_id: chan_upd_1_2.short_channel_id,
714+
payment_relay: PaymentRelay {
715+
cltv_expiry_delta: chan_upd_1_2.cltv_expiry_delta,
716+
fee_proportional_millionths: chan_upd_1_2.fee_proportional_millionths,
717+
fee_base_msat: chan_upd_1_2.fee_base_msat,
718+
},
719+
payment_constraints: PaymentConstraints {
720+
max_cltv_expiry: u32::max_value(),
721+
htlc_minimum_msat: chan_upd_1_2.htlc_minimum_msat,
722+
},
723+
features: BlindedHopFeatures::empty(),
724+
}), (nodes[2].node.get_our_node_id(), ForwardTlvs {
725+
short_channel_id: chan_upd_2_3.short_channel_id,
726+
payment_relay: PaymentRelay {
727+
cltv_expiry_delta: chan_upd_2_3.cltv_expiry_delta,
728+
fee_proportional_millionths: chan_upd_2_3.fee_proportional_millionths,
729+
fee_base_msat: chan_upd_2_3.fee_base_msat,
730+
},
731+
payment_constraints: PaymentConstraints {
732+
max_cltv_expiry: u32::max_value(),
733+
htlc_minimum_msat: chan_upd_2_3.htlc_minimum_msat,
734+
},
735+
features: BlindedHopFeatures::empty(),
736+
})];
737+
let payee_tlvs = ReceiveTlvs {
738+
payment_secret,
739+
payment_constraints: PaymentConstraints {
740+
max_cltv_expiry: u32::max_value(),
741+
htlc_minimum_msat: chan_upd_2_3.htlc_minimum_msat,
742+
},
743+
};
744+
let mut secp_ctx = Secp256k1::new();
745+
let blinded_path = BlindedPath::new_for_payment(
746+
&intermediate_nodes[..], nodes[3].node.get_our_node_id(), payee_tlvs,
747+
chan_upd_2_3.htlc_maximum_msat, &chanmon_cfgs[3].keys_manager, &secp_ctx
748+
).unwrap();
749+
750+
let route_params = RouteParameters {
751+
payment_params: PaymentParameters::blinded(vec![blinded_path]),
752+
final_value_msat: amt_msat
753+
};
754+
nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(),
755+
PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap();
756+
check_added_monitors(&nodes[0], 1);
757+
758+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
759+
assert_eq!(events.len(), 1);
760+
let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
761+
let payment_event = SendEvent::from_event(ev);
762+
763+
if intro_node_fails {
764+
// The intro node will see that the next-hop peer is disconnected and fail the HTLC backwards.
765+
nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id());
766+
}
767+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
768+
check_added_monitors!(nodes[1], 0);
769+
do_commitment_signed_dance(&nodes[1], &nodes[0], &payment_event.commitment_msg, true, true);
770+
771+
if intro_node_fails {
772+
let mut updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
773+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
774+
do_commitment_signed_dance(&nodes[0], &nodes[1], &updates.commitment_signed, false, false);
775+
expect_payment_failed_conditions(&nodes[0], payment_hash, false,
776+
PaymentFailedConditions::new().expected_htlc_error_data(INVALID_ONION_BLINDING, &[0; 32]));
777+
return
778+
}
779+
780+
expect_pending_htlcs_forwardable!(nodes[1]);
781+
check_added_monitors!(nodes[1], 1);
782+
let mut events = nodes[1].node.get_and_clear_pending_msg_events();
783+
assert_eq!(events.len(), 1);
784+
let ev = remove_first_msg_event_to_node(&nodes[2].node.get_our_node_id(), &mut events);
785+
let payment_event = SendEvent::from_event(ev);
786+
787+
nodes[2].node.peer_disconnected(&nodes[3].node.get_our_node_id());
788+
nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]);
789+
check_added_monitors!(nodes[2], 0);
790+
do_commitment_signed_dance(&nodes[2], &nodes[1], &payment_event.commitment_msg, true, true);
791+
792+
let mut updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
793+
assert_eq!(updates.update_fail_malformed_htlcs[0].failure_code, INVALID_ONION_BLINDING);
794+
assert_eq!(updates.update_fail_malformed_htlcs[0].sha256_of_onion, [0; 32]);
795+
nodes[1].node.handle_update_fail_malformed_htlc(&nodes[2].node.get_our_node_id(), &updates.update_fail_malformed_htlcs[0]);
796+
do_commitment_signed_dance(&nodes[1], &nodes[2], &updates.commitment_signed, true, false);
797+
798+
let mut updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
799+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
800+
do_commitment_signed_dance(&nodes[0], &nodes[1], &updates.commitment_signed, false, false);
801+
expect_payment_failed_conditions(&nodes[0], payment_hash, false,
802+
PaymentFailedConditions::new().expected_htlc_error_data(INVALID_ONION_BLINDING, &[0; 32]));
803+
}

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 {
@@ -3043,7 +3045,7 @@ where
30433045
}
30443046
let next_packet_pk = onion_utils::next_hop_pubkey(&self.secp_ctx,
30453047
msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
3046-
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk))
3048+
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk), true)
30473049
},
30483050
// We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
30493051
// inbound channel's state.
@@ -3167,6 +3169,7 @@ where
31673169
break None;
31683170
}
31693171
{
3172+
if blinded { return_blinded_htlc_err!(err); }
31703173
let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 2 + 8 + 2));
31713174
if let Some(chan_update) = chan_update {
31723175
if code == 0x1000 | 11 || code == 0x1000 | 12 {

0 commit comments

Comments
 (0)