-
Notifications
You must be signed in to change notification settings - Fork 272
Simple taproot channels #3103
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
Simple taproot channels #3103
Conversation
8292732
to
4c933f6
Compare
f45142a
to
7e101ce
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's nice that this doesn't require touching too many parts of the codebase now that we've done some refactoring in previous PRs, it's easy to focus on the important taproot-related features!
Overall, I think the main issue is that there is a lot of unsafe patterns where you introduce require
, casting to Right(_)
, .get
on Option
s and throwing exceptions. This must be improved: we cannot risk having an exception in most of those cases, because it would mean that the actor would crash, which could potentially be exploited to prevent us from publishing penalty transactions if our peer published a revoked commitment while our channel actor constantly crashes.
One of the culprits for that is the partial signing function and the signature aggregation: we must either make the functions that call them return an Either
(bubble up the failure), or if we know that we've previously validated the input and it will always work, we should change the low-level signing function to always return a partial signature without ever throwing.
Similarly, when we depend on remote nonces, we should probably use different function overloads that take a non-optional nonce (to prove that we've verified that it existed before calling the function) instead of doing a .get
inside the function. That may require creating different function overloads for taproot commitment formats in some cases, but that seems acceptable?
eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelFeatures.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/crypto/NonceGenerator.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/crypto/NonceGenerator.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/ChannelKeys.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala
Outdated
Show resolved
Hide resolved
Yes, I first wanted to get everything to work including splices and changes required for the interactive sessions, but I'll change this to safer code now.
I had something similar in mind. By far the biggest issue I had was nonce management, especially with splices and re-connections, it got much easier when we switched to sending |
2755e8d
to
f74c1e6
Compare
eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ErrorHandlers.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/ChannelTlv.scala
Outdated
Show resolved
Hide resolved
f74c1e6
to
227a8e6
Compare
Here is a (non-exhaustive) list of important tests that must be added to ensure that we have good enough coverage compared to other commitment formats:
One thing that could make sense would be to update many of the existing channel unit tests that currently use the default commitment format (which we plan to remove) to instead use taproot (mostly in |
1f96546
to
d1659b9
Compare
3dadcc6
to
be3eb9e
Compare
Almost all of these have been implemented by creating a superclass of the original test that uses taproot channels. |
Unfortunately, duplicating test suites like you did wasn't a good strategy: it gave a false sense of security but wasn't actually adding coverage where we need it. I've reverted most of those changes in #3136 (with more details about the motivation behind it) and added more focused tests (which let me find many subtle bugs). |
We add new commitment formats and TLV extensions to include musig2 nonces. This includes a specific commitment format for phoenix taproot channels. The old v1 channel establishment protocol is updated to include nonces and partial signatures. The v2 channel estalishment protocol, based on the interactive tx constuction protocol, is also updated, and the interactive tx session now includes: - an optional funding nonce for the shared input (i.e. the funding tx that is being spent) - a nonce for the commit tx that is being created, and another nonce that will become the channel's "next remote nonce" once the session completes The funding nonce is random and its lifecycle is bound to the interactive session. Side note: the new v2 protocol is both simpler to extend and gives us support for dual-funding and splices. Since there can be several different commitment transactions that valid at the same time while splices are pending, revoke_and_ack and channel_restablish are extended to include a list of funding_tx_id -> nonce tuples (one for each active commitment). channel_restablish also includes as an optional "current commit nonce": if we got disconnected while a splice was in progress before both nodes exchanged their commit signatures: if that is the case, we need to re-send our peer's current signature and will use this nonce to compute it. We also update the simple close protocol to include closing nonces. We allow upgrading channels to taproot during splices, with an optional channel_type TLV added to splice_init/splice_ack. This is not part of the BOLT proposal, and upgrading is currently limited to phoenix taproot channels from phoenix anchor channels.
bb2016a
to
f8a9860
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM let's goooo 🚀
This PR implements lightning/bolts#995 which introduces a new channel format where funding transactions send to an aggregated musig2 public key instead of a 2-of-2 multisig address:
funding and closing transactions become cheaper (by about 15%)
on-chain footprint becomes more private: funding and closing transactions are impossible to distinguish from other p2tr transactions.
This PR is compatible with lightning/bolts@1ad02ee with the assumption that
option_simple_close
is mandatory for simple taproot channels (which is not yet reflected in the BOLT proposal).Support for dual-funding and splicing has also been implemented through extensions to the interactive transaction construction protocol.
EDIT: This PR also includes code to upgrade channels to the new taproot commitment format during a splice.