Skip to content

Full Trampoline Support#4414

Draft
carlaKC wants to merge 40 commits intolightningdevkit:mainfrom
carlaKC:2299-end-to-end
Draft

Full Trampoline Support#4414
carlaKC wants to merge 40 commits intolightningdevkit:mainfrom
carlaKC:2299-end-to-end

Conversation

@carlaKC
Copy link
Copy Markdown
Contributor

@carlaKC carlaKC commented Feb 12, 2026

This PR contains all the changes to support trampoline forwarding in LDK.
It depends on #4304 and #4402 (and thus also #4373)

Outstanding:

  • Add note about forwarding_amt_msat in PaymentForwarded for trampoline
  • Add htlcs to HTLCHandlingFailureType::TrampolineForward
  • HTLC interception for trampoline
  • Consider changes to LSPS2 payment_forwarded (if required?) / better expression of skimmed_fee
  • Validate that the next_node_id we receive across trampoline parts is consistent

This obviously needs to be broken up into parts, and could certainly use some cleaning up (specifically around replays), but opening it up early to provide some context for the decisions make in #4304.

@ldk-reviews-bot
Copy link
Copy Markdown

👋 Hi! I see this is a draft PR.
I'll wait to assign reviewers until you mark it as ready for review.
Just convert it out of draft status when you're ready for review!

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 26, 2026

Codecov Report

❌ Patch coverage is 84.36874% with 156 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.30%. Comparing base (23b620a) to head (9d4fc86).
⚠️ Report is 14 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/outbound_payment.rs 67.44% 61 Missing and 9 partials ⚠️
lightning/src/ln/onion_utils.rs 80.00% 36 Missing and 2 partials ⚠️
lightning/src/ln/channel.rs 58.06% 26 Missing ⚠️
lightning/src/ln/channelmanager.rs 95.63% 20 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4414      +/-   ##
==========================================
+ Coverage   87.11%   87.30%   +0.18%     
==========================================
  Files         161      161              
  Lines      109246   109923     +677     
  Branches   109246   109923     +677     
==========================================
+ Hits        95173    95964     +791     
+ Misses      11592    11470     -122     
- Partials     2481     2489       +8     
Flag Coverage Δ
fuzzing-fake-hashes 30.90% <10.41%> (-0.23%) ⬇️
fuzzing-real-hashes 22.75% <17.32%> (+0.15%) ⬆️
tests 86.37% <83.56%> (+0.19%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@carlaKC carlaKC force-pushed the 2299-end-to-end branch 4 times, most recently from 6e01fea to 28ca55f Compare March 2, 2026 12:53
@carlaKC carlaKC force-pushed the 2299-end-to-end branch 3 times, most recently from 3a8eb0f to c4c9290 Compare March 13, 2026 20:15
@carlaKC carlaKC force-pushed the 2299-end-to-end branch 10 times, most recently from 88e6907 to 3da50ac Compare March 18, 2026 17:53
@carlaKC carlaKC force-pushed the 2299-end-to-end branch 5 times, most recently from 3bb2c0c to 2a44a80 Compare March 24, 2026 17:13
carlaKC added 29 commits May 1, 2026 10:05
We can't perform proper validation because we don't know the outgoing
channel id until we forward the HTLC, so we just perform a basic CLTV
check.

We don't yet have proper handling of trampoline forwards on restart, so
we only enable this in our tests.
Use even persistence value because we can't downgrade with a trampoline
payment in flight, we'll fail to claim the appropriate incoming HTLCs.

We track previous_hop_data in `TrampolineForwardInfo` so that we have
it on hand in our `OutboundPayment::Retryable`to build `HTLCSource` for
our retries.
When we are forwading as a trampoline within a blinded path, we need
to be able to set a blinding point in the outer onion so that
the next blinded trampoline can use it to decrypt its inner onion.

This is only used for relaying nodes in the blinded path, because the
introduction node's inner onion is encrypted using its node_id
(unblinded) pubkey so it can retrieve the path key from inside its
trampoline onion. Relaying nodes node_id is unknown to the original
sender, so their inner onion is encrypted with their blinded identity.
Relaying trampoline nodes therefore have to include the path key in the
outer payload so that the inner onion can be decrypted, which in turn
contains their blinded data for forwarding.

This isn't used for the case where we're the sending node, because all
we have to do is include the blinding point for the introduction node.
For relaying nodes, we just put their encrypted data inside of their
trampoline payload, relying on nodes in the blinded path to pass the
blinding point along.
For trampoline forwards, we try to decrypt with our chosen session key.
If the failing node encrypted the failure once, it's intended for us
and we'll be able to decrypt the failure. If they double encrypted it,
it's intended for the original sender.

To propagate this error back to the original sender, we need the
encrypted error packet so that we can ourselves double encrypt it back
to the original source.
- [ ] Check whether we can get away with checking path.hops[0] directly
  (outbound_payment should always be present?)
ln: return appropriate error for trampoline failures
The blinding point that we pass in is supposed to be the "update add"
blinding point equivalent, which in blinded trampoline relay is the
one that we get in the outer onion.
We failed here to prevent downgrade to versions of LDK that didn't
have full trampoline support. Now that we're done, we can allow reads.
To enable trampoline forwarding fully, remove the forced error
introduced to prevent forwarding trampoline payments when we weren't
ready.
Don't always blindly replace with a manually built test onion when we
run trampoline tests (only for unblinded / failure cases where we need
to mess with the onion).

The we update our replacement onion logic to correctly match our
internal behavior which adds one block to the current height when
dispatching payments.
- [ ] Right now, we assume that the presence of a trampoline means
      that we're in a blinded route. This fails when we test an
      unblinded case (which we do to get coverage for forwarding).
      We likely need to decouple trampoline and blinded tail to allow
      this to work properly.
When we add handling for trampoline payments, we're going to need the
full HTLCSource (with multiple prev_htlcs) to replay settles/claims.
Here we update our existing logic to support tracking by source.
For trampoline, we have multiple outgoing HTLCs for our single source.
Taking the bluntest approach of storing all information for trampoline
forwards as a first stab, can possibly reduce data later.
@carlaKC carlaKC force-pushed the 2299-end-to-end branch from e0c30b4 to 9d4fc86 Compare May 1, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants