Skip to content

Commit e48b8f8

Browse files
committed
f: dispatch trampoline MPP via public send_payment_with_route
Review comment from valentinewallace on lightning/src/ln/blinded_payment_tests.rs:2861: > Generally preferred to use the public API in tests. I clauded this > patch but haven't vetted it much, let me know your thoughts: > valentinewallace@79a0771 Adopt the patch's core idea: * Extend `create_trampoline_forward_blinded_tail` to also return the underlying `BlindedPaymentPath` so callers can register it in `PaymentParameters`. Update the existing single-path caller to use `.0` on the new tuple. * Build `PaymentParameters::blinded(vec![path_bob, path_barry])` from the two paths and dispatch the MPP via `send_payment_with_route` instead of `test_add_new_pending_payment` + `test_send_payment_along_path`. The registered blinded paths are required, not decorative: `insert_previously_failed_blinded_path` (outbound_payment.rs:2508) is invoked on the trampoline rejection / timeout failures this test exercises, and `debug_assert!`s that the failing tail is registered in payment_params. Also bump Carol's outer-hop `cltv_expiry_delta` from `trampoline_cltv + excess_final_cltv` (112) to `carol_relay.cltv_ expiry_delta + trampoline_cltv + excess_final_cltv` (184). Required by `FixedRouter` (router.rs:765-773), which validates that the last outer- hop's `cltv_expiry_delta` equals `sum(trampoline_hops[*].cltv_expiry_ delta)`. That sum is `blinded_path.payinfo.cltv_expiry_delta + excess_final_cltv_delta`, and the payinfo aggregates the intermediate trampoline relay's `cltv_expiry_delta` (= `carol_relay.cltv_expiry_ delta` from `fwd_tail`) plus `min_final_cltv_expiry_delta` (= `trampoline_cltv`). The `test_send_payment_along_path` helpers bypassed this validation, so 112 worked there; the public API does not. Reverting to 112 panics with "Path had a total trampoline CLTV of 184, which is not equal to the total last-hop CLTV delta of 112". Comment the derivation at the call site so the overloaded "relay" naming doesn't trip up future readers. Return `last_hop_cltv_delta` from `send_trampoline_mpp_payment` so the on-chain timeout branch can compute Carol's incoming HTLC CLTV from the same value the route is built with, rather than re-stating the magic constant 184 in two places.
1 parent 5ba7094 commit e48b8f8

2 files changed

Lines changed: 51 additions & 55 deletions

File tree

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 43 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,24 +2597,27 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
25972597
// Create a blinded tail where Carol is receiving. In our unblinded test cases, we'll
25982598
// override this anyway (with a tail sending to an unblinded receive, which LDK doesn't
25992599
// allow).
2600-
blinded_tail: Some(create_trampoline_forward_blinded_tail(
2601-
&secp_ctx,
2602-
&nodes[2].keys_manager,
2603-
&[],
2604-
carol_node_id,
2605-
nodes[2].keys_manager.get_receive_auth_key(),
2606-
ReceiveTlvs {
2607-
payment_secret,
2608-
payment_constraints: PaymentConstraints {
2609-
max_cltv_expiry: u32::max_value(),
2610-
htlc_minimum_msat: original_amt_msat,
2600+
blinded_tail: Some(
2601+
create_trampoline_forward_blinded_tail(
2602+
&secp_ctx,
2603+
&nodes[2].keys_manager,
2604+
&[],
2605+
carol_node_id,
2606+
nodes[2].keys_manager.get_receive_auth_key(),
2607+
ReceiveTlvs {
2608+
payment_secret,
2609+
payment_constraints: PaymentConstraints {
2610+
max_cltv_expiry: u32::max_value(),
2611+
htlc_minimum_msat: original_amt_msat,
2612+
},
2613+
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
26112614
},
2612-
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
2613-
},
2614-
original_trampoline_cltv,
2615-
excess_final_cltv,
2616-
original_amt_msat,
2617-
)),
2615+
original_trampoline_cltv,
2616+
excess_final_cltv,
2617+
original_amt_msat,
2618+
)
2619+
.0,
2620+
),
26182621
}],
26192622
route_params: None,
26202623
};
@@ -2736,10 +2739,10 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
27362739
/// next hop as a real node since forwarding isn't implemented yet -- we just need the onion to
27372740
/// contain a valid forward payload.
27382741
///
2739-
/// Returns (payment_hash, per_path_amount, ev_to_bob, ev_to_barry).
2742+
/// Returns (payment_hash, per_path_amount, last_hop_cltv_delta, ev_to_bob, ev_to_barry).
27402743
fn send_trampoline_mpp_payment<'a, 'b, 'c>(
27412744
nodes: &'a Vec<Node<'a, 'b, 'c>>,
2742-
) -> (PaymentHash, u64, MessageSendEvent, MessageSendEvent) {
2745+
) -> (PaymentHash, u64, u32, MessageSendEvent, MessageSendEvent) {
27432746
let secp_ctx = Secp256k1::new();
27442747

27452748
let alice_bob_chan =
@@ -2822,60 +2825,47 @@ fn send_trampoline_mpp_payment<'a, 'b, 'c>(
28222825
cltv_expiry_delta,
28232826
maybe_announced_channel: true,
28242827
};
2828+
let last_hop_cltv_delta =
2829+
carol_relay.cltv_expiry_delta as u32 + trampoline_cltv + excess_final_cltv;
28252830
let build_path_hops = |first_hop_node_id, first_hop_scid, second_hop_scid| {
28262831
vec![
28272832
hop(first_hop_node_id, first_hop_scid, 1000, 48),
2828-
hop(carol_node_id, second_hop_scid, 0, trampoline_cltv + excess_final_cltv),
2833+
hop(carol_node_id, second_hop_scid, 0, last_hop_cltv_delta),
28292834
]
28302835
};
28312836

2832-
let placeholder_tail = fwd_tail();
2833-
let mut route = Route {
2837+
let (tail_bob, blinded_path_bob) = fwd_tail();
2838+
let (tail_barry, blinded_path_barry) = fwd_tail();
2839+
let payment_params = PaymentParameters::blinded(vec![blinded_path_bob, blinded_path_barry]);
2840+
let route_params = RouteParameters {
2841+
payment_params,
2842+
final_value_msat: total_amt,
2843+
max_total_routing_fee_msat: None,
2844+
};
2845+
let route = Route {
28342846
paths: vec![
28352847
Path {
28362848
hops: build_path_hops(bob_node_id, alice_bob_scid, bob_carol_scid),
2837-
blinded_tail: Some(placeholder_tail.clone()),
2849+
blinded_tail: Some(tail_bob),
28382850
},
28392851
Path {
28402852
hops: build_path_hops(barry_node_id, alice_barry_scid, barry_carol_scid),
2841-
blinded_tail: Some(placeholder_tail),
2853+
blinded_tail: Some(tail_barry),
28422854
},
28432855
],
2844-
route_params: None,
2856+
route_params: Some(route_params),
28452857
};
28462858

2847-
let cur_height = nodes[0].best_block_info().1 + 1;
28482859
let payment_id = PaymentId(payment_hash.0);
28492860
let onion = RecipientOnionFields::secret_only(payment_secret, total_amt);
2850-
let session_privs = nodes[0]
2851-
.node
2852-
.test_add_new_pending_payment(payment_hash, onion.clone(), payment_id, &route)
2853-
.unwrap();
2854-
2855-
route.paths[0].blinded_tail = Some(fwd_tail());
2856-
route.paths[1].blinded_tail = Some(fwd_tail());
2857-
2858-
for (i, path) in route.paths.iter().enumerate() {
2859-
nodes[0]
2860-
.node
2861-
.test_send_payment_along_path(
2862-
path,
2863-
&payment_hash,
2864-
onion.clone(),
2865-
cur_height,
2866-
payment_id,
2867-
&None,
2868-
session_privs[i],
2869-
)
2870-
.unwrap();
2871-
check_added_monitors(&nodes[0], 1);
2872-
}
2861+
nodes[0].node.send_payment_with_route(route, payment_hash, onion, payment_id).unwrap();
2862+
check_added_monitors(&nodes[0], 2);
28732863

28742864
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
28752865
assert_eq!(events.len(), 2);
28762866
let ev_bob = remove_first_msg_event_to_node(&bob_node_id, &mut events);
28772867
let ev_barry = remove_first_msg_event_to_node(&barry_node_id, &mut events);
2878-
(payment_hash, per_path_amt, ev_bob, ev_barry)
2868+
(payment_hash, per_path_amt, last_hop_cltv_delta, ev_bob, ev_barry)
28792869
}
28802870

28812871
/// How an incomplete trampoline MPP times out (if at all).
@@ -2892,7 +2882,8 @@ fn do_trampoline_mpp_test(timeout: Option<TrampolineTimeout>) {
28922882
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &vec![None; 4]);
28932883
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
28942884

2895-
let (payment_hash, per_path_amt, ev_bob, ev_barry) = send_trampoline_mpp_payment(&nodes);
2885+
let (payment_hash, per_path_amt, last_hop_cltv_delta, ev_bob, ev_barry) =
2886+
send_trampoline_mpp_payment(&nodes);
28962887
let send_both = timeout.is_none();
28972888

28982889
let bob_path: &[&Node] = &[&nodes[1], &nodes[2]];
@@ -2921,7 +2912,7 @@ fn do_trampoline_mpp_test(timeout: Option<TrampolineTimeout>) {
29212912
Some(TrampolineTimeout::OnChain) => {
29222913
let current_height = nodes[2].best_block_info().1;
29232914
let send_height = nodes[0].best_block_info().1;
2924-
let htlc_cltv = send_height + 1 + 48 + 42 + 70;
2915+
let htlc_cltv = send_height + 1 + last_hop_cltv_delta;
29252916
connect_blocks(&nodes[2], htlc_cltv - HTLC_FAIL_BACK_BUFFER - current_height);
29262917
LocalHTLCFailureReason::CLTVExpiryTooSoon
29272918
},

lightning/src/ln/functional_test_utils.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5776,12 +5776,16 @@ pub fn get_scid_from_channel_id<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, channel_id:
57765776
///
57775777
/// The resulting tail contains blinded hops built from `intermediate_nodes` plus a dummy receive
57785778
/// TLV, with the `TrampolineHop` fee and CLTV derived from the blinded path's aggregated payinfo.
5779+
/// The constructed [`BlindedPaymentPath`] is also returned so callers can register it in
5780+
/// [`PaymentParameters`].
5781+
///
5782+
/// [`PaymentParameters`]: crate::routing::router::PaymentParameters
57795783
pub fn create_trampoline_forward_blinded_tail<ES: EntropySource>(
57805784
secp_ctx: &bitcoin::secp256k1::Secp256k1<bitcoin::secp256k1::All>, entropy_source: ES,
57815785
intermediate_nodes: &[ForwardNode<TrampolineForwardTlvs>], payee_node_id: PublicKey,
57825786
payee_receive_key: ReceiveAuthKey, payee_tlvs: ReceiveTlvs, min_final_cltv_expiry_delta: u32,
57835787
excess_final_cltv_delta: u32, final_value_msat: u64,
5784-
) -> BlindedTail {
5788+
) -> (BlindedTail, BlindedPaymentPath) {
57855789
let blinded_path = BlindedPaymentPath::new_for_trampoline(
57865790
intermediate_nodes,
57875791
payee_node_id,
@@ -5794,7 +5798,7 @@ pub fn create_trampoline_forward_blinded_tail<ES: EntropySource>(
57945798
)
57955799
.unwrap();
57965800

5797-
BlindedTail {
5801+
let tail = BlindedTail {
57985802
trampoline_hops: vec![TrampolineHop {
57995803
pubkey: intermediate_nodes.first().map(|n| n.node_id).unwrap_or(payee_node_id),
58005804
node_features: types::features::Features::empty(),
@@ -5813,5 +5817,6 @@ pub fn create_trampoline_forward_blinded_tail<ES: EntropySource>(
58135817
blinding_point: blinded_path.blinding_point(),
58145818
excess_final_cltv_expiry_delta: excess_final_cltv_delta,
58155819
final_value_msat,
5816-
}
5820+
};
5821+
(tail, blinded_path)
58175822
}

0 commit comments

Comments
 (0)