Olaoluwa Osuntokun [ARCHIVE] on Nostr: π Original date posted:2020-07-20 π Original message: Hi y'all, In this post, ...
π
Original date posted:2020-07-20
π Original message:
Hi y'all,
In this post, I'd like to share an early version of an extension to the spec
and channel state machine that would allow for on-the-fly commitment
_format/type_ changes. Notably, this would allow for us to _upgrade_
commitment types without any on-chain activity, executed in a
de-synchronized and distributed manner. The core realization these proposal
is based on the fact that the funding output is the _only_ component of a
channel that's actually set in stone (requires an on-chain transaction to
modify).
# Motivation
(you can skip this section if you already know why something like this is
important)
First, some motivation. As y'all are likely aware, the current deployed
commitment format has changed once so far: to introduce the
`static_remote_key` variant which makes channels safer by sending the funds
of the party that was force closed on to a plain pubkey w/o any extra tweaks
or derivation. This makes channel recovery safer, as the party that may have
lost data (or can't continue the channel), no longer needs to learn of a
secret value sent to them by the other party to be able to claim their
funds. However, as this new format was introduced sometime after the initial
bootstrapping phase of the network, most channels in the wild today _are
not_ using this safer format. Transitioning _all_ the existing channels to
this new format as is, would require closing them _all_, generating tens of
thousands of on-chain transactions (to close, then re-open), not to mention
chain fees.
With dynamic commitments, users will be able to upgrade their _existing_
channels to new safer types, without any new on-chain transactions!
Anchor output based commitments represent another step forward in making
channels safer as they allow users/software to no longer have to predict
chain fees ahead of time, and also bump up the fee of a
commitment/2nd-level-htlc-transaction, which is extremely important when it
comes to timely on-chain resolution of HTLC contracts. This upgrade process
(as touched on below) can either be manually triggered, or automatically
triggered once the software updates and finds a new preferable default
commitment format is available.
As many of us are aware, the addition of schnorr and taproot to the Bitcoin
protocol dramatically increases the design space for channels as a whole. It
may take some time to explore this design space, particularly as entirely
new channel/commitment formats [1] continue to be discovered. The roll out
of dynamic commitments allows us to defer the concrete design of the future
commitment formats, yet still benefit from the immediate improvement that
comes with morphing the funding output to be a single-key (non-p2wsh, though
the line starts to blur w/ taproot) output. With this new funding output
format in place, users/software will then be able to update to the latest
and greatest commitment format that starts to utilize all the new tools
available (scriptless script based htlcs, etc) at a later date.
Finally, the ability to update the commitment format itself will also allow
us to re-parametrize portions of the channels which are currently set in
stone. As an example, right now the # of max allowed outstanding HTLCs is
set in stone once the channel has opened. With the ability to also swap out
commitment _parameters_, we can start to experiment with flow-control like
ideas such as limiting a new channel peer to only a handful of HTLC slots,
which is then progressively increased based on "good behavior" (or the other
way around as well). Beyond just updating the channel parameters, it's also
possible to "change the rules" of a channel on the fly. An example of this
variant would be creating a new psuedo-type that implements a fee policy
other than "the initiator pays all fees".
# Protocol Changes
With the motivation/background set up, let's dig into some potential ways
the protocol can be modified to support this new meta-feature. As this
change is more of a meta-change, AFAICT, the amount of protocol changes
doesn't appear to be _too_ invasive ;). Most of the heavy lifting is done by
the wondrous TLV message field extensions.
## Explicit Channel Type Negotiation
Right now in the protocol, as new channel types are introduced (static key,
and now anchors) we add a new feature bit. If both nodes have the feature
bit set, then that new channel type is to be used. Notice how this is an
_implicit_ upgrade: there's no explicit signalling during the _funding_
process that a new channel type is to be used. This works OK, if there's one
major accepted "official" channel type, but not as new types are introduced
for specific use cases or applications. The implicit negotiation also makes
things a bit ambiguous at times. As an example, if both nodes have the
`static_remote_key` _and_ anchor outputs feature bit set, which channel type
should they open?
To resolve this existing ambiguity in the channel type negotiation, we'll
need to make the channel type used for funding _explicit_. Thankfully, we
recently modified the message format to be forwarding looking in order to
allow _TLV extensions_ to be added for all existing message types. A new
`channel_type` (type #???) TLV would be added which makes the channel type
used in funding explicit, with the existing feature bit advertisement system
being kept in place.
A draft of the changes in this area would be something like:
* `open_channel` and `accept_channel` gain a new `channel_type` TLV field.
* retroactively the OG commitment format is numbered as `channel_type=0`,
`static_remote_key`, as `channel_type=1`, and anchors as
`channel_type=2`
* if one receives an `open_channel`, or `accept_channel` message with an
unknown `channel_type`, they're to fail the funding flow
* nodes MUST NOT send an `open_channel` or `accept_channel` message with a
`channel_type` that isn't covered by their existing advertise feature
bits
* a mapping between feature bits and expected `channel_type` values would
then be added
* during funding negotiation, the _commitment_ type itself is parametrized
based on the `channel_type` value
* as we've all implemented `static_remote_key` commitments at this
point, I assume the necessary code-level abstractions are already
in-place
## Commitment State Machine Changes
With the changes described in the above section, we're now able to
explicitly identify _which_ channel type we want to enter a funding flow
for. As we add more types, there may not be a "default" type, so making this
process explicit is important to future exploration and extensibility. In
this section, we'll introduce a series of small changes to the `commit_sig`,
and `revoke_and_ack` messages which'll allow us to implement the "dynamic"
portion of this proposal.
Relying once again on the wondrous power of TLV message extensions we'll
carry over the `channel_type` TLV (just the name, # may be diff since this
is a diff message context) to the `commit_sig`, and `revoke_and_ack`
messages. The following guidelines on inclusion and interpretation would
then be applied:
* the `channel_type` specified on a given `commit_sig` message should be
the `channel_type` of the _new_ commitment being _created_
* when receiving a `commit_sig` with a `channel_type` that differs from
the `channel_type` of one's on revoked commitment:
* if the `channel_type` is unknown (or the `channel_type` transition
isn't allowed or defined), then the _p2p_ connection should be
aborted
* otherwise, using the `channel_type` as a parameter for commitment
transaction construction, a new commitment adhering to the rules of
the `channel_type` should be constructed
* the `channel_type` sent in the `revoke_and_ack` message should be the
`channel_type` of the commitment that's being _revoked_
With the above new rules, let's say Alice and Bob upgrade to new versions of
their LN software that support a new channel type `1`, while they're on
channel type `0`. Either triggered automatically, or manually (by either
side), the commitment flow would look something like:
1. sig_c_1 ->
2. <- revoke_c_0
3. <- sig_c_1
4. revoke_c_0 ->
By exchanging 4 messages, both sides are able to upgrade to a new commitment
format. However, one issue with the above flow is that it currently isn't
allowed by the spec, since we disallow sending a `commit_sig` message that
doesn't cover any updates. If we end up going with this route, then we'd
have to relax that constraint to something like:
* an empty `commit_sig` message (one that covers no updates) is
disallowed, unless the `commit_sig` has a `channel_type`, `c_n` that
differs from the channel type of the prior commitment, `c_n-1`.
It would then be up to _new protocol extension documents_ to define _how_ to
construct those new channel types, and also any changes to the on-chain
handling that are required by those channel types. Also certain transitions
may be disallowed. As an example, implementations may want to prevent a user
from going back to the non-static remote key channels from the
`static_remote_key` format.
In order to prepare for these changes, implementations need to be able to
handle "holding" unrevoked commitments of heterogeneous types, as if either
of them hit the chain, they'll need to be able to resolve all contracts
properly.
An alternative to attaching the `channel_type` message to the `commit_sig`
and having _that_ kick off the commitment upgrade, we could instead possibly
add a _new_ update message (like `update_fee`) to make the process more
explicit. In either case, we may want to restrict things a bit by only
allowing the initiator to trigger a commitment format update.
## Further Channel Type Parameterization
With the above protocol sketch, we're able to handle "simple" upgrades,
where some/all of the parameters of the channel are hard coded and/or have
been negotiated out of band. More complex channel types may require the
exchange of additional keys or parameters which need to be known in order to
reconstruct the _new_ commitment format and verify the new signature. This
additional information can possibly be piggy-backed on the `commit_sig`
message in the form of a _nested TLV_ type:
* a msg-local TLV type `channel_params` is added
* the value of this TLV type is a nested TLV blob, that contains all the
necessary fields and values needed to properly handle the channel switch
over
Returning to the flow control example earlier in this post, the new limits
for `max_allowed_htlcs`, can be included in this blob. More complex channel
types could send information such as new keys to be used, or other
parameters
that govern how a commitment is to be constructed (like the size of the
anchor outputs).
# Conclusion
Summarizing, in this post we've proposed a series of protocol modifications
(with TLV fields doing most of the heavy lifting) that allows LN nodes to
upgrade their commitments _without any on-chain_ transactions. Depending on
the architecture of a node, new types may even be added/removed without
actual downtime.
The ability to upgrade commitments after the fact lessens the pressure of
newer possibly experimental channel types to get all the details (and
explore the rather large design space) correct up front. Once Taproot rolls
around, we can simply update the funding output, roll that out, then
continue to hash out the details on the possibly new channel type(s) that
take advantage of all the new tools.
Allowing channel types to be upgraded on the fly let's us update the network
to the new _safer_ channel types in a de-synchronized, distributed manner
that doesn't require any on-chain transactions! Dynamic commitments as a
whole also creates another point of extensibility in the protocol so we can
start to explore all the variants on channels as we know them that exist.
I'm keen to gather feedback, as internally for `lnd` we've committed to
exploring this direction so we can start to upgrade _all_ the existing
lnd-involved channels to the new anchor commitment format, which is the
safest format yet.
[1]: https://eprint.iacr.org/2020/476
-- Laolu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linuxfoundation.org/pipermail/lightning-dev/attachments/20200720/67ee7ab2/attachment.html>
π Original message:
Hi y'all,
In this post, I'd like to share an early version of an extension to the spec
and channel state machine that would allow for on-the-fly commitment
_format/type_ changes. Notably, this would allow for us to _upgrade_
commitment types without any on-chain activity, executed in a
de-synchronized and distributed manner. The core realization these proposal
is based on the fact that the funding output is the _only_ component of a
channel that's actually set in stone (requires an on-chain transaction to
modify).
# Motivation
(you can skip this section if you already know why something like this is
important)
First, some motivation. As y'all are likely aware, the current deployed
commitment format has changed once so far: to introduce the
`static_remote_key` variant which makes channels safer by sending the funds
of the party that was force closed on to a plain pubkey w/o any extra tweaks
or derivation. This makes channel recovery safer, as the party that may have
lost data (or can't continue the channel), no longer needs to learn of a
secret value sent to them by the other party to be able to claim their
funds. However, as this new format was introduced sometime after the initial
bootstrapping phase of the network, most channels in the wild today _are
not_ using this safer format. Transitioning _all_ the existing channels to
this new format as is, would require closing them _all_, generating tens of
thousands of on-chain transactions (to close, then re-open), not to mention
chain fees.
With dynamic commitments, users will be able to upgrade their _existing_
channels to new safer types, without any new on-chain transactions!
Anchor output based commitments represent another step forward in making
channels safer as they allow users/software to no longer have to predict
chain fees ahead of time, and also bump up the fee of a
commitment/2nd-level-htlc-transaction, which is extremely important when it
comes to timely on-chain resolution of HTLC contracts. This upgrade process
(as touched on below) can either be manually triggered, or automatically
triggered once the software updates and finds a new preferable default
commitment format is available.
As many of us are aware, the addition of schnorr and taproot to the Bitcoin
protocol dramatically increases the design space for channels as a whole. It
may take some time to explore this design space, particularly as entirely
new channel/commitment formats [1] continue to be discovered. The roll out
of dynamic commitments allows us to defer the concrete design of the future
commitment formats, yet still benefit from the immediate improvement that
comes with morphing the funding output to be a single-key (non-p2wsh, though
the line starts to blur w/ taproot) output. With this new funding output
format in place, users/software will then be able to update to the latest
and greatest commitment format that starts to utilize all the new tools
available (scriptless script based htlcs, etc) at a later date.
Finally, the ability to update the commitment format itself will also allow
us to re-parametrize portions of the channels which are currently set in
stone. As an example, right now the # of max allowed outstanding HTLCs is
set in stone once the channel has opened. With the ability to also swap out
commitment _parameters_, we can start to experiment with flow-control like
ideas such as limiting a new channel peer to only a handful of HTLC slots,
which is then progressively increased based on "good behavior" (or the other
way around as well). Beyond just updating the channel parameters, it's also
possible to "change the rules" of a channel on the fly. An example of this
variant would be creating a new psuedo-type that implements a fee policy
other than "the initiator pays all fees".
# Protocol Changes
With the motivation/background set up, let's dig into some potential ways
the protocol can be modified to support this new meta-feature. As this
change is more of a meta-change, AFAICT, the amount of protocol changes
doesn't appear to be _too_ invasive ;). Most of the heavy lifting is done by
the wondrous TLV message field extensions.
## Explicit Channel Type Negotiation
Right now in the protocol, as new channel types are introduced (static key,
and now anchors) we add a new feature bit. If both nodes have the feature
bit set, then that new channel type is to be used. Notice how this is an
_implicit_ upgrade: there's no explicit signalling during the _funding_
process that a new channel type is to be used. This works OK, if there's one
major accepted "official" channel type, but not as new types are introduced
for specific use cases or applications. The implicit negotiation also makes
things a bit ambiguous at times. As an example, if both nodes have the
`static_remote_key` _and_ anchor outputs feature bit set, which channel type
should they open?
To resolve this existing ambiguity in the channel type negotiation, we'll
need to make the channel type used for funding _explicit_. Thankfully, we
recently modified the message format to be forwarding looking in order to
allow _TLV extensions_ to be added for all existing message types. A new
`channel_type` (type #???) TLV would be added which makes the channel type
used in funding explicit, with the existing feature bit advertisement system
being kept in place.
A draft of the changes in this area would be something like:
* `open_channel` and `accept_channel` gain a new `channel_type` TLV field.
* retroactively the OG commitment format is numbered as `channel_type=0`,
`static_remote_key`, as `channel_type=1`, and anchors as
`channel_type=2`
* if one receives an `open_channel`, or `accept_channel` message with an
unknown `channel_type`, they're to fail the funding flow
* nodes MUST NOT send an `open_channel` or `accept_channel` message with a
`channel_type` that isn't covered by their existing advertise feature
bits
* a mapping between feature bits and expected `channel_type` values would
then be added
* during funding negotiation, the _commitment_ type itself is parametrized
based on the `channel_type` value
* as we've all implemented `static_remote_key` commitments at this
point, I assume the necessary code-level abstractions are already
in-place
## Commitment State Machine Changes
With the changes described in the above section, we're now able to
explicitly identify _which_ channel type we want to enter a funding flow
for. As we add more types, there may not be a "default" type, so making this
process explicit is important to future exploration and extensibility. In
this section, we'll introduce a series of small changes to the `commit_sig`,
and `revoke_and_ack` messages which'll allow us to implement the "dynamic"
portion of this proposal.
Relying once again on the wondrous power of TLV message extensions we'll
carry over the `channel_type` TLV (just the name, # may be diff since this
is a diff message context) to the `commit_sig`, and `revoke_and_ack`
messages. The following guidelines on inclusion and interpretation would
then be applied:
* the `channel_type` specified on a given `commit_sig` message should be
the `channel_type` of the _new_ commitment being _created_
* when receiving a `commit_sig` with a `channel_type` that differs from
the `channel_type` of one's on revoked commitment:
* if the `channel_type` is unknown (or the `channel_type` transition
isn't allowed or defined), then the _p2p_ connection should be
aborted
* otherwise, using the `channel_type` as a parameter for commitment
transaction construction, a new commitment adhering to the rules of
the `channel_type` should be constructed
* the `channel_type` sent in the `revoke_and_ack` message should be the
`channel_type` of the commitment that's being _revoked_
With the above new rules, let's say Alice and Bob upgrade to new versions of
their LN software that support a new channel type `1`, while they're on
channel type `0`. Either triggered automatically, or manually (by either
side), the commitment flow would look something like:
1. sig_c_1 ->
2. <- revoke_c_0
3. <- sig_c_1
4. revoke_c_0 ->
By exchanging 4 messages, both sides are able to upgrade to a new commitment
format. However, one issue with the above flow is that it currently isn't
allowed by the spec, since we disallow sending a `commit_sig` message that
doesn't cover any updates. If we end up going with this route, then we'd
have to relax that constraint to something like:
* an empty `commit_sig` message (one that covers no updates) is
disallowed, unless the `commit_sig` has a `channel_type`, `c_n` that
differs from the channel type of the prior commitment, `c_n-1`.
It would then be up to _new protocol extension documents_ to define _how_ to
construct those new channel types, and also any changes to the on-chain
handling that are required by those channel types. Also certain transitions
may be disallowed. As an example, implementations may want to prevent a user
from going back to the non-static remote key channels from the
`static_remote_key` format.
In order to prepare for these changes, implementations need to be able to
handle "holding" unrevoked commitments of heterogeneous types, as if either
of them hit the chain, they'll need to be able to resolve all contracts
properly.
An alternative to attaching the `channel_type` message to the `commit_sig`
and having _that_ kick off the commitment upgrade, we could instead possibly
add a _new_ update message (like `update_fee`) to make the process more
explicit. In either case, we may want to restrict things a bit by only
allowing the initiator to trigger a commitment format update.
## Further Channel Type Parameterization
With the above protocol sketch, we're able to handle "simple" upgrades,
where some/all of the parameters of the channel are hard coded and/or have
been negotiated out of band. More complex channel types may require the
exchange of additional keys or parameters which need to be known in order to
reconstruct the _new_ commitment format and verify the new signature. This
additional information can possibly be piggy-backed on the `commit_sig`
message in the form of a _nested TLV_ type:
* a msg-local TLV type `channel_params` is added
* the value of this TLV type is a nested TLV blob, that contains all the
necessary fields and values needed to properly handle the channel switch
over
Returning to the flow control example earlier in this post, the new limits
for `max_allowed_htlcs`, can be included in this blob. More complex channel
types could send information such as new keys to be used, or other
parameters
that govern how a commitment is to be constructed (like the size of the
anchor outputs).
# Conclusion
Summarizing, in this post we've proposed a series of protocol modifications
(with TLV fields doing most of the heavy lifting) that allows LN nodes to
upgrade their commitments _without any on-chain_ transactions. Depending on
the architecture of a node, new types may even be added/removed without
actual downtime.
The ability to upgrade commitments after the fact lessens the pressure of
newer possibly experimental channel types to get all the details (and
explore the rather large design space) correct up front. Once Taproot rolls
around, we can simply update the funding output, roll that out, then
continue to hash out the details on the possibly new channel type(s) that
take advantage of all the new tools.
Allowing channel types to be upgraded on the fly let's us update the network
to the new _safer_ channel types in a de-synchronized, distributed manner
that doesn't require any on-chain transactions! Dynamic commitments as a
whole also creates another point of extensibility in the protocol so we can
start to explore all the variants on channels as we know them that exist.
I'm keen to gather feedback, as internally for `lnd` we've committed to
exploring this direction so we can start to upgrade _all_ the existing
lnd-involved channels to the new anchor commitment format, which is the
safest format yet.
[1]: https://eprint.iacr.org/2020/476
-- Laolu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linuxfoundation.org/pipermail/lightning-dev/attachments/20200720/67ee7ab2/attachment.html>