Skip to content

Commit 33a2e6e

Browse files
committed
ln/test: add tests for mpp accumulation of trampoline forwards
1 parent 7fce959 commit 33a2e6e

5 files changed

Lines changed: 275 additions & 56 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/channelmanager.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ enum OnionPayload {
527527
}
528528

529529
#[derive(PartialEq, Eq)]
530-
struct MppPart {
530+
pub(super) struct MppPart {
531531
prev_hop: HTLCPreviousHopData,
532532
cltv_expiry: u32,
533533
/// The amount (in msats) of this MPP part
@@ -542,6 +542,20 @@ struct MppPart {
542542
}
543543

544544
impl MppPart {
545+
#[cfg(test)]
546+
pub(super) fn new(
547+
prev_hop: HTLCPreviousHopData, value: u64, sender_intended_value: u64, cltv_expiry: u32,
548+
) -> Self {
549+
MppPart {
550+
prev_hop,
551+
cltv_expiry,
552+
value,
553+
sender_intended_value,
554+
timer_ticks: 0,
555+
total_value_received: None,
556+
}
557+
}
558+
545559
/// Returns a boolean indicating whether the HTLC has timed out on chain, accounting for a buffer
546560
/// that gives us time to resolve it.
547561
fn check_onchain_timeout(&self, height: u32) -> bool {
@@ -5780,6 +5794,20 @@ impl<
57805794
self.pending_outbound_payments.test_set_payment_metadata(payment_id, new_payment_metadata);
57815795
}
57825796

5797+
#[cfg(test)]
5798+
pub(super) fn test_handle_trampoline_htlc(
5799+
&self, mpp_part: MppPart, onion_fields: RecipientOnionFields, payment_hash: PaymentHash,
5800+
next_hop_info: NextTrampolineHopInfo, next_node_id: PublicKey,
5801+
) -> Result<(), (HTLCSource, onion_utils::HTLCFailReason)> {
5802+
self.handle_trampoline_htlc(
5803+
mpp_part,
5804+
onion_fields,
5805+
payment_hash,
5806+
next_hop_info,
5807+
next_node_id,
5808+
)
5809+
}
5810+
57835811
/// Pays a [`Bolt11Invoice`] associated with the `payment_id`. See [`Self::send_payment`] for more info.
57845812
///
57855813
/// # Payment Id

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
}

lightning/src/ln/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ mod reorg_tests;
118118
mod shutdown_tests;
119119
#[cfg(any(feature = "_test_utils", test))]
120120
pub mod splicing_tests;
121+
#[cfg(test)]
122+
mod trampoline_forward_tests;
121123
#[cfg(any(test, feature = "_externalize_tests"))]
122124
#[allow(unused_mut)]
123125
pub mod update_fee_tests;

0 commit comments

Comments
 (0)