Skip to content

Commit e0a2a9f

Browse files
committed
f: test blinded forward success
1 parent dae8f2c commit e0a2a9f

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

lightning/src/ln/blinded_payment_tests.rs

+121
Original file line numberDiff line numberDiff line change
@@ -2695,3 +2695,124 @@ fn test_unblinded_trampoline_forward() {
26952695
do_test_unblinded_trampoline_forward(true);
26962696
do_test_unblinded_trampoline_forward(false);
26972697
}
2698+
2699+
#[test]
2700+
fn test_blinded_trampoline_forward() {
2701+
// Simulate a payment of A (0) -> B (1) -> C(Trampoline (blinded forward)) (2) -> D(Trampoline(blinded receive)) (3)
2702+
// trampoline hops C -> T0 (4) -> D
2703+
// make it fail at B, then at C's outer onion, then at C's inner onion
2704+
const TOTAL_NODE_COUNT: usize = 5;
2705+
let secp_ctx = Secp256k1::new();
2706+
2707+
let chanmon_cfgs = create_chanmon_cfgs(TOTAL_NODE_COUNT);
2708+
let node_cfgs = create_node_cfgs(TOTAL_NODE_COUNT, &chanmon_cfgs);
2709+
let node_chanmgrs = create_node_chanmgrs(TOTAL_NODE_COUNT, &node_cfgs, &vec![None; TOTAL_NODE_COUNT]);
2710+
let mut nodes = create_network(TOTAL_NODE_COUNT, &node_cfgs, &node_chanmgrs);
2711+
2712+
let (_, _, chan_id_alice_bob, _) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
2713+
let (_, _, chan_id_bob_carol, _) = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0);
2714+
let (_, _, _, _) = create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 1_000_000, 0);
2715+
let (_, _, _, _) = create_announced_chan_between_nodes_with_value(&nodes, 4, 3, 1_000_000, 0);
2716+
2717+
for i in 0..TOTAL_NODE_COUNT { // connect all nodes' blocks
2718+
connect_blocks(&nodes[i], (TOTAL_NODE_COUNT as u32) * CHAN_CONFIRM_DEPTH + 1 - nodes[i].best_block_info().1);
2719+
}
2720+
2721+
let bob_node_id = nodes[1].node().get_our_node_id();
2722+
let carol_node_id = nodes[2].node().get_our_node_id();
2723+
let dave_node_id = nodes[3].node().get_our_node_id();
2724+
2725+
let alice_bob_scid = nodes[0].node().list_channels().iter().find(|c| c.channel_id == chan_id_alice_bob).unwrap().short_channel_id.unwrap();
2726+
let bob_carol_scid = nodes[1].node().list_channels().iter().find(|c| c.channel_id == chan_id_bob_carol).unwrap().short_channel_id.unwrap();
2727+
2728+
let amt_msat = 1000;
2729+
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None);
2730+
2731+
let alice_carol_trampoline_shared_secret = secret_from_hex("a0f4b8d7b6c2d0ffdfaf718f76e9decaef4d9fb38a8c4addb95c4007cc3eee03");
2732+
let carol_blinding_point = PublicKey::from_secret_key(&secp_ctx, &alice_carol_trampoline_shared_secret);
2733+
2734+
let forwarding_tlvs = blinded_path::payment::TrampolineForwardTlvs {
2735+
next_trampoline: dave_node_id,
2736+
payment_relay: PaymentRelay {
2737+
cltv_expiry_delta: 224,
2738+
fee_proportional_millionths: 0,
2739+
fee_base_msat: 2000,
2740+
},
2741+
payment_constraints: PaymentConstraints {
2742+
max_cltv_expiry: u32::max_value(),
2743+
htlc_minimum_msat: amt_msat
2744+
},
2745+
features: BlindedHopFeatures::empty(),
2746+
next_blinding_override: None,
2747+
};
2748+
let carol_unblinded_tlvs = forwarding_tlvs.encode();
2749+
2750+
let payee_tlvs = UnauthenticatedReceiveTlvs {
2751+
payment_secret,
2752+
payment_constraints: PaymentConstraints {
2753+
max_cltv_expiry: u32::max_value(),
2754+
htlc_minimum_msat: amt_msat,
2755+
},
2756+
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
2757+
};
2758+
2759+
let nonce = Nonce([42u8; 16]);
2760+
let expanded_key = nodes[3].keys_manager.get_inbound_payment_key();
2761+
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
2762+
let dave_unblinded_tlvs = payee_tlvs.encode();
2763+
2764+
let path = [(carol_node_id, WithoutLength(&carol_unblinded_tlvs)), (dave_node_id, WithoutLength(&dave_unblinded_tlvs))];
2765+
let blinded_hops = blinded_path::utils::construct_blinded_hops(
2766+
&secp_ctx, path.into_iter(), &alice_carol_trampoline_shared_secret,
2767+
).unwrap();
2768+
2769+
let route = Route {
2770+
paths: vec![Path {
2771+
hops: vec![
2772+
// Bob
2773+
RouteHop {
2774+
pubkey: bob_node_id,
2775+
node_features: NodeFeatures::empty(),
2776+
short_channel_id: alice_bob_scid,
2777+
channel_features: ChannelFeatures::empty(),
2778+
fee_msat: 1000, // forwarding fee to Carol
2779+
cltv_expiry_delta: 48,
2780+
maybe_announced_channel: false,
2781+
},
2782+
2783+
// Carol
2784+
RouteHop {
2785+
pubkey: carol_node_id,
2786+
node_features: NodeFeatures::empty(),
2787+
short_channel_id: bob_carol_scid,
2788+
channel_features: ChannelFeatures::empty(),
2789+
fee_msat: 2000, // fee for the usage of the entire blinded path, including Trampoline
2790+
cltv_expiry_delta: 48,
2791+
maybe_announced_channel: false,
2792+
}
2793+
],
2794+
blinded_tail: Some(BlindedTail {
2795+
trampoline_hops: vec![
2796+
// Carol
2797+
TrampolineHop {
2798+
pubkey: carol_node_id,
2799+
node_features: Features::empty(),
2800+
fee_msat: amt_msat,
2801+
cltv_expiry_delta: 176, // let her cook
2802+
},
2803+
],
2804+
hops: blinded_hops,
2805+
blinding_point: carol_blinding_point,
2806+
excess_final_cltv_expiry_delta: 39,
2807+
final_value_msat: amt_msat,
2808+
})
2809+
}],
2810+
route_params: None,
2811+
};
2812+
2813+
nodes[0].node.send_payment_with_route(route.clone(), payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0)).unwrap();
2814+
check_added_monitors!(&nodes[0], 1);
2815+
2816+
pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2], &nodes[4], &nodes[3]]], amt_msat, payment_hash, payment_secret);
2817+
claim_payment(&nodes[0], &[&nodes[1], &nodes[2], &nodes[4], &nodes[3]], payment_preimage);
2818+
}

0 commit comments

Comments
 (0)