mirror of
https://github.com/lightning/bolts.git
synced 2024-11-19 01:50:03 +01:00
BOLT 2: Details of HTLC Timeouts, ie. cltv_expiry_delta
.
Complete rewrite, including a routing example and the new min_final_cltv expirt. I hope this makes it clear. (Thanks to everyone who reviewed and gave feedback; you rock!) Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
d1fbfd30f8
commit
58d4d9bca3
@ -16,7 +16,7 @@ operation, and closing.
|
||||
* [Closing negotiation: `closing_signed`](#closing-negotiation-closing_signed)
|
||||
* [Normal Operation](#normal-operation)
|
||||
* [Forwarding HTLCs](#forwarding-htlcs)
|
||||
* [Risks With HTLC Timeouts](#risks-with-htlc-timeouts)
|
||||
* [`cltv_expiry_delta` Selection](#cltv_expiry_delta-selection)
|
||||
* [Adding an HTLC: `update_add_htlc`](#adding-an-htlc-update_add_htlc)
|
||||
* [Removing an HTLC: `update_fulfill_htlc`, `update_fail_htlc` and `update_fail_malformed_htlc`](#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc)
|
||||
* [Committing Updates So Far: `commitment_signed`](#committing-updates-so-far-commitment_signed)
|
||||
@ -508,7 +508,7 @@ the incoming HTLC has been irrevocably committed.
|
||||
A node MUST NOT fail an incoming HTLC (`update_fail_htlc`) for which it has committed
|
||||
to an outgoing HTLC, until the removal of the outgoing HTLC is irrevocably committed, or the outgoing on-chain HTLC output has been spent via the HTLC-timeout transaction with sufficient depth.
|
||||
|
||||
A node MUST fail an incoming HTLC (`update_fail_htlc`) once its `cltv_expiry` has been reached.
|
||||
A node MUST fail an incoming HTLC (`update_fail_htlc`) once its `cltv_expiry` has been reached, or if `cltv_expiry` - `current_height` < `cltv_expiry_delta` for the outgoing channel.
|
||||
|
||||
A node MUST fulfill an incoming HTLC for which it has committed to an outgoing HTLC,
|
||||
as soon as it receives `update_fulfill_htlc` for the outgoing HTLC, or has discovered the `payment_preimage` from an on-chain HTLC spend.
|
||||
@ -520,61 +520,113 @@ Fulfilling an HTLC is different: knowledge of the preimage is by definition irre
|
||||
so we should fulfill the incoming HTLC as soon as we can to reduce latency.
|
||||
|
||||
|
||||
### Risks With HTLC Timeouts
|
||||
### `cltv_expiry_delta` Selection
|
||||
|
||||
|
||||
Once an HTLC has timed out where it could either be fulfilled or timed-out;
|
||||
Once an HTLC has timed out it could either be fulfilled or timed-out;
|
||||
care must be taken around this transition both for offered and received HTLCs.
|
||||
|
||||
As a result of forwarding an HTLC from node A to node C, B will end up having an incoming
|
||||
HTLC from A and an outgoing HTLC to C. B will make sure that the incoming HTLC has a greater
|
||||
timeout than the outgoing HTLC, so that B can get refunded from C sooner than it has to refund
|
||||
A if the payment does not complete.
|
||||
Consider the following scenario, where A sends an HTLC to B, who
|
||||
forwards to C, who delivers the goods as soon as the payment is
|
||||
received.
|
||||
|
||||
For example, node A might offer node B an HTLC with a timeout of 3 days, and node B might
|
||||
offer node C the same HTLC with a timeout of 2 days:
|
||||
1. C needs to be sure that the HTLC from B cannot time out, even if B becomes
|
||||
unresponsive; i.e. C can fulfill the incoming HTLC on-chain before B can
|
||||
time it out on-chain.
|
||||
|
||||
```
|
||||
3 days timeout 2 days timeout
|
||||
A ------------------> B ------------------> C
|
||||
```
|
||||
2. B needs to be sure that if C fulfills the HTLC from B, it can fulfill the
|
||||
incoming HTLC from A. i.e. B can get the preimage from C and fulfill incoming the
|
||||
HTLC on-chain before A can time it out on-chain.
|
||||
|
||||
The difference in timeouts is called `cltv_expiry_delta` in
|
||||
[BOLT #7](07-routing-gossip.md).
|
||||
The critical settings here are the `cltv_expiry_delta` in
|
||||
[BOLT #7](07-routing-gossip.md#the-channel_update-message), and the
|
||||
related
|
||||
[`min_final_cltv_expiry` in BOLT #11](11-payment-encoding.md#tagged-fields).
|
||||
`cltv_expiry_delta` is the minimum difference in HTLC CLTV timeouts in
|
||||
the forwarding case (B) and `min_final_ctlv_expiry` is the minimum difference
|
||||
between HTLC CLTV timeout and the current block height for the
|
||||
terminal case (C).
|
||||
|
||||
This difference is important: after 2 days B can try to
|
||||
remove the offer to C even if C is unresponsive, by broadcasting the
|
||||
commitment transaction it has with C and spending the HTLC output.
|
||||
Even though C might race to try to use its payment preimage at that point to
|
||||
also spend the HTLC, it should be resolved well before the 3 day
|
||||
deadline so B can either redeem the HTLC off A or close it.
|
||||
Note that if this value is too low for a channel, the risk is only to
|
||||
the node *accepting* the HTLC, not the node offering it. For this
|
||||
reason, the `cltv_expiry_delta` for the *outgoing* channel is used as
|
||||
the delta across a node.
|
||||
|
||||
We can derive the worst-case number of blocks between outgoing and
|
||||
incoming HTLC resolution, given a few assumptions:
|
||||
|
||||
If the timing is too close, there is a risk of "one-sided redemption",
|
||||
where the payment preimage received from an offered HTLC is too late
|
||||
to be used for an incoming HTLC, leaving the node with unexpected
|
||||
liability.
|
||||
* A worst-case reorganization depth `R` blocks
|
||||
* A grace-period `G` blocks after HTLC timeout before we give up on
|
||||
an unresponsive peer and drop to chain.
|
||||
* A number of blocks `S` between transaction broadcast and the
|
||||
transaction being included in a block.
|
||||
|
||||
The worst case is for a forwarding node (B) which takes the longest
|
||||
possible time to spot the outgoing HTLC fulfillment, and then takes
|
||||
the longest possible time to redeem it on-chain:
|
||||
|
||||
Thus the effective timeout of the HTLC is the `cltv_expiry`, plus some
|
||||
additional delay for the transaction which redeems the HTLC output to
|
||||
be irreversibly committed to the blockchain.
|
||||
1. The B->C HTLC times out at block `N`, and B waits `G` blocks until
|
||||
it gives up waiting for C. B or C commits to the blockchain,
|
||||
and B spends HTLC, which takes `S` blocks to be included.
|
||||
2. Bad case: C wins the race (just) and fulfills the HTLC, B only sees
|
||||
that transaction when it sees block `N+G+S+1`.
|
||||
3. Worst case: There's reorganization `R` deep in which C wins and
|
||||
fulfills. B only sees transaction at `N+G+S+R`.
|
||||
4. B now needs to fulfill the incoming A->B HTLC, but A is unresponsive: B waits `G` more
|
||||
blocks before giving up waiting for A. A or B commits to the blockchain.
|
||||
5. Bad case: B sees A's commitment transaction in block `N+G+S+R+G+1`, and has
|
||||
to spend the HTLC output, which takes `S` blocks to be mined.
|
||||
6. Worst case: There's another reorganization `R` deep which A uses to
|
||||
spend the commitment transaction, so B sees A's commitment
|
||||
transaction in block `N+G+S+R+G+R`, and has to spend the HTLC output, which
|
||||
takes `S` blocks to be mined.
|
||||
7. B's HTLC spend needs to be at least `R` deep before it times out,
|
||||
otherwise another reorganization could allow A to timeout the
|
||||
transaction.
|
||||
|
||||
Thus the worst case is `3R+2G+2S` assuming `R` is at least 1. Note that the
|
||||
chances of three reorganizations in which the other node wins all of them is
|
||||
low for `R` of 2 or more. Since we use high fees (and HTLC spends can use
|
||||
almost arbitrary fees) `S` should be small, though given that block times are
|
||||
irregular and empty blocks still occur, `S = 2` should be considered a
|
||||
minimum. Similarly, the grace period `G` can be low (1 or 2), as nodes are
|
||||
required to timeout or fulfill as soon as possible; but too low increases the
|
||||
risk of unnecessary channel closure due to networking delays.
|
||||
|
||||
There are four values we need to derive:
|
||||
|
||||
1. The `cltv_expiry_delta` for channels. `3R+2G+2S`; if in doubt, a
|
||||
`cltv_expiry_delta` of 12 is reasonable (R=2, G=1, S=2).
|
||||
|
||||
2. For HTLCs we offer: the timeout deadline when we have to fail the channel
|
||||
and time it out on-chain. This is `G` blocks after the HTLC
|
||||
`cltv_expiry`; 1 block is reasonable.
|
||||
|
||||
3. For HTLCs we accept and have a preimage: the fulfillment deadline when we
|
||||
have to fail the channel and fulfill the HTLC onchain before its
|
||||
`cltv_expiry`. This is steps 4-7 above, which means a deadline of `2R+G+S`
|
||||
blocks before `cltv_expiry`; 7 blocks is reasonable.
|
||||
|
||||
4. The minimum `cltv_expiry` we will accept for terminal payments: the
|
||||
worst case for the terminal node C lower at `2R+G+S` blocks (steps
|
||||
1-3 above don't apply). The default in
|
||||
[BOLT 11](11-payment-encoding.md) is 9, which is slightly more
|
||||
conservative than the 6 this calculation suggests.
|
||||
|
||||
The fulfillment risk is similar: if a node C fulfills an HTLC after
|
||||
its timeout, B might broadcast the commitment transaction and
|
||||
immediately broadcast the HTLC timeout transaction. In this scenario,
|
||||
B would gain knowledge of the preimage without paying C.
|
||||
|
||||
#### Requirements
|
||||
|
||||
A node MUST estimate the deadline for successful redemption for each
|
||||
HTLC. A node MUST NOT offer a HTLC after this deadline, and
|
||||
MUST fail the channel if an HTLC which it offered is in either node's
|
||||
current commitment transaction past this deadline.
|
||||
A node MUST estimate a timeout deadline for each HTLC it offers. A node MUST
|
||||
NOT offer an HTLC with a timeout deadline before its `cltv_expiry`, and MUST
|
||||
fail the channel if an HTLC which it offered is in either node's current
|
||||
commitment transaction past this timeout deadline.
|
||||
|
||||
A node MUST estimate a fulfillment deadline for each HTLC it is attempting to
|
||||
fulfill. A node MUST fail (and not forward) an HTLC whose fulfillment
|
||||
deadline is already past, and MUST fail the connection if a HTLC it has
|
||||
fulfilled is in either node's current commitment transaction past this
|
||||
fulfillment deadline.
|
||||
|
||||
A node MUST NOT fulfill an HTLC after this deadline, and MUST fail the
|
||||
connection if a HTLC it has fulfilled is in either node's current
|
||||
commitment transaction past this deadline.
|
||||
|
||||
### Adding an HTLC: `update_add_htlc`
|
||||
|
||||
@ -743,7 +795,7 @@ using the `failure_code` given and setting the data to
|
||||
#### Rationale
|
||||
|
||||
A node which doesn't time out HTLCs risks channel failure (see
|
||||
"Risks With HTLC Timeouts").
|
||||
[`cltv_expiry_delta` Selection](#cltv_expiry_delta-selection).
|
||||
|
||||
A node which sends `update_fulfill_htlc` before the sender is also
|
||||
committed to the HTLC risks losing funds.
|
||||
|
@ -146,7 +146,7 @@ Field Description:
|
||||
* `outgoing_cltv_value` - The CLTV value that the _outgoing_ HTLC carrying
|
||||
the packet should have.
|
||||
|
||||
cltv_expiry - cltv_expiry_delta = outgoing_cltv_value
|
||||
cltv_expiry - cltv_expiry_delta >= outgoing_cltv_value
|
||||
|
||||
Inclusion of this field allows a node to both authenticate the information
|
||||
specified by the original sender and the parameters of the HTLC forwarded,
|
||||
@ -557,7 +557,7 @@ outgoing channel:
|
||||
* [`2`:`len`]
|
||||
* [`len`:`channel_update`]
|
||||
|
||||
If the cltv-expiry is too near, we tell them the the current channel
|
||||
If the `cltv_expiry` is too near, we tell them the the current channel
|
||||
setting for the outgoing channel:
|
||||
|
||||
1. type: UPDATE|14 (`expiry_too_soon`)
|
||||
|
@ -448,6 +448,96 @@ Other more advanced considerations involve diversity of routes to
|
||||
avoid single points of failure and detection, and channel balance
|
||||
of local channels.
|
||||
|
||||
### Routing Example
|
||||
|
||||
Consider four nodes:
|
||||
|
||||
|
||||
```
|
||||
B
|
||||
/ \
|
||||
/ \
|
||||
A C
|
||||
\ /
|
||||
\ /
|
||||
D
|
||||
```
|
||||
|
||||
Each advertises the following `cltv_expiry_delta` on its end of every
|
||||
channel:
|
||||
|
||||
1. A: 10 blocks
|
||||
2. B: 20 blocks
|
||||
3. C: 30 blocks
|
||||
4. D: 40 blocks
|
||||
|
||||
C also uses a`min_final_cltv_expiry` of 9 (the default) when requesting
|
||||
payments.
|
||||
|
||||
Also, each node has the same fee scheme which it uses for each of its
|
||||
channels:
|
||||
|
||||
1. A: 100 base + 1000 millionths
|
||||
1. B: 200 base + 2000 millionths
|
||||
1. C: 300 base + 3000 millionths
|
||||
1. D: 400 base + 4000 millionths
|
||||
|
||||
The network will see eight `channel_update` messages:
|
||||
|
||||
1. A->B: `cltv_expiry_delta` = 10, `fee_base_msat` = 100, `fee_proportional_millionths` = 1000
|
||||
1. A->D: `cltv_expiry_delta` = 10, `fee_base_msat` = 100, `fee_proportional_millionths` = 1000
|
||||
1. B->A: `cltv_expiry_delta` = 20, `fee_base_msat` = 200, `fee_proportional_millionths` = 2000
|
||||
1. D->A: `cltv_expiry_delta` = 40, `fee_base_msat` = 400, `fee_proportional_millionths` = 4000
|
||||
1. B->C: `cltv_expiry_delta` = 20, `fee_base_msat` = 200, `fee_proportional_millionths` = 2000
|
||||
1. D->C: `cltv_expiry_delta` = 40, `fee_base_msat` = 400, `fee_proportional_millionths` = 4000
|
||||
1. C->B: `cltv_expiry_delta` = 30, `fee_base_msat` = 300, `fee_proportional_millionths` = 3000
|
||||
1. C->D: `cltv_expiry_delta` = 30, `fee_base_msat` = 300, `fee_proportional_millionths` = 3000
|
||||
|
||||
If B were to send 4,999,999 millisatoshi directly to C, it wouldn't
|
||||
charge itself a fee nor add its own `cltv_expiry_delta`, so it would
|
||||
use C's requested `min_final_cltv_expiry` of 9. We also assume it adds a
|
||||
"shadow route" to give an extra CLTV of 42. It could also add extra
|
||||
cltv deltas at other hops, as these values are a minimum, but we don't
|
||||
here for simplicity:
|
||||
|
||||
* `amount_msat`: 4999999
|
||||
* `cltv_expiry`: current-block-height + 9 + 42
|
||||
* `onion_routing_packet`:
|
||||
* `amt_to_forward` = 4999999
|
||||
* `outgoing_cltv_value` = current-block-height + 9 + 42
|
||||
|
||||
If A were to send an 4,999,999 millisatoshi to C via B, it needs to
|
||||
pay B the fee it specified in the B->C `channel_update`, calculated as
|
||||
per [HTLC Fees](#htlc_fees):
|
||||
|
||||
200 + 4999999 * 2000 / 1000000 = 10199
|
||||
|
||||
Similarly, it would need to add the `cltv_expiry` from B->C's
|
||||
`channel_update` (20), plus C's requested `min_final_cltv_expiry` (9), plus 42 for the
|
||||
"shadow route". Thus the `update_add_htlc` message from A to B would
|
||||
be:
|
||||
|
||||
* `amount_msat`: 5010198
|
||||
* `cltv_expiry`: current-block-height + 20 + 9 + 42
|
||||
* `onion_routing_packet`:
|
||||
* `amt_to_forward` = 4999999
|
||||
* `outgoing_cltv_value` = current-block-height + 9 + 42
|
||||
|
||||
The `update_add_htlc` from B to C would be the same as the B->C direct
|
||||
payment above.
|
||||
|
||||
Finally, if for some reason A chose the more expensive route via D, it
|
||||
would send the following `update_add_htlc` to D:
|
||||
|
||||
* `amount_msat`: 5020398
|
||||
* `cltv_expiry`: current-block-height + 40 + 9 + 42
|
||||
* `onion_routing_packet`:
|
||||
* `amt_to_forward` = 4999999
|
||||
* `outgoing_cltv_value` = current-block-height + 9 + 42
|
||||
|
||||
And the `update_add_htlc` from D to C would be the same as the B->C
|
||||
direct payment again.
|
||||
|
||||
## References
|
||||
|
||||
![Creative Commons License](https://i.creativecommons.org/l/by/4.0/88x31.png "License CC-BY")
|
||||
|
Loading…
Reference in New Issue
Block a user