Skip to content

Commit a36ef3d

Browse files
committed
f: test more forwarding failure scenarios
1 parent bba7da7 commit a36ef3d

File tree

1 file changed

+190
-46
lines changed

1 file changed

+190
-46
lines changed

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 190 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// You may not use this file except in accordance with one or both of these
88
// licenses.
99

10+
use std::cmp::PartialEq;
1011
use bitcoin::hashes::hex::FromHex;
1112
use bitcoin::hex::DisplayHex;
1213
use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, schnorr};
@@ -2497,7 +2498,14 @@ fn test_trampoline_constraint_enforcement() {
24972498
}
24982499
}
24992500

2500-
fn do_test_unblinded_trampoline_forward(success: bool) {
2501+
#[derive(PartialEq)]
2502+
enum TrampolineForwardFailureScenario {
2503+
NoRoute,
2504+
InvalidRecipientOnion,
2505+
InvalidInterTrampolineOnion,
2506+
}
2507+
2508+
fn do_test_unblinded_trampoline_forward(failure_scenario: Option<TrampolineForwardFailureScenario>) {
25012509
// Simulate a payment of A (0) -> B (1) -> C(Trampoline) (2) -> D(Trampoline(receive)) (3)
25022510
// trampoline hops C -> T0 (4) -> D
25032511
// make it fail at B, then at C's outer onion, then at C's inner onion
@@ -2511,7 +2519,7 @@ fn do_test_unblinded_trampoline_forward(success: bool) {
25112519

25122520
let (_, _, chan_id_alice_bob, _) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
25132521
let (_, _, chan_id_bob_carol, _) = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0);
2514-
if success {
2522+
if failure_scenario != Some(TrampolineForwardFailureScenario::NoRoute) {
25152523
let (_, _, _, _) = create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 1_000_000, 0);
25162524
}
25172525
let (_, _, _, _) = create_announced_chan_between_nodes_with_value(&nodes, 4, 3, 1_000_000, 0);
@@ -2641,59 +2649,195 @@ fn do_test_unblinded_trampoline_forward(success: bool) {
26412649
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
26422650
assert_eq!(events.len(), 1);
26432651
let mut first_message_event = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
2644-
let mut update_message = match first_message_event {
2645-
MessageSendEvent::UpdateHTLCs { ref mut updates, .. } => {
2646-
assert_eq!(updates.update_add_htlcs.len(), 1);
2647-
updates.update_add_htlcs.get_mut(0)
2648-
},
2649-
_ => panic!()
2650-
};
2651-
update_message.map(|msg| {
2652-
msg.onion_routing_packet = replacement_onion.clone();
2653-
});
2654-
2655-
let success_route = [&nodes[1], &nodes[2], &nodes[4], &nodes[3]];
2656-
let failure_route = [&nodes[1], &nodes[2]];
2657-
let route: &[&Node] = if success { &success_route } else { &failure_route };
2658-
let args = PassAlongPathArgs::new(&nodes[0], route, amt_msat, payment_hash, first_message_event);
2659-
let args = if success {
2660-
args.with_payment_secret(payment_secret)
2661-
} else {
2662-
args.with_payment_preimage(payment_preimage)
2663-
.without_claimable_event()
2664-
.expect_failure(HTLCDestination::FailedTrampolineForward { requested_next_node_id: dave_node_id, forward_scid: None })
2665-
};
2666-
do_pass_along_path(args);
2652+
{
2653+
let mut update_message_alice_bob = match first_message_event {
2654+
MessageSendEvent::UpdateHTLCs { ref mut updates, .. } => {
2655+
assert_eq!(updates.update_add_htlcs.len(), 1);
2656+
updates.update_add_htlcs.get_mut(0)
2657+
}
2658+
_ => panic!()
2659+
};
2660+
update_message_alice_bob.map(|msg| {
2661+
msg.onion_routing_packet = replacement_onion.clone();
2662+
});
2663+
}
26672664

2668-
if success {
2669-
claim_payment(&nodes[0], &[&nodes[1], &nodes[2], &nodes[4], &nodes[3]], payment_preimage);
2670-
} else {
2671-
{
2672-
let unblinded_node_updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
2673-
nodes[1].node.handle_update_fail_htlc(
2674-
nodes[2].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
2675-
);
2676-
do_commitment_signed_dance(&nodes[1], &nodes[2], &unblinded_node_updates.commitment_signed, true, false);
2665+
match failure_scenario {
2666+
None => {
2667+
let route: &[&Node] = &[&nodes[1], &nodes[2], &nodes[4], &nodes[3]];
2668+
let args = PassAlongPathArgs::new(&nodes[0], route, amt_msat, payment_hash, first_message_event)
2669+
.with_payment_secret(payment_secret);
2670+
do_pass_along_path(args);
2671+
claim_payment(&nodes[0], &[&nodes[1], &nodes[2], &nodes[4], &nodes[3]], payment_preimage);
26772672
}
2678-
{
2679-
let unblinded_node_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
2680-
nodes[0].node.handle_update_fail_htlc(
2681-
nodes[1].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
2682-
);
2683-
do_commitment_signed_dance(&nodes[0], &nodes[1], &unblinded_node_updates.commitment_signed, false, false);
2673+
Some(TrampolineForwardFailureScenario::NoRoute) => {
2674+
let route = &[&nodes[1], &nodes[2]];
2675+
let args = PassAlongPathArgs::new(&nodes[0], route, amt_msat, payment_hash, first_message_event)
2676+
.with_payment_preimage(payment_preimage)
2677+
.without_claimable_event()
2678+
.expect_failure(HTLCDestination::FailedTrampolineForward { requested_next_node_id: dave_node_id, forward_scid: None });
2679+
do_pass_along_path(args);
2680+
2681+
{
2682+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
2683+
nodes[1].node.handle_update_fail_htlc(
2684+
nodes[2].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0],
2685+
);
2686+
do_commitment_signed_dance(&nodes[1], &nodes[2], &unblinded_node_updates.commitment_signed, true, false);
2687+
}
2688+
{
2689+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
2690+
nodes[0].node.handle_update_fail_htlc(
2691+
nodes[1].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0],
2692+
);
2693+
do_commitment_signed_dance(&nodes[0], &nodes[1], &unblinded_node_updates.commitment_signed, false, false);
2694+
}
2695+
{
2696+
let payment_failed_conditions = PaymentFailedConditions::new()
2697+
.expected_htlc_error_data(0x2000 | 25, &[0; 0]);
2698+
expect_payment_failed_conditions(&nodes[0], payment_hash, false, payment_failed_conditions);
2699+
}
26842700
}
2685-
{
2686-
let payment_failed_conditions = PaymentFailedConditions::new()
2687-
.expected_htlc_error_data(0x2000 | 25, &[0; 0]);
2688-
expect_payment_failed_conditions(&nodes[0], payment_hash, false, payment_failed_conditions);
2701+
Some(TrampolineForwardFailureScenario::InvalidRecipientOnion) => {
2702+
let route_alice_t0: &[&Node] = &[&nodes[1], &nodes[2], &nodes[4]];
2703+
pass_along_path(&nodes[0], route_alice_t0, amt_msat, payment_hash.clone(),
2704+
None, first_message_event.clone(), false, Some(payment_preimage));
2705+
2706+
check_added_monitors!(&nodes[4], 1);
2707+
let mut events = nodes[4].node.get_and_clear_pending_msg_events();
2708+
assert_eq!(events.len(), 1);
2709+
2710+
let mut update_message_t0_dave = remove_first_msg_event_to_node(&nodes[3].node.get_our_node_id(), &mut events);
2711+
{
2712+
let mut update_message = match update_message_t0_dave {
2713+
MessageSendEvent::UpdateHTLCs { ref mut updates, .. } => {
2714+
assert_eq!(updates.update_add_htlcs.len(), 1);
2715+
updates.update_add_htlcs.get_mut(0)
2716+
}
2717+
_ => panic!()
2718+
};
2719+
update_message.map(|msg| {
2720+
// corrupt the onion packet
2721+
msg.onion_routing_packet.hmac = [1; 32];
2722+
});
2723+
}
2724+
2725+
let route_to_dave: &[&Node] = &[&nodes[3]];
2726+
let args = PassAlongPathArgs::new(&nodes[4], route_to_dave, amt_msat, payment_hash, update_message_t0_dave.clone()).expect_failure(HTLCDestination::InvalidOnion);
2727+
do_pass_along_path(args);
2728+
2729+
{
2730+
let downstream_id = 3;
2731+
let upstream_id = 4;
2732+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[downstream_id], nodes[upstream_id].node.get_our_node_id());
2733+
nodes[upstream_id].node.handle_update_fail_malformed_htlc(
2734+
nodes[downstream_id].node.get_our_node_id(), &unblinded_node_updates.update_fail_malformed_htlcs[0]
2735+
);
2736+
do_commitment_signed_dance(&nodes[upstream_id], &nodes[downstream_id], &unblinded_node_updates.commitment_signed, true, false);
2737+
}
2738+
{
2739+
let downstream_id = 4;
2740+
let upstream_id = 2;
2741+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[downstream_id], nodes[upstream_id].node.get_our_node_id());
2742+
nodes[upstream_id].node.handle_update_fail_htlc(
2743+
nodes[downstream_id].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
2744+
);
2745+
do_commitment_signed_dance(&nodes[upstream_id], &nodes[downstream_id], &unblinded_node_updates.commitment_signed, true, false);
2746+
}
2747+
{
2748+
let downstream_id = 2;
2749+
let upstream_id = 1;
2750+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[downstream_id], nodes[upstream_id].node.get_our_node_id());
2751+
nodes[upstream_id].node.handle_update_fail_htlc(
2752+
nodes[downstream_id].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
2753+
);
2754+
do_commitment_signed_dance(&nodes[upstream_id], &nodes[downstream_id], &unblinded_node_updates.commitment_signed, true, false);
2755+
}
2756+
{
2757+
let downstream_id = 1;
2758+
let upstream_id = 0;
2759+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[downstream_id], nodes[upstream_id].node.get_our_node_id());
2760+
nodes[upstream_id].node.handle_update_fail_htlc(
2761+
nodes[downstream_id].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
2762+
);
2763+
do_commitment_signed_dance(&nodes[upstream_id], &nodes[downstream_id], &unblinded_node_updates.commitment_signed, false, false);
2764+
}
2765+
{
2766+
let payment_failed_conditions = PaymentFailedConditions::new()
2767+
.expected_htlc_error_data(0x2000 | 25, &[0; 0]);
2768+
expect_payment_failed_conditions(&nodes[0], payment_hash, false, payment_failed_conditions);
2769+
}
2770+
}
2771+
Some(TrampolineForwardFailureScenario::InvalidInterTrampolineOnion) => {
2772+
let route_alice_carol: &[&Node] = &[&nodes[1], &nodes[2]];
2773+
pass_along_path(&nodes[0], route_alice_carol, amt_msat, payment_hash.clone(),
2774+
None, first_message_event.clone(), false, Some(payment_preimage));
2775+
2776+
check_added_monitors!(&nodes[2], 1);
2777+
let mut events = nodes[2].node.get_and_clear_pending_msg_events();
2778+
assert_eq!(events.len(), 1);
2779+
2780+
let mut update_message_carol_t0 = remove_first_msg_event_to_node(&nodes[4].node.get_our_node_id(), &mut events);
2781+
{
2782+
let mut update_message = match update_message_carol_t0 {
2783+
MessageSendEvent::UpdateHTLCs { ref mut updates, .. } => {
2784+
assert_eq!(updates.update_add_htlcs.len(), 1);
2785+
updates.update_add_htlcs.get_mut(0)
2786+
}
2787+
_ => panic!()
2788+
};
2789+
update_message.map(|msg| {
2790+
// corrupt the onion packet
2791+
msg.onion_routing_packet.hmac = [1; 32];
2792+
});
2793+
}
2794+
2795+
let route_carol_t0: &[&Node] = &[&nodes[4]];
2796+
let args = PassAlongPathArgs::new(&nodes[2], route_carol_t0, amt_msat, payment_hash, update_message_carol_t0.clone()).expect_failure(HTLCDestination::InvalidOnion);
2797+
do_pass_along_path(args);
2798+
2799+
{
2800+
let downstream_id = 4;
2801+
let upstream_id = 2;
2802+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[downstream_id], nodes[upstream_id].node.get_our_node_id());
2803+
nodes[upstream_id].node.handle_update_fail_malformed_htlc(
2804+
nodes[downstream_id].node.get_our_node_id(), &unblinded_node_updates.update_fail_malformed_htlcs[0]
2805+
);
2806+
do_commitment_signed_dance(&nodes[upstream_id], &nodes[downstream_id], &unblinded_node_updates.commitment_signed, true, false);
2807+
}
2808+
{
2809+
let downstream_id = 2;
2810+
let upstream_id = 1;
2811+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[downstream_id], nodes[upstream_id].node.get_our_node_id());
2812+
nodes[upstream_id].node.handle_update_fail_htlc(
2813+
nodes[downstream_id].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
2814+
);
2815+
do_commitment_signed_dance(&nodes[upstream_id], &nodes[downstream_id], &unblinded_node_updates.commitment_signed, true, false);
2816+
}
2817+
{
2818+
let downstream_id = 1;
2819+
let upstream_id = 0;
2820+
let unblinded_node_updates = get_htlc_update_msgs!(nodes[downstream_id], nodes[upstream_id].node.get_our_node_id());
2821+
nodes[upstream_id].node.handle_update_fail_htlc(
2822+
nodes[downstream_id].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
2823+
);
2824+
do_commitment_signed_dance(&nodes[upstream_id], &nodes[downstream_id], &unblinded_node_updates.commitment_signed, false, false);
2825+
}
2826+
{
2827+
let payment_failed_conditions = PaymentFailedConditions::new()
2828+
.expected_htlc_error_data(0x2000 | 25, &[0; 0]);
2829+
expect_payment_failed_conditions(&nodes[0], payment_hash, false, payment_failed_conditions);
2830+
}
26892831
}
26902832
}
26912833
}
26922834

26932835
#[test]
26942836
fn test_unblinded_trampoline_forward() {
2695-
do_test_unblinded_trampoline_forward(true);
2696-
do_test_unblinded_trampoline_forward(false);
2837+
do_test_unblinded_trampoline_forward(None);
2838+
do_test_unblinded_trampoline_forward(Some(TrampolineForwardFailureScenario::NoRoute));
2839+
do_test_unblinded_trampoline_forward(Some(TrampolineForwardFailureScenario::InvalidInterTrampolineOnion));
2840+
do_test_unblinded_trampoline_forward(Some(TrampolineForwardFailureScenario::InvalidRecipientOnion));
26972841
}
26982842

26992843
#[test]

0 commit comments

Comments
 (0)