ln: handle trampoline claims on restart
What changed, and why it matters
This patch fixes a restart-related bug in how the Lightning node resumes claiming forwarded trampoline payments. Previously, after a restart, trampoline payments that needed to be claimed on-chain might not have been processed correctly because the code only looked at single-hop previous channels and ignored trampoline forwards that bundle multiple incoming hops. The fix reuses existing replay logic so those bundled incoming hops are also claimed. A user-visible effect could be that funds from a trampoline forward were temporarily stuck or not recovered automatically after a crash/restart.
Treat as a bug fix with low-to-moderate operational/security relevance. Review related trampoline restart paths for similar omissions. No immediate emergency response indicated, but nodes handling trampoline forwards should upgrade to avoid stuck claims after restart.
Security signals we found
Funds-availability / liveness issue on restart for trampoline forwards
Incomplete handling of HTLCSource enum variant in claim replay path
Patch is additive and conservative (reuses existing replay logic)
Evidence from the diff
In channelmanager.rs, the outbound payment claims replay logic now handles HTLCSource::TrampolineForward by collecting all previous_hop_data entries, instead of only handling HTLCSource::PreviousHopData. The code assumes all incoming HTLCs in a trampoline source are represented and will be claimed together, avoiding duplicate claims. This is a small completeness fix to on-chain claim replay after persistence/restart.
Changed components
lightning/src/ln/channelmanager.rsTrampoline payment forwarding and on-chain claim replayInspect captured patch +3 / −0
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index 3600b97..ad5d4d4 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -19514,6 +19514,9 @@ impl<
let payment_preimage = preimage_opt?;
let prev_htlcs = match &htlc_source {
HTLCSource::PreviousHopData(prev_hop) => vec![prev_hop],
+ HTLCSource::TrampolineForward { previous_hop_data, .. } => {
+ previous_hop_data.iter().collect()
+ },
// If it was an outbound payment, we've handled it above - if a preimage
// came in and we persisted the `ChannelManager` we either handled it
// and are good to go or the channel force-closed - we don't have to
Why this scored 44/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.