Skip to content

Full Trampoline Support#4414

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

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

Conversation

@carlaKC
Copy link
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

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

👋 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

codecov bot commented Feb 26, 2026

Codecov Report

❌ Patch coverage is 85.46945% with 195 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.36%. Comparing base (ab31f99) to head (a10a8c2).
⚠️ Report is 2 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 75.78% 44 Missing and 2 partials ⚠️
lightning/src/ln/channelmanager.rs 94.84% 36 Missing and 2 partials ⚠️
lightning/src/ln/channel.rs 49.23% 33 Missing ⚠️
lightning/src/events/mod.rs 0.00% 7 Missing ⚠️
lightning/src/blinded_path/payment.rs 98.33% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4414      +/-   ##
==========================================
+ Coverage   86.19%   86.36%   +0.16%     
==========================================
  Files         160      160              
  Lines      107537   108447     +910     
  Branches   107537   108447     +910     
==========================================
+ Hits        92693    93656     +963     
+ Misses      12220    12155      -65     
- Partials     2624     2636      +12     
Flag Coverage Δ
tests 86.36% <85.46%> (+0.16%) ⬆️

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 March 24, 2026 13:18
To create trampoline forwarding and single hop receiving tails.
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.
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