1
0
mirror of https://github.com/lightning/blips.git synced 2024-11-19 00:50:02 +01:00
lightning-blips/blip-0017.md

367 lines
16 KiB
Markdown
Raw Permalink Normal View History

2022-10-31 17:31:05 +01:00
```
bLIP: 0017
Title: Hosted Channels
Status: Active
Author: Anton Kumaigorodski <akumaigorodski@gmail.com>
fiatjaf <fiatjaf@gmail.com>
Created: 2022-07-07
License: CC0
```
## Abstract
Hosted Channels is a specification for auditable Lightning-like channels backed
only by trust from a client in a host.
This bLIP serves to document what is already supported by some wallets and daemons
(see [Reference Implementations](#reference-implementations)) and to encourage new
implementations.
## Copyright
This bLIP is licensed under the CC0 license.
## Motivation
Hosted Channels are an improvement over the traditional custodial Lightning wallet
model. They describe the roles of "host" and "client", the client being the peer
that is trusting the host to allow them to spend from the channel according to their
balance.
Like custodial wallets, hosted channel clients do not have to have any previous
Bitcoin UTXO or touch the chain in any way; they gain the ability to receive
payments immediately; and they do not have to keep track of a channel state history
and all the pitfalls involved on that, or keep track of Bitcoin transactions or fees.
Unlike custodial wallets, hosted channel clients are not "accounts" in a central
server, they communicate through signed messages over the Lightning protocol and are
otherwise anonymous to the hosts; they perform client-side routing and their hosts only
ever see onions to forward, never the final destination of a payment; they can open
multiple channels to different hosts and send MPP payments over these channels, further
improving their anonymity; and their channel state is signed by both parties, so
they are immune to hosts that may tamper with balances from their actual state on
purpose or by mistake. All this also means clients must be online to send and receive,
as they must sign state updates.
## Specification
The protocol consists of messages being passed through [bolt01][bolt01] connections and
mimics [bolt02][bolt02], with different messages that serve analogous purposes.
Importantly, it defines two distinct roles in the channel: that of the HOST and that of
the CLIENT. The CLIENT being the party who trusts the HOST with its funds when it requests
a hosted channel and receives payments into it.
### Channel Establishment
This is a diagram that illustrates the entire channel establishment process.
C is the CLIENT, H is the HOST.
+-------+ +-------+
| |--(1)--- invoke_hosted_channel -->| |
| |<-(2)--- init_hosted_channel -----| |
| C | | H |
| |--(3)------ state_update -------->| |
| |<-(4)------ state_update ---------| |
+-------+ +-------+
The following sections about the messages will detail this process further.
### The `invoke_hosted_channel` Message
This message is sent by the CLIENT when it wants to request a new hosted channel from a
HOST, but also every time it establishes a connection to the HOST, to activate that
channel and check if the two parties are in agreement with regards to the channel state.
1. type: 65535 (`invoke_hosted_channel`)
2. data:
* [`chain_hash`:`chain_hash`]
* [`u16`:`len`]
* [`len*byte`:`refund_scriptpubkey`]
* [`u16`:`len`]
* [`len*byte`:`secret`]
The `refund_scriptpubkey` is similar to `scriptpubkey` in [bolt02][bolt02-scriptpubkey]
and must be provided in case HOST wants to terminate the channel but cannot contact the
CLIENT.
The `secret` is an optional blob that can be used by HOST to tweak channel parameters
in multiple ways: offer an initial balance, tweak the capacity, only allow clients with
2022-10-31 17:31:05 +01:00
a given secret etc.
Upon receiving an `invoke_hosted_channel` message, the HOST, if willing to establish the
channel, must reply with an `init_hosted_channel` message. If the CLIENT already has a
channel established, the HOST must instead reply with a `last_cross_signed_state`.
### The `init_hosted_channel` Message
This is sent by the HOST after a new CLIENT requests a channel using the
`invoke_hosted_channel` message.
1. type: 65533 (`init_hosted_channel`)
2. data:
* [`u64`:`max_htlc_value_in_flight_msat`]
* [`u64`:`htlc_minimum_msat`]
* [`u16`:`max_accepted_htlcs`]
* [`u64`:`channel_capacity_msat`]
* [`u64`:`initial_client_balance_msat`]
* [`u16`:`len`]
* [`len*byte`:`features`]
It contains the parameters of the hosted channel offered from HOST to CLIENT.
### The `last_cross_signed_state` Message
This message essentially represents the _state of the channel_ and the only
piece of data that must be stored by peers. It is different for each peer or rather
each peer sees the reverse of what the other peer sees, but it includes a signature
by each peer of the other peer's view, thus the name "cross-signed".
1. type: 65531 (`last_cross_signed_state`)
2. data:
* [`bool`: `is_host`]
* [`u16`:`len`]
* [`len*byte`:`last_refund_scriptpubkey`]
* [[`init_hosted_channel`](#the-init_hosted_channel-message):`init_hosted_channel`]
* [`u32`:`block_day`]
* [`u64`:`local_balance_msat`]
* [`u64`:`remote_balance_msat`]
* [`u32`:`local_updates`]
* [`u32`:`remote_updates`]
* [`u16`:`num_incoming_htlcs`]
* [`num_incoming_htlcs`*[`update_add_htlc`][update_add_htlc]:`incoming_htlcs`]
* [`u16`:`num_outgoing_htlcs`]
* [`num_outgoing_htlcs`*[`update_add_htlc`][update_add_htlc]:`outgoing_htlcs`]
* [`signature`:`remote_sig_of_local`]
* [`signature`:`local_sig_of_remote`]
The `is_host` property must be set to either `true` or `false` depending on the side
that is signing it.
The `block_day` is the current Bitcoin block height divided by 144 and rounded down.
The `last_refund_scriptpubkey` is the value of `refund_scriptpubkey` received in the
last `invoke_hosted_channel` sent by CLIENT.
`local_updates` and `remote_updates` are the number of updates each party has added to
the channel over the time, these numbers increase every time a peer sends an
`update_add_htlc`, `update_fail_htlc`, `update_fail_malformed_htlc` or `update_fulfill_htlc`.
Upon receiving this message the CLIENT must check the signatures and proceed as follows:
1. if the number of `local_updates` + `remote_updates` is smaller than what they have
stored, the CLIENT must ignore the message and send their own `last_cross_signed_state`.
In this case the HOST must accept the state as sent by the peer, **reverse** it and
override their own state with the state received from CLIENT.
2. if the number of updates is the same that means CLIENT and HOST are on agreement.
The CLIENT must still sent their `last_cross_signed_state` so the HOST will acknowledge
that and the channel can become "active".
3. if the number of updates is greater than what the CLIENT has stored, they must
**reverse** it and replace their local state with that, then send their local updated
`last_cross_signed_state` to HOST so they can acknowledge that. From the point of view
of the HOST there is no difference between cases 2 and 3.
If the signatures are bad the peer must send an [`error`](#the-error-message) and put
the channel in an "errored" state until it can be fixed manually.
To **reverse** a `last_cross_signed_state` means to see it as the channel peer would, i.e.
change `is_host` from `true` to `false` and vice-versa; to set `local_updates` to
`remote_updates` and vice-versa; to to set `local_balance_msat` to `remote_balance_msat`
and vice-versa, to set `incoming_htlcs` to `outgoing_htlcs` and vice-versa and finally
(although this part is not relevant when signing a `state_update`) to set
`local_sig_of_remote` to `remote_sig_of_local` and vice-versa.
### The `state_update` Message
After receiving an `init_hosted_channel` the CLIENT should check if it likes its params,
then send this message.
Upon receiving it, the HOST will then send its own `state_update` and from the two
`state_update`s
combined both parties should be able to construct their `last_cross_signed_state`
independently, which are the effective channel "state" that both parties must store and
keep track of.
1. type: 65529 (`state_update`)
2. data:
* [`u32`:`block_day`]
* [`u32`:`local_updates`]
* [`u32`:`remote_updates`]
* [`signature`:`local_sig_of_remote`]
The initial value for `local_updates` and `remote_updates` is `0`.
The `local_sig_of_remote` is a signature over the **reverse** of the current value for
`last_cross_signed_state` known to the signer, i.e. the peer's view of the channel
state. The calculation of the hash to be signed can be seen [in this piece of source code][hosted_sighash].
### Normal Operation
The normal channel operation consists in peers offering the default [bolt02][bolt02]
"update messages" to each other, `update_add_htlc`, `update_fail_htlc`,
`update_fail_malformed_htlc` and `update_fulfill_htlc`, then following them with a
`state_update` representing what will be the next state of the channel after the updates
are accepted by the peer.
The peer must respond with their own `state_update` after applying the received update
to their local state view.
There is no distinction between HOST and CLIENT here.
+-------+ +-------+
| |--(1)---- update_add_htlc ---->| |
| |--(2)---- update_add_htlc ---->| |
| |--(3)---- state_update ------->| |
| |<-(4)---- state_update --------| |
| | | |
| A |<-(5)-- update_fulfill_htlc ---| B |
| |<-(6)-- state_update ----------| |
| |--(7)-- state_update --------->| |
| | | |
| |<-(8)--- update_fail_htlc -----| |
| |<-(9)--- state_update ---------| |
| |-(10)--- state_update -------->| |
+-------+ +-------+
To construct the `state_update` message, for each update sent or received, the peers must
increase the `local_updates` or `remote_updates` count of their next (still uncommitted,
unsigned) state (`last_cross_signed_state`), change the balances accordingly, then sign the
**reverse** of that.
`state_update` messages with `local_updates` or `remote_updates` counts smaller than the
current view of a peer's next state must be ignored, and only when their counts and signature
matches a the receiver's current view of the next state that state can be considered
committed, i.e. cross-signed.
### The `update_add_htlc` Message
This is the same [`update_add_htlc` message][update_add_htlc] from bolt01,
but using the type `63505`.
### The `update_fulfill_htlc` Message
This is the same [`update_fulfill_htlc` message][update_fulfill_htlc] from bolt01,
but using the type `63503`.
### The `update_fail_htlc` Message
This is the same [`update_fail_htlc` message][update_fail_htlc] from bolt01,
but using the type `63501`.
### The `update_fail_malformed_htlc` Message
This is the same [`update_fail_malformed_htlc` message][update_fail_malformed_htlc] from bolt01,
but using the type `63499`.
### The `error` Message
This is the same [`error` message][error] from bolt02, but using the type `63497`.
### Dealing with problems
If a peer receives a preimage from a payment sent upstream, but can't contact their hosted
peer to send the `update_fulfill_htlc` and effectively update the state, they can opt to
publish the preimage to the Bitcoin chain in an `OP_RETURN` output. The output scriptPubKey
must take the form of either `OP_RETURN <32-byte-preimage>` or `OP_RETURN <32-byte-preimage>
<32-byte-preimage>` (for publishing two preimages in the same output). Peers should also
monitor the blockchain in search for preimages that may have been published for their
in-flight HTLCs, as the presence of these preimages onchain effectively proves the payment,
even if the peer hasn't sent an `update_fulfill_htlc` update through the normal means.
If an HTLC that is incoming through a hosted channel times out and there is no sight of its
preimage anywhere, it is considered failed, and the peer who is holding that must send an
[`error`](#the-error-message) and put the channel in an "errored" state until it can be
fixed manually.
When the state is "errored" it must not accept new updates _except_ `update_fail_htlc` and
`update_fulfill_htlc` for non-expired pending HTLCs, as good HTLCs may still be resolved
peacefully independent of the conflict caused by others.
After a channel reaches an "errored" state peers can agree through extra-protocol means to
reactivate it under a certain balance distribution. Once that happens the HOST must send
an `state_override` message and the CLIENT must accept it.
### The `state_override` Message
1. type: 65527 (`state_override`)
2. data:
* [`u32`:`block_day`]
* [`u32`:`local_updates`]
* [`u32`:`remote_updates`]
* [`signature`:`local_sig_of_remote`]
After receiving a `state_override`, at any point a CLIENT may send a `state_update` that
matches the `last_cross_signed_state` implied by the `state_override` parameters. That will
put the channel back in an active state.
### Optional branding
Channels can be "branded", i.e. they can have a URL for human contact, a color and an image
logo.
Upon establishing a connection to a HOST, a CLIENT can at anytime send a `ask_branding_info`
message and a HOST may or may not reply with a `hosted_channel_branding` message.
### The `ask_branding_info` Message
1. type: 65511 (`ask_branding_info`)
2. data:
* [`chain_hash`:`chain_hash`]
### The `hosted_channel_branding` Message
1. type: 65525 (`hosted_channel_branding`)
2. data:
* [`3*byte`:`rgb_color`]
* [`bool`:`has_png`]
* [`if has_png: u16`:`len`]
* [`len*byte`:`png_icon`]
* [`u16`:`len`]
* [`len*byte`:`contact_info`]
The `png_icon` must have at most 65535 bytes, and `contact_info` must be a valid URL.
## Rationale
The protocol for hosted channels was created based on real-world experience maintaining
the first standalone Lightning mobile wallet, [BLW][blw], and improved upon the
[initial version of the protocol][rfc1] that was deployed on that in 2019.
It introduces some new messages with numbers picked from the end of the range of
available numbers and a set of messages related to HTLC adding and removing that are
exactly like their BOLT equivalents, but wrapped so they don't interfere with the normal
protocol and can be implemented on plugins that allow custom messages to be sent and
received from nodes like Eclair, CLN and LND.
## Universality
Most nodes are probably not interested in using hosted channels, but that is fine since
for the protocol to be useful we only ever need two parties that are interested in
establishing such a channel to support it, and they connect to each other directly.
## Backwards Compatibility
This does not have backwards compatibility concerns.
## Reference Implementations
* Simple Bitcoin Wallet (client): <https://github.com/btcontract/wallet>
* Eclair Plugin (host): <https://github.com/btcontract/plugin-hosted-channels>
* IMMORTAN (client): <https://github.com/fiatjaf/immortan>
* Poncho (host): <https://github.com/fiatjaf/poncho>
* scoin (types and codecs): [https://github.com/fiatjaf/scoin](https://github.com/fiatjaf/scoin/blob/master/shared/src/main/scala/hc/HostedChannelCodecs.scala)
[blw]: https://archive.is/iMVJj
[rfc1]: https://github.com/btcontract/hosted-channels-rfc/tree/b9d53d5ec9e5238273cead742730cf15824ef48f
[bolt01]: https://github.com/lightning/bolts/blob/master/01-messaging.md
[bolt02]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md
[bolt02-scriptpubkey]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#closing-initiation-shutdown
[hosted_sighash]: https://github.com/fiatjaf/scoin/blob/315be232a70e9a9caa648ac384b679e6eb563ad7/shared/src/main/scala/hc/HostedChannelMessages.scala#L77-L117
[error]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-error-and-warning-messages
[update_add_htlc]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#adding-an-htlc-update_add_htlc
[update_fulfill_htlc]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc
[update_fail_htlc]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc
[update_fail_malformed_htlc]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc