ln: use total_msat to calculate the amount for our next trampoline
What changed, and why it matters
This commit fixes a bug in how the Lightning Dev Kit calculates the amount to forward when acting as a trampoline node for blinded multi-path payments. Previously, the code used the amount from a single incoming payment packet, which could be too small when several partial payments are meant to combine. The fix uses the intended total payment amount instead, preventing the node from rejecting or misrouting trampoline forwards that arrive in multiple pieces.
Review whether this bug could have caused live trampoline forwards to fail or be rejected, and consider backporting to maintained release branches that support blinded trampoline forwarding. No immediate emergency response is indicated, but users relying on trampoline routing should upgrade.
Security signals we found
Logic error in payment amount validation for blinded trampoline forwards
Multi-path payment (MPP) aggregation not accounted for in forward amount calculation
Potential incorrect HTLC rejection or under-forwarding for trampoline payments
Fix uses aggregate total_msat rather than single incoming HTLC amount
Evidence from the diff
In create_fwd_pending_htlc_info, the TrampolineBlindedForward branch previously called check_blinded_forward with msg.amount_msat as the inbound amount. For blinded trampoline forwards, multiple incoming HTLCs can make up the total inbound amount via MPP. The patch changes the first argument to outer_hop_data.multipath_trampoline_data.as_ref().map(|f| f.total_msat).unwrap_or(msg.amount_msat), so the aggregate total_msat is used to validate payment relay/constraints and compute the outbound forward amount. The comment explicitly notes this is needed because payment_relay and payment_constraints apply to the aggregate forward amount, not a single HTLC.
Changed components
lightning/src/ln/onion_payment.rsTrampolineBlindedForward handling in create_fwd_pending_htlc_infocheck_blinded_forward amount validationInspect captured patch +5 / −1
diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs
index 4c31b63..4fe44ac 100644
--- a/lightning/src/ln/onion_payment.rs
+++ b/lightning/src/ln/onion_payment.rs
@@ -185,8 +185,12 @@ pub(super) fn create_fwd_pending_htlc_info(
)
},
onion_utils::Hop::TrampolineBlindedForward { outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
+ // The blinded path's payment_relay and payment_constraints apply to the aggregate
+ // amount that the trampoline node will forward onward, not the individual amount that
+ // arrives in a single (incoming MPP) HTLC. We used the desired total amount to
+ // calculate our outbound values.
let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
- msg.amount_msat, msg.cltv_expiry, &next_trampoline_hop_data.payment_relay, &next_trampoline_hop_data.payment_constraints, &next_trampoline_hop_data.features
+ outer_hop_data.multipath_trampoline_data.as_ref().map(|f| f.total_msat).unwrap_or(msg.amount_msat), msg.cltv_expiry, &next_trampoline_hop_data.payment_relay, &next_trampoline_hop_data.payment_constraints, &next_trampoline_hop_data.features
).map_err(|()| {
// We should be returning malformed here if `msg.blinding_point` is set, but this is
// unreachable right now since we checked it in `decode_update_add_htlc_onion`.
Why this scored 59/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.