ln: store incoming mpp data in PendingHTLCRouting
What changed, and why it matters
This commit is a small code change that stores extra multi-path payment (MPP) information when a trampoline forward is received. It appears to be a preparatory step for validating incoming payment parts before forwarding them onward. There is no direct evidence in the commit that this fixes an active security vulnerability; it reads more like internal plumbing for an unfinished feature.
Treat as routine feature development unless additional context (e.g., a follow-up commit, security advisory, or bug report) shows this change prevents a concrete vulnerability. Review the subsequent validation logic that consumes `incoming_multipath_data` to ensure MPP parts are properly authenticated and aggregated before outbound forwarding.
Security signals we found
Adds MPP data plumbing for trampoline forwards
No validation logic is visible in this commit
No mention of security, CVE, bug, or vulnerability in commit message
Commit is small and preparatory (+12 -5)
No tests or adversarial scenarios included in diff
Evidence from the diff
The change adds an incoming_multipath_data field of type Option<msgs::FinalOnionHopData> to PendingHTLCRouting::Trampoline and to the internal RoutingInfo::Trampoline variant. The field is populated from outer_hop_data.multipath_trampoline_data in both trampoline forward paths and then threaded into the pending HTLC struct. Serialization support is added via an optional TLV field. The commit message states this is needed to wait for MPP parts to arrive before forwarding the outgoing payment.
Changed components
lightning/src/ln/channelmanager.rslightning/src/ln/onion_payment.rsPendingHTLCRouting::TrampolineRoutingInfo::TrampolineInspect captured patch +12 / −5
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index b822b9a..7582321 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -237,6 +237,8 @@ pub enum PendingHTLCRouting {
blinded: Option<BlindedForward>,
/// The absolute CLTV of the inbound HTLC
incoming_cltv_expiry: u32,
+ /// MPP data for accumulating incoming HTLCs before dispatching an outbound payment.
+ incoming_multipath_data: Option<msgs::FinalOnionHopData>,
},
/// The onion indicates that this is a payment for an invoice (supposedly) generated by us.
///
@@ -17890,6 +17892,7 @@ impl_ser_tlv_based_enum!(PendingHTLCRouting,
(4, blinded, option),
(6, node_id, required),
(8, incoming_cltv_expiry, required),
+ (10, incoming_multipath_data, option),
}
);
diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs
index e8ff978..4c31b63 100644
--- a/lightning/src/ln/onion_payment.rs
+++ b/lightning/src/ln/onion_payment.rs
@@ -111,6 +111,7 @@ enum RoutingInfo {
next_hop_hmac: [u8; 32],
shared_secret: SharedSecret,
current_path_key: Option<PublicKey>,
+ incoming_multipath_data: Option<msgs::FinalOnionHopData>,
},
}
@@ -167,14 +168,15 @@ pub(super) fn create_fwd_pending_htlc_info(
reason: LocalHTLCFailureReason::InvalidOnionPayload,
err_data: Vec::new(),
}),
- onion_utils::Hop::TrampolineForward { next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
+ onion_utils::Hop::TrampolineForward { outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
(
RoutingInfo::Trampoline {
next_trampoline: next_trampoline_hop_data.next_trampoline,
new_packet_bytes: new_trampoline_packet_bytes,
next_hop_hmac: next_trampoline_hop_hmac,
shared_secret: trampoline_shared_secret,
- current_path_key: None
+ current_path_key: None,
+ incoming_multipath_data: outer_hop_data.multipath_trampoline_data,
},
next_trampoline_hop_data.amt_to_forward,
next_trampoline_hop_data.outgoing_cltv_value,
@@ -200,7 +202,8 @@ pub(super) fn create_fwd_pending_htlc_info(
new_packet_bytes: new_trampoline_packet_bytes,
next_hop_hmac: next_trampoline_hop_hmac,
shared_secret: trampoline_shared_secret,
- current_path_key: outer_hop_data.current_path_key
+ current_path_key: outer_hop_data.current_path_key,
+ incoming_multipath_data: outer_hop_data.multipath_trampoline_data,
},
amt_to_forward,
outgoing_cltv_value,
@@ -233,7 +236,7 @@ pub(super) fn create_fwd_pending_htlc_info(
}),
}
}
- RoutingInfo::Trampoline { next_trampoline, new_packet_bytes, next_hop_hmac, shared_secret, current_path_key } => {
+ RoutingInfo::Trampoline { next_trampoline, new_packet_bytes, next_hop_hmac, shared_secret, current_path_key, incoming_multipath_data } => {
let next_trampoline_packet_pubkey = match next_packet_pubkey_opt {
Some(Ok(pubkey)) => pubkey,
_ => return Err(InboundHTLCErr {
@@ -260,7 +263,8 @@ pub(super) fn create_fwd_pending_htlc_info(
failure: intro_node_blinding_point
.map(|_| BlindedFailure::FromIntroductionNode)
.unwrap_or(BlindedFailure::FromBlindedNode),
- })
+ }),
+ incoming_multipath_data,
}
}
};
Why this scored 25/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.