Simplify test_trampoline_single_hop_receive
What changed, and why it matters
This commit only changes a test file. It simplifies an existing unit test for trampoline payments by replacing a complex, manually-built failing onion with a simpler helper that makes the recipient reject the payment. No production code is modified, so there is no security impact on real users.
No action required. This is a test-only refactor with no security relevance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff modifies lightning/src/ln/blinded_payment_tests.rs, specifically do_test_trampoline_single_hop_receive. It removes manual construction of an invalid trampoline onion (using override_random_bytes, compute_trampoline_session_priv, construct_blinded_hops, build_trampoline_onion_payloads, etc.) and replaces both success and failure branches with standard test helpers: pass_along_route, claim_payment, and fail_payment. The commit message explicitly states the removed failure path will be re-added as a dedicated test in the next commit to preserve coverage.
Changed components
lightning/src/ln/blinded_payment_tests.rsInspect captured patch +16 / −128
diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs
index ca7e563..79697f0 100644
--- a/lightning/src/ln/blinded_payment_tests.rs
+++ b/lightning/src/ln/blinded_payment_tests.rs
@@ -1999,7 +1999,6 @@ fn do_test_trampoline_single_hop_receive(success: bool) {
connect_blocks(&nodes[i], (TOTAL_NODE_COUNT as u32) * CHAN_CONFIRM_DEPTH + 1 - nodes[i].best_block_info().1);
}
- let alice_node_id = nodes[0].node().get_our_node_id();
let bob_node_id = nodes[1].node().get_our_node_id();
let carol_node_id = nodes[2].node().get_our_node_id();
@@ -2009,54 +2008,19 @@ fn do_test_trampoline_single_hop_receive(success: bool) {
let amt_msat = 1000;
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None);
- // We need the session priv to compute the trampoline session priv and construct an invalid onion packet later.
- let override_random_bytes = [3; 32];
- *nodes[0].keys_manager.override_random_bytes.lock().unwrap() = Some(override_random_bytes);
-
- let outer_onion_session_priv = SecretKey::from_slice(&override_random_bytes[..]).unwrap();
- let carol_alice_trampoline_session_priv = onion_utils::compute_trampoline_session_priv(&outer_onion_session_priv);
- let carol_blinding_point = PublicKey::from_secret_key(&secp_ctx, &carol_alice_trampoline_session_priv);
- let carol_blinded_hops = if success {
- let payee_tlvs = UnauthenticatedReceiveTlvs {
- payment_secret,
- payment_constraints: PaymentConstraints {
- max_cltv_expiry: u32::max_value(),
- htlc_minimum_msat: amt_msat,
- },
- payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
- };
-
- let nonce = Nonce([42u8; 16]);
- let expanded_key = nodes[2].keys_manager.get_expanded_key();
- let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
- let carol_unblinded_tlvs = payee_tlvs.encode();
-
- let path = [((carol_node_id, None), WithoutLength(&carol_unblinded_tlvs))];
- blinded_path::utils::construct_blinded_hops(
- &secp_ctx, path.into_iter(), &carol_alice_trampoline_session_priv,
- )
- } else {
- let payee_tlvs = blinded_path::payment::TrampolineForwardTlvs {
- next_trampoline: alice_node_id,
- payment_constraints: PaymentConstraints {
- max_cltv_expiry: u32::max_value(),
- htlc_minimum_msat: amt_msat,
- },
- features: BlindedHopFeatures::empty(),
- payment_relay: PaymentRelay {
- cltv_expiry_delta: 0,
- fee_proportional_millionths: 0,
- fee_base_msat: 0,
- },
- next_blinding_override: None,
- };
-
- let carol_unblinded_tlvs = payee_tlvs.encode();
- let path = [((carol_node_id, None), WithoutLength(&carol_unblinded_tlvs))];
- blinded_path::utils::construct_blinded_hops(
- &secp_ctx, path.into_iter(), &carol_alice_trampoline_session_priv,
- )
+ // Create a 1-hop blinded path for Carol.
+ let payee_tlvs = UnauthenticatedReceiveTlvs {
+ payment_secret,
+ payment_constraints: PaymentConstraints {
+ max_cltv_expiry: u32::max_value(),
+ htlc_minimum_msat: amt_msat,
+ },
+ payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
};
+ let nonce = Nonce([42u8; 16]);
+ let expanded_key = nodes[2].keys_manager.get_expanded_key();
+ let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
+ let blinded_path = BlindedPaymentPath::new(&[], carol_node_id, payee_tlvs, u64::MAX, 0, nodes[2].keys_manager, &secp_ctx).unwrap();
let route = Route {
paths: vec![Path {
@@ -2093,8 +2057,8 @@ fn do_test_trampoline_single_hop_receive(success: bool) {
cltv_expiry_delta: 24,
},
],
- hops: carol_blinded_hops,
- blinding_point: carol_blinding_point,
+ hops: blinded_path.blinded_hops().to_vec(),
+ blinding_point: blinded_path.blinding_point(),
excess_final_cltv_expiry_delta: 39,
final_value_msat: amt_msat,
})
@@ -2105,87 +2069,11 @@ fn do_test_trampoline_single_hop_receive(success: bool) {
nodes[0].node.send_payment_with_route(route.clone(), payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0)).unwrap();
check_added_monitors!(&nodes[0], 1);
+ pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], amt_msat, payment_hash, payment_secret);
if success {
- pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], amt_msat, payment_hash, payment_secret);
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
} else {
- let replacement_onion = {
- // create a substitute onion where the last Trampoline hop is a forward
- let recipient_onion_fields = RecipientOnionFields::spontaneous_empty();
- let mut blinded_tail = route.paths[0].blinded_tail.clone().unwrap();
-
- // append some dummy blinded hop so the intro hop looks like a forward
- blinded_tail.hops.push(BlindedHop {
- blinded_node_id: alice_node_id,
- encrypted_payload: vec![],
- });
-
- let (mut trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) = onion_utils::build_trampoline_onion_payloads(&blinded_tail, amt_msat, &recipient_onion_fields, 32, &None).unwrap();
-
- // pop the last dummy hop
- trampoline_payloads.pop();
-
- let trampoline_onion_keys = onion_utils::construct_trampoline_onion_keys(&secp_ctx, &route.paths[0].blinded_tail.as_ref().unwrap(), &carol_alice_trampoline_session_priv);
- let trampoline_packet = onion_utils::construct_trampoline_onion_packet(
- trampoline_payloads,
- trampoline_onion_keys,
- override_random_bytes,
- &payment_hash,
- None,
- ).unwrap();
-
- let (outer_payloads, _, _) = onion_utils::build_onion_payloads(&route.paths[0], outer_total_msat, &recipient_onion_fields, outer_starting_htlc_offset, &None, None, Some(trampoline_packet)).unwrap();
- let outer_onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.clone().paths[0], &outer_onion_session_priv);
- let outer_packet = onion_utils::construct_onion_packet(
- outer_payloads,
- outer_onion_keys,
- override_random_bytes,
- &payment_hash,
- ).unwrap();
-
- outer_packet
- };
-
- let mut events = nodes[0].node.get_and_clear_pending_msg_events();
- assert_eq!(events.len(), 1);
- let mut first_message_event = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
- let mut update_message = match first_message_event {
- MessageSendEvent::UpdateHTLCs { ref mut updates, .. } => {
- assert_eq!(updates.update_add_htlcs.len(), 1);
- updates.update_add_htlcs.get_mut(0)
- },
- _ => panic!()
- };
- update_message.map(|msg| {
- msg.onion_routing_packet = replacement_onion.clone();
- });
-
- let route: &[&Node] = &[&nodes[1], &nodes[2]];
- let args = PassAlongPathArgs::new(&nodes[0], route, amt_msat, payment_hash, first_message_event)
- .with_payment_preimage(payment_preimage)
- .without_claimable_event()
- .expect_failure(HTLCHandlingFailureType::InvalidOnion);
- do_pass_along_path(args);
-
- {
- let unblinded_node_updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
- nodes[1].node.handle_update_fail_htlc(
- nodes[2].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
- );
- do_commitment_signed_dance(&nodes[1], &nodes[2], &unblinded_node_updates.commitment_signed, true, false);
- }
- {
- let unblinded_node_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
- nodes[0].node.handle_update_fail_htlc(
- nodes[1].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
- );
- do_commitment_signed_dance(&nodes[0], &nodes[1], &unblinded_node_updates.commitment_signed, false, false);
- }
- {
- let payment_failed_conditions = PaymentFailedConditions::new()
- .expected_htlc_error_data(LocalHTLCFailureReason::InvalidOnionPayload, &[0; 0]);
- expect_payment_failed_conditions(&nodes[0], payment_hash, true, payment_failed_conditions);
- }
+ fail_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_hash);
}
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.