Skip to content

Trampoline onion format (Feature 56/57) #836

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open

Conversation

t-bast
Copy link
Collaborator

@t-bast t-bast commented Jan 25, 2021

Trampoline routing uses layered onions to trustlessly and privately offload the calculation of parts of a payment route to remote trampoline nodes.

A normal onion contains a smaller onion for the last hop of the route, and that smaller onion contains routing information about the next trampoline hop.

Intermediate trampoline nodes "fill the gap" by finding a route to the next trampoline node, and sending it the peeled trampoline onion, until that reaches the final destination.

This PR details the onion construction and requirements for supporting nodes. I advise readers to also have a look at #829 which gives a more high-level view of the different components, how they interact, and provides nice diagrams that help understand the low-level details.

Copy link
Collaborator

@rustyrussell rustyrussell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it, but I'm not sure I understand the purpose of the payment_secret except inside the internal onion for the final node?

@rustyrussell rustyrussell changed the title Trampoline onion format Trampoline onion format (Feature 24/25) Mar 1, 2021
Copy link
Contributor

@lightning-developer lightning-developer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the spec should make a recommendation for CLTV and fee budgets that senders of trampoline onions should use for each trampoline to reduce the usage of temporary_trampoline_failure.

Also it seems reasonable to just reply with a single fee_budget_msat instead of * [u32:fee_base_msat] and [u32:fee_proportional_millionths] as those fields seem not to make sense in the context of trampolines.

Trampolines could announce the fee_budget_msat and cltv_budget (in case you like the new name) that they believe to be sufficient in their node announcements?

cdecker pushed a commit to cdecker/lightning that referenced this pull request Mar 11, 2025
This commit adds the error messages that a trampoline node can return to
a client according to the trampoline onoion format proposal
lightning/bolts#836

Signed-off-by: Peter Neuroth <[email protected]>
We don't actually need to use MPP between trampoline nodes: a single
part payment could work. We're thus removing the requirement to always
provide the MPP field in the outer onion.

Always using MPP (even for single-part payments) simplified our eclair
implementation, but other implementations may work differently, so it
shouldn't impact the spec.
t-bast added a commit to ACINQ/eclair that referenced this pull request Mar 26, 2025
We add support for the official version of trampoline payments, as
specified in lightning/bolts#836.

We keep supporting trampoline payments that use the legacy protocol
to allow a smooth transition. We hardcode the legacy feature bit 149
in a few places to make this work, which is a bit hacky but simple
and should be removed 6 months after releasing the official version.

We also keep supporting payments from trampoline wallets to nodes that
don't support trampoline: this is bad from a privacy standpoint, but
will be fixed when recipients start supporting Bolt 12.
When a trampoline node inside a trampoline blinded path wants to fail an
incoming payment, it must use `update_fail_malformed_htlc` to avoid
leaking blinded path information. The introduction node will translate
that into a real `temporary_trampoline_failure` that it then encrypts to
the payer. We add a test vector that showcases this behavior.
@t-bast
Copy link
Collaborator Author

t-bast commented Mar 26, 2025

@arik-so I've made a small change in faeea3f to allow omitting the MPP field in the outer onion when not using MPP to reach a trampoline node. This is implemented in eclair in #836 if you want to make some cross-compat tests.

- MUST include `amt_to_forward`, `outgoing_cltv_value` and `total_amount_msat`.
- MUST NOT include any other field.
- MAY prepend additional trampoline nodes where the trampoline onion payload:
- MUST include `amt_to_forward` and `outgoing_cltv_value`.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should behaviors be explicitly specified for the scenario where a receiving node's amt_to_forward inside the Trampoline onion is greater/less than in its outer onion? And similar discrepancies for the CLTV value?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean? We're already stating that we must process the contents of the trampoline packet as a normal onion, and thus apply the same requirements. Can you be more precise and suggest specific changes to add to the spec?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, perhaps I'm missing the change, but do we explicitly specify the error code to be returned in this scenario, because trampoline_fee_or_expiry_insufficient's description only seems to refer to the forwarding scenario.

Copy link

@arik-so arik-so Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, absent a total_msat in the outer onion, presumably the comparison in the following line should be made against the amt_to_forward value?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, absent a total_msat in the outer onion, presumably the comparison in the following line should be made against the amt_to_forward value?

Good catch, now that we allow omitting the payment_data TLV, we must explicitly handle the case where it's absent, done in b4aec54

Sure, perhaps I'm missing the change, but do we explicitly specify the error code to be returned in this scenario, because trampoline_fee_or_expiry_insufficient's description only seems to refer to the forwarding scenario.

Since this is a final recipient error, in eclair we do the same thing as what we'd do in the similar case for a non-trampoline recipient:

  • if the expiry is incorrect, we return final_incorrect_cltv_expiry
  • if the amount is incorrect, we return final_incorrect_htlc_amount

Do you want me to explicitly link those two error codes in the receiver requirements you added? Or is there a potential reason for implementations to use a different error code?

t-bast added a commit to t-bast/blips that referenced this pull request Mar 27, 2025
[Trampoline routing](lightning/bolts#836) allows
nodes to send payments with limited access to the network graph, by
relying on trampoline nodes to compute the missing parts of the route.
The BOLTs only specify how such payments can be made to recipients who
either support the trampoline feature or use Bolt12 with a blinded path.
This leaves a gap when paying legacy nodes that don't support any of
those features.

This bLIP provides a mechanism to pay such legacy invoices, by revealing
some of the invoice data to the last trampoline node, who converts the
trampoline payment to a standard payment.
t-bast added a commit to ACINQ/lightning-kmp that referenced this pull request Apr 2, 2025
We update the trampoline feature to match the official specification
from lightning/bolts#836.

We remove support for the previous version of trampoline, which means
that when paying nodes that use the experimental version, we will use
the trampoline-to-non-trampoline flow instead. Similarly, when older
nodes pay updated nodes, they won't understand the new trampoline
feature bit and will use the trampoline-to-non-trampoline flow.

We update the trampoline-to-non-trampoline flow to remove the unused
trampoline payload in the onion, which saves some space. Note that we
don't want to officially specify this scenario, as it leaks some data
about the recipient to the trampoline node. We rather wait for nodes
to either support trampoline or blinded paths, which fixes this issue.
t-bast added a commit to ACINQ/lightning-kmp that referenced this pull request Apr 2, 2025
We update our trampoline payments to blinded paths to match the official
specification from lightning/bolts#836.

The blinded paths and recipient features are included in the trampoline
onion, which potentially allows using multiple trampoline hops.

That was already what we were doing with experimental TLVs, so we simply
update the TLV values to match the spec values.
t-bast added a commit to ACINQ/lightning-kmp that referenced this pull request Apr 2, 2025
We add the ability to pay recipients that support trampoline *and*
blinded paths. We include the blinded path data in the trampoline
payloads for each node inside the blinded path. This doesn't reveal
unnecessary information to the trampoline node: this is specified in
details in lightning/bolts#836.
t-bast added a commit to ACINQ/eclair that referenced this pull request Apr 3, 2025
We add support for the official version of trampoline payments, as
specified in lightning/bolts#836.

We keep supporting trampoline payments that use the legacy protocol
to allow a smooth transition. We hardcode the legacy feature bit 149
in a few places to make this work, which is a bit hacky but simple
and should be removed 6 months after releasing the official version.

We also keep supporting payments from trampoline wallets to nodes that
don't support trampoline: this is bad from a privacy standpoint, but
will be fixed when recipients start supporting Bolt 12.
- MUST use `current_path_key` from the trampoline onion or the outer onion to decrypt it.
- MUST validate its content as it would for the non-trampoline case.
- MUST include the next `current_path_key` in the `hop_payload` for the next trampoline node.
- MUST compute a route to the next trampoline node.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any thoughts on how to protect against DoS here? Also wondering what the most effective way would be for an attacker to overload trampoline nodes. I suppose a max length route sending the htlc in circles with each hop needing to search for a hard to find path would be a component of it.

It seems to be a channel jamming like problem because there's again no info on sender or receiver to filter out / limit trampoline activitiy.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's up to the implementation/node operator to decide what to do here. In practice, trampoline will mostly be used by LSPs and routes will only be computed for mobile wallets that have paid fees to the LSP when getting a channel and liquidity, which is a form of DoS protection. But we'll probably need better heuristics to protect against resource exhaustion indeed!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering what happens if a node doesn't filter for its own clients and just offers trampoline routing to anyone. Would it be advisable at all to enable this, or is this asking for trouble without having the heuristics in place too?

I wouldn't even know how to do these heuristics.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it shouldn't be too hard: you can benchmark how much path-finding you can do in parallel without exhausting your machine's resources, and then rate-limit the number of pending trampoline requests you receive based on that value? That obviously wouldn't be a fair rate-limiting, but it ensures that you don't end up being DoS-ed while still serving some requests, which is probably good enough for such public trampoline nodes?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd imagine that it is easy for an attacker to just drown out the real requests completely.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, but it's easy to ensure they only DoS the requests that don't come from your customers: if you are a wallet provider, you would use separate queues for requests coming from your wallet users and public ones. And at some point when we start using upfront fees, maintaining this attack will have a cost for the attacker!


The trampoline onion specified an `outgoing_node_id` that cannot be reached
from the processing node.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this is obvious to others, but I think it would be helpful to add some trampoline-specific wording to the requirements section below for handling blinded failures, specifically: if current_path_key is set in the onion payload and it is not the final node

The trampoline is the final node in the top level onion path, but not actually the final node, so it can be a little ambiguous as it's currently written?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one was a bit tricky: I think I've improved it by renaming this "payment recipient" in 9938ab3 and removing the redundant "final node" in the "forwarding node" section, but if that's still confusing, let me know what I can change to make it better!

There is no identified scenario where intermediate trampoline nodes use
a blinded path to reach the next trampoline node, since they know the
identity of that next node. We thus disallow this case by specifying
that the `current_path_key` can only be set in either the outer onion
or the trampoline onion (for the introduction node).
t-bast added a commit to ACINQ/eclair that referenced this pull request Jun 12, 2025
We add support for the official version of trampoline payments, as
specified in lightning/bolts#836.

We keep supporting trampoline payments that use the legacy protocol
to allow a smooth transition. We hardcode the legacy feature bit 149
in a few places to make this work, which is a bit hacky but simple
and should be removed 6 months after releasing the official version.

We also keep supporting payments from trampoline wallets to nodes that
don't support trampoline: this is bad from a privacy standpoint, but
will be fixed when recipients start supporting Bolt 12.
t-bast added a commit to ACINQ/eclair that referenced this pull request Jun 24, 2025
We add support for the official version of trampoline payments, as
specified in lightning/bolts#836.

We keep supporting trampoline payments that use the legacy protocol
to allow a smooth transition. We hardcode the legacy feature bit 149
in a few places to make this work, which is a bit hacky but simple
and should be removed 6 months after releasing the official version.

We also keep supporting payments from trampoline wallets to nodes that
don't support trampoline: this is bad from a privacy standpoint, but
will be fixed when recipients start supporting Bolt 12.
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.

10 participants