mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-19 12:01:27 +02:00
lnwallet: update internal co-op close flow to support musig2 keyspend
In this commit, we update the co-op close flow to support the new musig2 keyspend flow. We'll use some new functional options to allow a caller to pass in an active musig2 session. If this is present, then we'll use that to complete the musig2 flow by signing with a partial signature, and then ultimately combining the signatures at the end.
This commit is contained in:
@@ -2903,6 +2903,7 @@ func (p *Brontide) createChanCloser(channel *lnwallet.LightningChannel,
|
||||
chanCloser := chancloser.NewChanCloser(
|
||||
chancloser.ChanCloseCfg{
|
||||
Channel: channel,
|
||||
MusigSession: NewMusigChanCloser(channel),
|
||||
FeeEstimator: &chancloser.SimpleCoopFeeEstimator{},
|
||||
BroadcastTx: p.cfg.Wallet.PublishTransaction,
|
||||
DisableChannel: func(op wire.OutPoint) error {
|
||||
|
127
peer/musig_chan_closer.go
Normal file
127
peer/musig_chan_closer.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// MusigChanCloser is an adapter over the normal channel state machine that
|
||||
// allows the chan closer to handle the musig2 details of closing taproot
|
||||
// channels.
|
||||
type MusigChanCloser struct {
|
||||
channel *lnwallet.LightningChannel
|
||||
|
||||
musigSession *lnwallet.MusigSession
|
||||
|
||||
localNonce *musig2.Nonces
|
||||
remoteNonce *musig2.Nonces
|
||||
}
|
||||
|
||||
// NewMusigChanCloser creates a new musig chan closer from a normal channel.
|
||||
func NewMusigChanCloser(channel *lnwallet.LightningChannel) *MusigChanCloser {
|
||||
return &MusigChanCloser{
|
||||
channel: channel,
|
||||
}
|
||||
}
|
||||
|
||||
// ProposalClosingOpts returns the options that should be used when
|
||||
// generating a new co-op close signature.
|
||||
func (m *MusigChanCloser) ProposalClosingOpts() ([]lnwallet.ChanCloseOpt, error) {
|
||||
switch {
|
||||
case m.localNonce == nil:
|
||||
return nil, fmt.Errorf("local nonce not generated")
|
||||
|
||||
case m.remoteNonce == nil:
|
||||
return nil, fmt.Errorf("remote nonce not generated")
|
||||
}
|
||||
|
||||
localKey, remoteKey := m.channel.MultiSigKeys()
|
||||
m.musigSession = lnwallet.NewPartialMusigSession(
|
||||
*m.localNonce, localKey, remoteKey,
|
||||
m.channel.Signer, m.channel.FundingTxOut(),
|
||||
lnwallet.RemoteMusigCommit,
|
||||
)
|
||||
|
||||
err := m.musigSession.FinalizeSession(*m.remoteNonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []lnwallet.ChanCloseOpt{
|
||||
lnwallet.WithCoopCloseMusigSession(m.musigSession),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CombineClosingOpts returns the options that should be used when combining
|
||||
// the final musig partial signature. The method also maps the lnwire partial
|
||||
// signatures into an input.Signature that can be used more generally.
|
||||
func (m *MusigChanCloser) CombineClosingOpts(localSig,
|
||||
remoteSig lnwire.PartialSig) (input.Signature, input.Signature,
|
||||
[]lnwallet.ChanCloseOpt, error) {
|
||||
|
||||
if m.musigSession == nil {
|
||||
return nil, nil, nil, fmt.Errorf("musig session not created")
|
||||
}
|
||||
|
||||
// We'll convert the wire partial signatures into an input.Signature
|
||||
// compliant struct so we can pass it into the final combination
|
||||
// function.
|
||||
localPartialSig := &lnwire.PartialSigWithNonce{
|
||||
PartialSig: localSig,
|
||||
Nonce: m.localNonce.PubNonce,
|
||||
}
|
||||
remotePartialSig := &lnwire.PartialSigWithNonce{
|
||||
PartialSig: remoteSig,
|
||||
Nonce: m.remoteNonce.PubNonce,
|
||||
}
|
||||
|
||||
localMuSig := new(lnwallet.MusigPartialSig).FromWireSig(
|
||||
localPartialSig,
|
||||
)
|
||||
remoteMuSig := new(lnwallet.MusigPartialSig).FromWireSig(
|
||||
remotePartialSig,
|
||||
)
|
||||
|
||||
opts := []lnwallet.ChanCloseOpt{
|
||||
lnwallet.WithCoopCloseMusigSession(m.musigSession),
|
||||
}
|
||||
|
||||
// For taproot channels, we'll need to pass along the session so the
|
||||
// final combined signature can be created.
|
||||
return localMuSig, remoteMuSig, opts, nil
|
||||
}
|
||||
|
||||
// ClosingNonce returns the nonce that should be used when generating the our
|
||||
// partial signature for the remote party.
|
||||
func (m *MusigChanCloser) ClosingNonce() (*musig2.Nonces, error) {
|
||||
if m.localNonce != nil {
|
||||
return m.localNonce, nil
|
||||
}
|
||||
|
||||
localKey, _ := m.channel.MultiSigKeys()
|
||||
nonce, err := musig2.GenNonces(
|
||||
musig2.WithPublicKey(localKey.PubKey),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.localNonce = nonce
|
||||
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
// InitRemoteNonce saves the remote nonce the party sent during their shutdown
|
||||
// message so it can be used later to generate and verify signatures.
|
||||
func (m *MusigChanCloser) InitRemoteNonce(nonce *musig2.Nonces) {
|
||||
m.remoteNonce = nonce
|
||||
}
|
||||
|
||||
// A compile-time assertion to ensure MusigChanCloser implements the
|
||||
// chancloser.MusigSession interface.
|
||||
var _ chancloser.MusigSession = (*MusigChanCloser)(nil)
|
Reference in New Issue
Block a user