ln: add trampoline LocalHTLCFailureReason variants per spec
What changed, and why it matters
This commit adds three new error-code labels used when a Lightning payment fails while being forwarded through a special routing feature called Trampoline payments. It is essentially a standards-compliance update that maps new internal reasons to the correct numeric failure codes and serialization IDs. There is no direct evidence this fixes an active security bug or vulnerability.
Treat as a routine protocol-compliance update. Review in the context of the broader Trampoline-payments feature branch to confirm the new failure reasons are emitted only in appropriate forwarding paths and that failure-data contents match the spec.
Security signals we found
New enum variants for protocol failure codes only
No changes to cryptographic validation, HTLC acceptance, or channel-state transitions
Debug assertions added for expected failure-data length
Serialization IDs added for persistence compatibility
Evidence from the diff
The patch extends the LocalHTLCFailureReason enum in lightning/src/ln/onion_utils.rs with three Trampoline-specific variants: TemporaryTrampolineFailure, TrampolineFeeOrExpiryInsufficient, and UnknownNextTrampoline. It assigns them the failure-code values NODE|25, NODE|26, and PERM|27 respectively, adds serialization tags 43-45, and adds debug assertions about the expected failure-data length. The change aligns the implementation with the Trampoline payment specification and improves error reporting, but does not by itself alter authorization, cryptographic, or funds-safety logic.
Changed components
lightning/src/ln/onion_utils.rsLocalHTLCFailureReason enumHTLCFailReason serializationInspect captured patch +19 / −1
diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs
index e32b397..75fa46f 100644
--- a/lightning/src/ln/onion_utils.rs
+++ b/lightning/src/ln/onion_utils.rs
@@ -1663,6 +1663,13 @@ pub enum LocalHTLCFailureReason {
PeerOffline,
/// The HTLC was failed because the channel balance was overdrawn.
ChannelBalanceOverdrawn,
+ /// We have been unable to forward a payment to the next Trampoline node but may be able to
+ /// do it later.
+ TemporaryTrampolineFailure,
+ /// The amount or CLTV expiry were insufficient to route the payment to the next Trampoline.
+ TrampolineFeeOrExpiryInsufficient,
+ /// The specified next Trampoline node cannot be reached from our node.
+ UnknownNextTrampoline,
}
impl LocalHTLCFailureReason {
@@ -1704,6 +1711,9 @@ impl LocalHTLCFailureReason {
Self::InvalidOnionPayload | Self::InvalidTrampolinePayload => PERM | 22,
Self::MPPTimeout => 23,
Self::InvalidOnionBlinding => BADONION | PERM | 24,
+ Self::TemporaryTrampolineFailure => NODE | 25,
+ Self::TrampolineFeeOrExpiryInsufficient => NODE | 26,
+ Self::UnknownNextTrampoline => PERM | 27,
Self::UnknownFailureCode { code } => *code,
}
}
@@ -1863,7 +1873,10 @@ ser_failure_reasons!(
(39, HTLCMinimum),
(40, HTLCMaximum),
(41, PeerOffline),
- (42, ChannelBalanceOverdrawn)
+ (42, ChannelBalanceOverdrawn),
+ (43, TemporaryTrampolineFailure),
+ (44, TrampolineFeeOrExpiryInsufficient),
+ (45, UnknownNextTrampoline)
);
impl From<&HTLCFailReason> for HTLCHandlingFailureReason {
@@ -2031,6 +2044,11 @@ impl HTLCFailReason {
debug_assert!(false, "Unknown failure code: {}", code)
}
},
+ LocalHTLCFailureReason::TemporaryTrampolineFailure => debug_assert!(data.is_empty()),
+ LocalHTLCFailureReason::TrampolineFeeOrExpiryInsufficient => {
+ debug_assert_eq!(data.len(), 10)
+ },
+ LocalHTLCFailureReason::UnknownNextTrampoline => debug_assert!(data.is_empty()),
}
Self(HTLCFailReasonRepr::Reason { data, failure_reason })
Why this scored 19/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.