1
0
mirror of https://github.com/lightning/bolts.git synced 2024-11-19 01:50:03 +01:00

Trampoline Routing

This proposal allows nodes running on constrained devices to sync only a
small portion of the network and leverage trampoline nodes to calculate
the missing parts of the payment route.

The main idea is to use layered onions: a normal onion contains a smaller
onion for the last hop of the route, and that smaller onion contains routing
information to reach the next trampoline hop.
This commit is contained in:
t-bast 2020-12-28 16:24:40 +01:00 committed by t-bast
parent 247e83d528
commit 03e9309140
No known key found for this signature in database
GPG Key ID: 34F377B0100ED6BB

648
proposals/trampoline.md Normal file
View File

@ -0,0 +1,648 @@
# Trampoline Onion Routing
## Table of Contents
* [Introduction](#introduction)
* [Overview](#overview)
* [Trampoline onion](#trampoline-onion)
* [Returning errors](#returning-errors)
* [Invoice flow](#invoice-flow)
* [With Bolt 11 invoices](#with-bolt-11-invoices)
* [With Bolt 12 invoices](#with-bolt-12-invoices)
* [Privacy](#privacy)
* [Trampoline MPP](#trampoline-mpp)
* [Trampoline fees](#trampoline-fees)
* [Future gossip extensions](#future-gossip-extensions)
* [Why not rendezvous routing](#why-not-rendezvous-routing)
## Introduction
As the network grows, more bandwidth and storage will be required to keep an
up-to-date view of the whole network. Finding a payment path will also require
more computing power, making it unsustainable for constrained devices.
Constrained devices should only keep a view of a small part of the network and
leverage trampoline nodes to route payments.
While a thorough analysis has not been made, the current state of the proposal
should not result in a loss of privacy; on the contrary, it gives more routing
flexibility and is likely to improve the anonymity set.
## Overview
Nodes that are able to calculate (partial) routes on behalf of other nodes will
advertise support for the `trampoline_routing` feature. This is an opportunity
for them to earn more fees than with the default onion routing (payers choose
to pay a fee premium in exchange for reliable path-finding-as-a-service from
trampoline nodes).
A payer selects trampoline nodes and builds a corresponding trampoline onion,
very similar to the normal onion; the only difference is that the next nodes
are identified by `node_id` instead of `short_channel_id` and may not be
direct peers.
The payer then embeds that trampoline onion in the last `hop_payload` of an
`onion_packet` destined to the first trampoline node. Computing routes between
trampoline nodes is then deferred to the trampoline nodes themselves.
A trampoline payment will thus look like this:
```text
Trampoline route:
Alice ---> Bob ---> Carol ---> Dave
Complete route:
+--> Irvin --> Iris --+ +--> ... --+ +--> ... --+
| | | | | |
| | | | | |
Alice --+ +--> Bob --+ +--> Carol --+ +--> Dave
<----------------------------------><----------------------><--------------------->
(normal payment) (normal payment) (normal payment)
```
Note that this construction still uses onions created by the payer so it doesn't
sacrifice privacy (in most cases it may even provide a bigger anonymity set).
## Trampoline onion
A trampoline onion uses the same construction as normal payment onions but with
a smaller size, to allow embedding it inside a normal payment onion.
For example, Alice may want to pay Carol using trampoline. Alice inserts
trampoline nodes between her and Carol. For this example we use a single
trampoline (Bob) but Alice may use more than one trampoline.
Alice then finds a route to the first trampoline Bob. The complete route is:
```text
+--> Irvin --> Iris --+ +--> ... --+
| | | |
| | | |
Alice --+ +--> Bob --+ +--> Carol
```
Note again that Alice only needs to find a route to Bob (instead of having to
find a complete route to Carol). She doesn't know what route will be used
between Bob and Carol: it will be Bob's responsibility to find one that works.
If Alice wants to send 50 000 msat to Carol, the corresponding `update_add_htlc`
message sent by Alice to Irvin will look like:
```text
update_add_htlc
+---------------------------------------------------------------------------+
| channel_id: 1x2x3 |
| htlc_id: 42 |
| amount_msat: 55000 |
| cltv_expiry: 1500 |
| payment_hash: 0xabcd |
| onion_routing_packet: |
| +-----------------------------------------------------------------------+ |
| | +--------------------------------------------+----------------------+ | |
| | | amt_to_forward: 54000 | normal onion payload | | |
| | | outgoing_cltv_value: 1450 | for Irvin | | |
| | | short_channel_id: 5x3x7 | | | |
| | +--------------------------------------------+----------------------+ | |
| | +--------------------------------------------+----------------------+ | |
| | | amt_to_forward: 53000 | normal onion payload | | |
| | | outgoing_cltv_value: 1400 | for Iris | | |
| | | short_channel_id: 6x3x0 | | | |
| | +--------------------------------------------+----------------------+ | |
| | +--------------------------------------------+----------------------+ | |
| | | amt_to_forward: 53000 | | | |
| | | outgoing_cltv_value: 1400 | normal onion payload | | |
| | | payment_secret: 0x1111... | for Bob | | |
| | | total_amount: 53000 | | | |
| | | trampoline_onion: | | | |
| | | +---------------------------+------------+ | | | |
| | | | amt_to_forward: 50000 | trampoline | | | | |
| | | | outgoing_cltv_value: 1000 | payload | | | | |
| | | | outgoing_node_id: carol | for Bob | | | | |
| | | +---------------------------+------------+ | | | |
| | | +---------------------------+------------+ | | | |
| | | | amt_to_forward: 50000 | trampoline | | | | |
| | | | outgoing_cltv_value: 1000 | payload | | | | |
| | | | payment_secret: 0x6666 | for Carol | | | | |
| | | | total_amount: 50000 | (final) | | | | |
| | | +---------------------------+------------+ | | | |
| | +--------------------------------------------+----------------------+ | |
| +-----------------------------------------------------------------------+ |
+---------------------------------------------------------------------------+
```
When Bob receives the trampoline onion, he discovers that the next node is Carol.
Bob finds a route to Carol, builds a new payment onion and includes the peeled
trampoline onion in the final payload. This process may repeat with multiple
trampoline hops until we reach the final recipient.
Here is an example flow of `update_add_htlc` messages received at each hop:
```text
Alice ------------------> Irvin -------------------------------------> Iris -----------------------------------> Bob -----------------------------------------> John ------------------------------------> Jack ------------------------------------> Carol
update_add_htlc update_add_htlc update_add_htlc update_add_htlc update_add_htlc update_add_htlc
+-------------------------------+ +-------------------------------+ +-----------------------------------+ +-------------------------------+ +-------------------------------+ +-----------------------------------+
| channel_id: 1x2x3 | | channel_id: 5x3x7 | | channel_id: 6x3x0 | | channel_id: 2x8x3 | | channel_id: 1x3x5 | | channel_id: 6x5x4 |
| htlc_id: 42 | | htlc_id: 21 | | htlc_id: 17 | | htlc_id: 7 | | htlc_id: 15 | | htlc_id: 3 |
| amount_msat: 55000 | | amount_msat: 54000 | | amount_msat: 53000 | | amount_msat: 51000 | | amount_msat: 50500 | | amount_msat: 50000 |
| cltv_expiry: 1500 | | cltv_expiry: 1450 | | cltv_expiry: 1400 | | cltv_expiry: 1200 | | cltv_expiry: 1100 | | cltv_expiry: 1000 |
| payment_hash: 0xabcd... | | payment_hash: 0xabcd... | | payment_hash: 0xabcd... | | payment_hash: 0xabcd... | | payment_hash: 0xabcd... | | payment_hash: 0xabcd... |
| onion_routing_packet: | | onion_routing_packet: | | onion_routing_packet: | | onion_routing_packet: | | onion_routing_packet: | | onion_routing_packet: |
| +---------------------------+ | | +---------------------------+ | | +-------------------------------+ | | +---------------------------+ | | +---------------------------+ | | +-------------------------------+ |
| | amt_to_forward: 54000 | | | | amt_to_forward: 53000 | | | | amt_to_forward: 53000 | | | | amt_to_forward: 50500 | | | | amt_to_forward: 50000 | | | | amt_to_forward: 50000 | |
| | outgoing_cltv_value: 1450 | | | | outgoing_cltv_value: 1400 | | | | outgoing_cltv_value: 1400 | | | | outgoing_cltv_value: 1100 | | | | outgoing_cltv_value: 1000 | | | | outgoing_cltv_value: 1000 | |
| | short_channel_id: 5x3x7 | | | | short_channel_id: 6x3x0 | | | | payment_secret: 0x1111... | | | | short_channel_id: 1x3x5 | | | | short_channel_id: 6x5x4 | | | | payment_secret: 0x2222... | |
| +---------------------------+ | | +---------------------------+ | | | total_amount: 53000 | | | +---------------------------+ | | +---------------------------+ | | | total_amount: 50000 | |
| | (encrypted) | | | | (encrypted) | | | | trampoline_onion: | | | | (encrypted) | | | | (encrypted) | | | | trampoline_onion: | |
| +---------------------------+ | | +---------------------------+ | | | +---------------------------+ | | | +---------------------------+ | | +---------------------------+ | | | +---------------------------+ | |
+-------------------------------+ +-------------------------------+ | | | amt_to_forward: 50000 | | | +-------------------------------+ +-------------------------------+ | | | amt_to_forward: 50000 | | |
| | | outgoing_cltv_value: 1000 | | | | | | outgoing_cltv_value: 1000 | | |
| | | outgoing_node_id: carol | | | | | | payment_secret: 0x6666... | | |
| | +---------------------------+ | | | | | total_amount: 50000 | | |
| | | (encrypted) | | | | | +---------------------------+ | |
| | +---------------------------+ | | | | | EOF | | |
| +-------------------------------+ | | | +---------------------------+ | |
| | EOF | | | +-------------------------------+ |
| +-------------------------------+ | | | EOF | |
+-----------------------------------+ | +-------------------------------+ |
+-----------------------------------+
```
## Returning errors
Trampoline nodes apply the same error-wrapping mechanism used for normal onions
at the trampoline onion level. This results in two layers of error wrapping
that let the origin node get actionable data for potential retries.
### Notations
We note `ss(Alice, Bob)` the shared secret between Alice and Bob for the outer
onion encryption, and `tss(Alice, Bob)` the shared secret between Alice and Bob
for the trampoline onion encryption.
### Error before the first trampoline
```text
+---> N1 ---> N2 (error)
|
|
+-------+ +----+
| Alice | | T1 |
+-------+ +----+
```
* Alice receives `wrap(ss(Alice,N1), wrap(ss(Alice,N2), error))`
* She discovers N2 is the failing node by unwrapping with outer onion shared secrets
### Error between trampoline nodes
```text
+---> N1 ---> N2 ---+ +---> M1 ---+ +---> E1 ---> E2 (error)
| | | | |
| v | v |
+-------+ +----+ +----+
| Alice | | T1 | | T2 |
+-------+ +----+ +----+
```
* T2 receives `wrap(ss(T2,E1),wrap(ss(T2,E2), error))`
* T2 discovers E2 is the failing node by unwrapping with outer onion shared
secrets, and can transform this error to the error that makes the most sense
to return to the payer, and wraps it with the trampoline shared secret and
then the outer onion shared secret: `wrap(ss(T1,T2), wrap(tss(Alice,T2), error))`
* T1 receives `wrap(ss(T1, M1), wrap(ss(T1,T2), wrap(tss(Alice,T2), error)))`
* After unwrapping with the outer onion shared secrets T1 obtains: `wrap(tss(Alice,T2), error)`
T1 cannot decrypt further, so it adds its own two layers of wrapping and
forwards upstream `wrap(ss(Alice,T1), wrap(tss(Alice,T1), wrap(tss(Alice,T2), error)))`
* Alice receives `wrap(ss(Alice,N1), wrap(ss(Alice,N2), wrap(ss(Alice,T1), wrap(tss(Alice,T1), wrap(tss(Alice,T2), error)))))`
* She unwraps with the outer onion secrets and obtains: `wrap(tss(Alice,T1), wrap(tss(Alice,T2), error))`
* Since this is still not a plaintext error, she unwraps with the trampoline
onion secrets, recovers `error` and knows that T2 sent it.
### Error at a trampoline node
```text
+---> N1 ---> N2 ---+ +---> M1 ----+
| | | |
| v | v
+-------+ +----+ +----+
| Alice | | T1 | | T2 | (error)
+-------+ +----+ +----+
```
* T2 creates a local error and wraps it: `wrap(ss(T1,T2), wrap(tss(Alice,T2), error))`
* T1 receives `wrap(ss(T1, M1), wrap(ss(T1,T2), wrap(tss(Alice,T2), error)))`
* After unwrapping with the outer onion shared secrets T1 obtains: `wrap(tss(Alice,T2), error)`
It cannot decrypt further, so it adds its own two layers of wrapping and
forwards upstream `wrap(ss(Alice,T1), wrap(tss(Alice,T1), wrap(tss(Alice,T2), error)))`
* Alice receives `wrap(ss(Alice,N1), wrap(ss(Alice,N2), wrap(ss(Alice,T1), wrap(tss(Alice,T1), wrap(tss(Alice,T2), error)))))`
* She unwraps with the outer onion secrets and obtains: `wrap(tss(Alice,T1), wrap(tss(Alice,T2), error))`
* Since this is still not a plaintext error, she unwraps with the trampoline
onion secrets, recovers `error` and knowns that T2 sent it.
### Unparsable error somewhere in the route
This works the same, each trampoline unwraps as much as it can then re-wraps.
It will result in an unparsable error at Alice (as expected).
## Invoice flow
Now the question is: how does Alice choose the trampoline nodes to reach Carol?
### With Bolt 11 invoices
When creating a Bolt 11 invoice with the trampoline feature bit activated, the
recipient may include routing hints that support trampoline. This is useful in
particular when the recipient is directly connected to trampoline nodes with
private channels: those trampoline nodes can be used by the sender to reach the
recipient.
If the recipient is a public node, they don't need to include any routing hint
in their invoice.
```json
{
"routing_hints": [
{
"trampoline_node_id": "036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2",
"short_channel_id": "823786x17x3",
"cltv_expiry_delta": 288,
"fee_base_msat": 5,
"fee_proportional_millionths": 300
}
]
}
```
When Alice wants to pay the invoice, she selects a trampoline node close to her
(let's call it T1) and a trampoline node from Carol's invoice (let's call it
T2). If Carol doesn't include any routing hint in the invoice, T2 = Carol.
Alice then simply uses the trampoline route `Alice -> T1 -> T2 -> Carol` and
creates the corresponding trampoline onion. Alice then finds a route to T1, and
sends the payment through that route.
```text
Alice's neighborhood Carol's neighborhood
+----------------------------------+ +----------------------+
| | | |
| +-----> T4 | | T3 <--------+ |
| | | | | |
| | | | | |
| Alice -----> N1 -----> T1 |-------> (public network graph) ------->| T2 <----- Carol |
| | | | |
| | | +----------------------+
| +-----> N2 -----> T5 |
| |
+----------------------------------+
```
Alice and Carol both assume connectivity between their respective neighborhoods.
Note that this assumption is also necessary with the default source-routing
scheme, so trampoline is not adding any new restrictions.
### With Bolt 12 invoices
Bolt 12 introduces blinded paths in order to protect the receiver's privacy.
This feature combines very nicely with trampoline payments, by providing two
options for the payer. If the receiver supports trampoline, the blinded nodes
are used as trampoline nodes, which provides great anonymity and flexibility.
Otherwise, if the receiver does not support trampoline, the payer can still
pay them privately by asking a trampoline node to relay to the blinded paths
provided in the invoice, which doesn't reveal the receiver's identity (unless
the blinded paths are empty, in which case the payment shouldn't be made with
trampoline if privacy is important).
Carol provides a standard Bolt 12 invoice containing blinded paths to herself:
```text
Carol's neighborhood
+--------------------------------+
| |
| I1 -----> I2 ------+ |
| | |
| v |
| I3 -----> I4 -----> Carol |
| |
+--------------------------------+
```
#### Invoice using trampoline
If Carol supports trampoline, Alice uses every node of the blinded path as
trampoline node, and adds a trampoline node in her own neighborhood at the
beginning of the trampoline route. She includes the invoice's encrypted data
for each node in their respective trampoline payload: this is very similarly
to paying a blinded path without trampoline.
Alice includes the `current_path_key` of the blinded path in the trampoline
onion payload for the introduction node: this means that her trampoline node
T1 doesn't even learn that a blinded path is being used.
This also lets her include any additional fields she'd like in the trampoline
onion payload for Carol.
```text
+---> N1 ---+ +-----+ +-----+
| | | | | |
Alice --+ +--> T1 -----> Bob ----> I3 --+ +--> I4 --+ +--> Carol
<------------------------><------------------><---------------------------------->
(normal payment) (normal payment) (blinded trampoline payment)
```
The `update_add_htlc` messages received at each hop look like:
```text
Alice -----------> N1 --------------------------------------> T1 --------------------------------------------> Bob ------------------------------------------> I3 ---------------------------------------------> I4 ------------------------------------------> Carol
update_add_htlc update_add_htlc update_add_htlc update_add_htlc update_add_htlc update_add_htlc
+-------------------------------+ +-----------------------------------+ +-----------------------------------+ +-------------------------------------+ +-------------------------------------+ +-------------------------------------+
| channel_id: 1x2x3 | | channel_id: 5x3x7 | | channel_id: 9x3x6 | | channel_id: 2x8x0 | | channel_id: 7x2x3 | | channel_id: 8x3x0 |
| htlc_id: 42 | | htlc_id: 17 | | htlc_id: 23 | | htlc_id: 31 | | htlc_id: 17 | | htlc_id: 33 |
| amount_msat: 55000 | | amount_msat: 54000 | | amount_msat: 52000 | | amount_msat: 51000 | | amount_msat: 50500 | | amount_msat: 50000 |
| cltv_expiry: 1500 | | cltv_expiry: 1450 | | cltv_expiry: 1300 | | cltv_expiry: 1200 | | cltv_expiry: 1150 | | cltv_expiry: 1000 |
| payment_hash: 0xabcd... | | payment_hash: 0xabcd... | | payment_hash: 0xabcd... | | payment_hash: 0xabcd... | | payment_hash: 0xabcd... | | payment_hash: 0xabcd... |
| onion_routing_packet: | | onion_routing_packet: | | onion_routing_packet: | | onion_routing_packet: | | onion_routing_packet: | | onion_routing_packet: |
| +---------------------------+ | | +-------------------------------+ | | +-------------------------------+ | | +---------------------------------+ | | +---------------------------------+ | | +---------------------------------+ |
| | amt_to_forward: 54000 | | | | amt_to_forward: 54000 | | | | amt_to_forward: 51000 | | | | amt_to_forward: 51000 | | | | amt_to_forward: 50500 | | | | amt_to_forward: 50000 | |
| | outgoing_cltv_value: 1450 | | | | outgoing_cltv_value: 1450 | | | | outgoing_cltv_value: 1200 | | | | outgoing_cltv_value: 1200 | | | | outgoing_cltv_value: 1150 | | | | outgoing_cltv_value: 1000 | |
| | short_channel_id: 5x3x7 | | | | payment_secret: 0x1111... | | | | short_channel_id: 2x8x0 | | | | payment_secret: 0x2222... | | | | payment_secret: 0x3333... | | | | payment_secret: 0x4444... | |
| +---------------------------+ | | | total_amount: 54000 | | | +-------------------------------+ | | | total_amount: 51000 | | | | total_amount: 50500 | | | | total_amount: 50000 | |
| | (encrypted) | | | | trampoline_onion: | | | | (encrypted) | | | | trampoline_onion: | | | | current_path_key: 0xd5b1... | | | | current_path_key: 0x73a5... | |
| +---------------------------+ | | | +---------------------------+ | | | +-------------------------------+ | | | +-----------------------------+ | | | | trampoline_onion: | | | | trampoline_onion: | |
+-------------------------------+ | | | outgoing_node_id: I3 | | | +-----------------------------------+ | | | current_path_key: 0x7a3c... | | | | | +-----------------------------+ | | | | +-----------------------------+ | |
| | | amt_to_forward: 51000 | | | | | | encrypted_recipient_data: | | | | | | encrypted_recipient_data: | | | | | | amt_to_forward: 50000 | | |
| | | outgoing_cltv_value: 1200 | | | | | | +-------------------------+ | | | | | | +-------------------------+ | | | | | | outgoing_cltv_value: 1000 | | |
| | +---------------------------+ | | | | | | cltv_expiry_delta: 50 | | | | | | | | cltv_expiry_delta: 150 | | | | | | | encrypted_recipient_data: | | |
| | | (encrypted) | | | | | | | fee_proportional: 0 | | | | | | | | fee_proportional: 0 | | | | | | | +-------------------------+ | | |
| | +---------------------------+ | | | | | | fee_base_msat: 500 | | | | | | | | fee_base_msat: 500 | | | | | | | | path_id: 0xdeadbeef... | | | |
| +-------------------------------+ | | | | | short_channel_id: 7x2x3 | | | | | | | | short_channel_id: 8x3x0 | | | | | | | +-------------------------+ | | |
| | EOF | | | | | +-------------------------+ | | | | | | +-------------------------+ | | | | | +-----------------------------+ | |
| +-------------------------------+ | | | +-----------------------------+ | | | | +-----------------------------+ | | | | | EOF | | |
+-----------------------------------+ | | | (encrypted) | | | | | | (encrypted) | | | | | +-----------------------------+ | |
| | +-----------------------------+ | | | | +-----------------------------+ | | | +---------------------------------+ |
| +---------------------------------+ | | +---------------------------------+ | | | EOF | |
| | EOF | | | | EOF | | | +---------------------------------+ |
| +---------------------------------+ | | +---------------------------------+ | +-------------------------------------+
+-------------------------------------+ +-------------------------------------+
```
Note that this also lets nodes inside the blinded path split the outgoing
payment in multiple parts if they have more than one channel with the next
node, which improves reliability.
#### Invoice without trampoline
If Carol doesn't support trampoline, Alice can still pay her invoice with
trampoline, but in that case she won't be able to include additional fields
in the payment for Carol (e.g. async payment fields).
Alice chooses a trampoline node in her own neighborhood and simply provides
the blinded paths in the trampoline onion. The trampoline node then forwards
the payment using those blinded paths, which ensures that it doesn't learn
the receiver's identity (only the blinded paths introduction nodes).
```text
+---> N1 ---+ +---> I4 ---+
| | | |
Alice --+ +--> T1 -----> Bob ----> I3 --+ +--> Carol
<------------------------><------------------><------------------------>
(normal payment) (normal payment) (blinded payment)
```
The `update_add_htlc` message sent by Alice to N1 looks like:
```text
update_add_htlc
+---------------------------------------------------------------------------+
| channel_id: 1x2x3 |
| htlc_id: 42 |
| amount_msat: 55000 |
| cltv_expiry: 1500 |
| payment_hash: 0xabcd... |
| onion_routing_packet: |
| +-----------------------------------------------------------------------+ |
| | +--------------------------------------------+----------------------+ | |
| | | amt_to_forward: 54000 | normal onion payload | | |
| | | outgoing_cltv_value: 1450 | for N1 | | |
| | | short_channel_id: 5x3x7 | | | |
| | +--------------------------------------------+----------------------+ | |
| | +--------------------------------------------+----------------------+ | |
| | | amt_to_forward: 53000 | | | |
| | | outgoing_cltv_value: 1400 | normal onion payload | | |
| | | payment_secret: 0x1111... | for T1 | | |
| | | total_amount: 53000 | | | |
| | | trampoline_onion: | | | |
| | | +---------------------------+------------+ | | | |
| | | | amt_to_forward: 50000 | | | | | |
| | | | outgoing_cltv_value: 1000 | trampoline | | | | |
| | | | blinded_paths: | payload | | | | |
| | | | <blinded_path_from_I1> | for N1 | | | | |
| | | | <blinded_path_from_I3> | | | | | |
| | | +---------------------------+------------+ | | | |
| | | | EOF | | | | |
| | | +----------------------------------------+ | | | |
| | +--------------------------------------------+----------------------+ | |
| | +-------------------------------------------------------------------+ | |
| | | EOF | | |
| | +-------------------------------------------------------------------+ | |
| +-----------------------------------------------------------------------+ |
+---------------------------------------------------------------------------+
```
The `update_add_htlc` message sent by T1 to Bob looks like:
```text
update_add_htlc
+---------------------------------------------------------------------------+
| channel_id: 4x5x6 |
| htlc_id: 13 |
| amount_msat: 52000 |
| cltv_expiry: 1300 |
| payment_hash: 0xabcd... |
| onion_routing_packet: |
| +-----------------------------------------------------------------------+ |
| | +--------------------------------------------+----------------------+ | |
| | | amt_to_forward: 51000 | normal onion payload | | |
| | | outgoing_cltv_value: 1200 | for Bob | | |
| | | short_channel_id: 5x3x7 | | | |
| | +--------------------------------------------+----------------------+ | |
| | +--------------------------------------------+----------------------+ | |
| | | current_path_key: 0x7a3c... | | | |
| | | encrypted_recipient_data: | blinded path | | |
| | | +----------------------------------------+ | introduction onion | | |
| | | | cltv_expiry_delta: 100 | | payload for I3 | | |
| | | | fee_proportional_millionths: 0 | | | | |
| | | | fee_base_msat: 500 | | | | |
| | | | short_channel_id: 8x1x9 | | | | |
| | | +----------------------------------------+ | | | |
| | +--------------------------------------------+----------------------+ | |
| | +--------------------------------------------+----------------------+ | |
| | | encrypted_recipient_data: | | | |
| | | +----------------------------------------+ | blinded path onion | | |
| | | | cltv_expiry_delta: 100 | | payload for I4 | | |
| | | | fee_proportional_millionths: 0 | | | | |
| | | | fee_base_msat: 500 | | | | |
| | | | short_channel_id: 4x3x7 | | | | |
| | | +----------------------------------------+ | | | |
| | +--------------------------------------------+----------------------+ | |
| | +--------------------------------------------+----------------------+ | |
| | | amt_to_forward: 50000 | | | |
| | | total_amount_msat: 50000 | blinded path onion | | |
| | | outgoing_cltv_value: 1000 | payload for Carol | | |
| | | encrypted_recipient_data: | | | |
| | | +----------------------------------------+ | | | |
| | | | path_id: 0xdeadbeef... | | | | |
| | | +----------------------------------------+ | | | |
| | +--------------------------------------------+----------------------+ | |
| | +-------------------------------------------------------------------+ | |
| | | EOF | | |
| | +-------------------------------------------------------------------+ | |
| +-----------------------------------------------------------------------+ |
+---------------------------------------------------------------------------+
```
## Privacy
Trampoline routing allows constrained devices to send and receive payments
without sacrificing privacy.
Such nodes are advised to sync only a small portion of the graph (their local
neighborhood) and to ensure connectivity to a few distinct trampoline nodes.
This allows them to insert normal hops before the first trampoline node, thus
protecting their privacy with the same guarantees as normal payments. In the
example graph from the previous section, T1 cannot know that the payment comes
from Alice because it only sees an HTLC coming from N1 (especially if Alice is
using an unannounced channel to N1). When T1 receives the HTLC, it cannot know
if the next node in the route (T2) is the final destination or not. Similarly,
T2 cannot know that Carol is the recipient nor that the payment comes from
Alice (T2 cannot even know that the previous trampoline node was T1).
When used with blinded paths, there is no need for multiple trampoline hops.
Even with a single trampoline node, the destination stays private.
## Trampoline MPP
Trampoline routing combines nicely with multi-part payments. When multi-part
payment is used, we can let trampoline nodes combine all the incoming partial
payments before forwarding. Once the totality of the payment is received, the
trampoline node can choose the most efficient way to re-split it to reach the
next trampoline node.
For example, Alice could split a payment in 3 parts to reach a trampoline node,
which would then split it in only 2 parts to reach the destination (we use a
single hop between trampoline nodes for simplicity here, but any number of
intermediate nodes may be used):
```text
HTLC(1500 msat, 600112 cltv)
+---------------------------+
| amount_fwd: 1500 msat |
| expiry: 600112 |
HTLC(1560 msat, 600124 cltv) | payment_secret: aaaaa |
+-----------------------+ | total_amount: 2800 msat |
| amount_fwd: 1500 msat | | trampoline_onion: | HTLC(1100 msat, 600000 cltv)
| expiry: 600112 | | +-----------------------+ | +-----------------------------+
+--> | channel_id: 3 | ---> I1 ---> | | amount_fwd: 2500 msat | | --+ | amount_fwd: 1100 msat |
| |-----------------------| | | expiry: 600000 | | | | expiry: 600000 |
| | (encrypted) | | | node_id: Bob | | | | payment_secret: xxxxx |
| +-----------------------+ | +-----------------------+ | | HTLC(1150 msat, 600080 cltv) | total_amount: 2500 msat |
| | | (encrypted) | | | +-----------------------+ | trampoline_onion: |
| | +-----------------------+ | | | amount_fwd: 1100 msat | | +-------------------------+ |
| +---------------------------+ | | expiry: 600000 | | | amount_fwd: 2500 msat | |
| | EOF | | +--> | channel_id: 561 | ---> I4 ---> | | expiry: 600000 | | --+
| +---------------------------+ | | |-----------------------| | | total_amount: 2500 msat | | |
| HTLC(800 msat, 600112 cltv) | | | (encrypted) | | | payment_secret: yyyyy | | |
| +---------------------------+ | | +-----------------------+ | +-------------------------+ | |
| | amount_fwd: 800 msat | | | | | EOF | | |
| | expiry: 600112 | | | | +-------------------------+ | |
| HTLC(820 msat, 600130 cltv) | payment_secret: aaaaa | | | +-----------------------------+ |
| +-----------------------+ | total_amount: 2800 msat | | | | EOF | |
| | amount_fwd: 800 msat | | trampoline_onion: | | | +-----------------------------+ |
| | expiry: 600112 | | +-----------------------+ | | | |
Alice --+--> | channel_id: 5 | ---> I2 ---> | | amount_fwd: 2500 msat | | --+--> Trampoline --+ +--> Bob
| |-----------------------| | | expiry: 600000 | | | (fee 170 msat) | HTLC(1400 msat, 600000 cltv) |
| | (encrypted) | | | node_id: Bob | | | (delta 32) | +-----------------------------+ |
| +-----------------------+ | +-----------------------+ | | | | amount_fwd: 1400 msat | |
| | | (encrypted) | | | | | expiry: 600000 | |
| | +-----------------------+ | | | | payment_secret: xxxxx | |
| +---------------------------+ | | HTLC(1480 msat, 600065 cltv) | total_amount: 2500 msat | |
| | EOF | | | +-----------------------+ | trampoline_onion: | |
| +---------------------------+ | | | amount_fwd: 1400 msat | | +-------------------------+ | |
| HTLC(500 msat, 600112 cltv) | | | expiry: 600000 | | | amount_fwd: 2500 msat | | |
| +---------------------------+ | +--> | channel_id: 1105 | ---> I5 ---> | | expiry: 600000 | | --+
| | amount_fwd: 500 msat | | |-----------------------| | | total_amount: 2500 msat | |
| | expiry: 600112 | | | (encrypted) | | | payment_secret: yyyyy | |
| HTLC(510 msat, 600120 cltv) | payment_secret: aaaaa | | +-----------------------+ | +-------------------------+ |
| +-----------------------+ | total_amount: 2800 msat | | | | EOF | |
| | amount_fwd: 500 msat | | trampoline_onion: | | | +-------------------------+ |
| | expiry: 600112 | | +-----------------------+ | | +-----------------------------+
+--> | channel_id: 7 | ---> I3 ---> | | amount_fwd: 2500 msat | | --+ | EOF |
|-----------------------| | | expiry: 600000 | | +-----------------------------+
| (encrypted) | | | node_id: Bob | |
+-----------------------+ | +-----------------------+ |
| | (encrypted) | |
| +-----------------------+ |
+---------------------------+
| EOF |
+---------------------------+
```
## Trampoline fees
An important question that comes to mind if how senders choose the fee budget
that they allocate to each trampoline node. A previous version of this proposal
had extensions to the `node_announcement` message that contained trampoline fees.
However, this is different from channel relay fees, because since trampoline
nodes aren't necessarily directly connected to each other, fees may vary based
on the destination and the liquidity available along those paths.
This mechanism was dropped in favor of a trial-and-error approach: whenever
trampoline nodes are unable to relay a payment because the fee budget is not
sufficient to reach the next trampoline node, they return an error to the
sender that contains the fees that would likely work for that payment, and
the sender may retry the payment with those values.
This mechanism is inefficient when many trampoline nodes are used. However,
the most common scenario will be to use a single trampoline node (when using
blinded paths) or two trampoline nodes (mobile-to-mobile payments). In those
cases, the trial-and-error approach works well.
We may want to add a gossip mechanism later to communicate fees if we feel
that the trial-and-error approach is too limiting for some use-cases.
## Future gossip extensions
With the current gossip mechanisms, some bandwidth will be unnecessarily wasted
when constrained nodes sync their local neighborhood, because they have no way
of asking for `channel_update`s within a given distance boundary nor telling
their peers to *not* relay some updates to them.
That can be easily addressed in the future with new Bolt 7 gossip queries, but
is not mandatory to the deployment of trampoline routing.
Two mechanisms in particular would be useful:
* `channel_update` filters: constrained nodes can ask their peers to discard
updates coming from nodes that are further than N hops instead of relaying
them.
* distance-based gossip queries: constrained nodes can ask their peers for all
updates from nodes that are at most N hops far, and combine that with the
current gossip query tricks to avoid replaying updates they already have.
## Why not rendezvous routing
While rendezvous routing shares some properties with trampoline routing and may
be more private, it's also less flexible: payers cannot add data to the partial
onion for the recipient nor change existing data. The amount and expiry must be
fixed ahead of time in the partial onion, which means MPP cannot be used, and
holding payments at trampoline nodes for often-offline mobile wallets (e.g. for
https://github.com/lightning/bolts/pull/1149) is not possible either (whereas
the expiry can be simply omitted from the trampoline onion to make this
possible).