Skip to content

Commit

Permalink
funding+lnwallet: only blind tapscript root early in funding flow
Browse files Browse the repository at this point in the history
In this commit, we modify the aux funding work flow slightly. We won't
be able to generate the full AuxFundingDesc until both sides has
sent+received funding params. So we'll now only attempt to bind the
tapscript root as soon as we send+recv the open_channel message.

We'll now also make sure that we pass the tapscript root all the way
down into the musig2 session creation.
  • Loading branch information
Roasbeef authored and guggero committed May 1, 2024
1 parent cd34dbb commit 078f756
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 60 deletions.
6 changes: 6 additions & 0 deletions funding/aux_funding.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package funding

import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/protofsm"
Expand All @@ -23,4 +24,9 @@ type AuxFundingController interface {
// TODO(roasbeef): erorr on validation if fail due to invalid root
// match?
DescFromPendingChanID(PendingChanID) fn.Option[lnwallet.AuxFundingDesc]

// DeriveTapscriptRoot takes a pending channel ID and maybe returns a
// tapscript root that should be used when creating any musig2 sessions
// for a channel.
DeriveTapscriptRoot(PendingChanID) fn.Option[chainhash.Hash]
}
24 changes: 12 additions & 12 deletions funding/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1620,11 +1620,11 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer,
}

// At this point, if we have an AuxFundingController active, we'll
// check to see if we have any aux info that we should carry along for
// this pid.
auxFundingDesc := fn.MapOption(
func(a AuxFundingController) fn.Option[lnwallet.AuxFundingDesc] {
return a.DescFromPendingChanID(msg.PendingChannelID)
// check to see if we have a special tapscript root to use in our
// musig2 funding output.
tapscriptRoot := fn.MapOption(
func(a AuxFundingController) fn.Option[chainhash.Hash] {
return a.DeriveTapscriptRoot(msg.PendingChannelID)
},
)(f.cfg.AuxFundingController)

Expand All @@ -1644,7 +1644,7 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer,
ZeroConf: zeroConf,
OptionScidAlias: scid,
ScidAliasFeature: scidFeatureVal,
AuxFundingDesc: fn.FlattenOption(auxFundingDesc),
TapscriptRoot: fn.FlattenOption(tapscriptRoot),
}

reservation, err := f.cfg.Wallet.InitChannelReservation(req)
Expand Down Expand Up @@ -4620,11 +4620,11 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
}

// At this point, if we have an AuxFundingController active, we'll
// check to see if we have any aux info that we should carry along for
// this pid.
auxFundingDesc := fn.MapOption(
func(a AuxFundingController) fn.Option[lnwallet.AuxFundingDesc] {
return a.DescFromPendingChanID(chanID)
// check to see if we have a special tapscript root to use in our
// musig2 funding output.
tapscriptRoot := fn.MapOption(
func(a AuxFundingController) fn.Option[chainhash.Hash] {
return a.DeriveTapscriptRoot(chanID)
},
)(f.cfg.AuxFundingController)

Expand All @@ -4651,7 +4651,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
OptionScidAlias: scid,
ScidAliasFeature: scidFeatureVal,
Memo: msg.Memo,
AuxFundingDesc: fn.FlattenOption(auxFundingDesc),
TapscriptRoot: fn.FlattenOption(tapscriptRoot),
}

reservation, err := f.cfg.Wallet.InitChannelReservation(req)
Expand Down
8 changes: 8 additions & 0 deletions lnwallet/chanfunding/psbt_assembler.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/psbt"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/fn"
Expand Down Expand Up @@ -164,6 +165,13 @@ func (i *PsbtIntent) BindKeys(localKey *keychain.KeyDescriptor,
i.State = PsbtOutputKnown
}

// BindTapscriptRoot takes an optional tapscript root and binds it to the
// underlying funding intent. This only applies to musig2 channels, and will be
// used to make the musig2 funding output.
func (i *PsbtIntent) BindTapscriptRoot(root fn.Option[chainhash.Hash]) {
i.tapscriptRoot = root
}

// FundingParams returns the parameters that are necessary to start funding the
// channel output this intent was created for. It returns the P2WSH funding
// address, the exact funding amount and a PSBT packet that contains exactly one
Expand Down
19 changes: 2 additions & 17 deletions lnwallet/reservation.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
)

// CommitmentType is an enum indicating the commitment type we should use for
Expand Down Expand Up @@ -419,7 +418,7 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
chanType |= channeldb.ScidAliasFeatureBit
}

if req.AuxFundingDesc.IsSome() {
if req.TapscriptRoot.IsSome() {
chanType |= channeldb.TapscriptRootBit
}

Expand All @@ -444,39 +443,25 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
RemoteBalance: theirBalance,
FeePerKw: btcutil.Amount(req.CommitFeePerKw),
CommitFee: commitFee,
CustomBlob: fn.MapOption(func(desc AuxFundingDesc) tlv.Blob {
return desc.CustomLocalCommitBlob
})(req.AuxFundingDesc),
},
RemoteCommitment: channeldb.ChannelCommitment{
LocalBalance: ourBalance,
RemoteBalance: theirBalance,
FeePerKw: btcutil.Amount(req.CommitFeePerKw),
CommitFee: commitFee,
CustomBlob: fn.MapOption(func(desc AuxFundingDesc) tlv.Blob {
return desc.CustomRemoteCommitBlob
})(req.AuxFundingDesc),
},
ThawHeight: thawHeight,
Db: wallet.Cfg.Database,
InitialLocalBalance: ourBalance,
InitialRemoteBalance: theirBalance,
Memo: req.Memo,
CustomBlob: fn.MapOption(func(desc AuxFundingDesc) tlv.Blob {
return desc.CustomFundingBlob
})(req.AuxFundingDesc),
TapscriptRoot: fn.MapOption(func(desc AuxFundingDesc) chainhash.Hash {
return desc.TapscriptRoot
})(req.AuxFundingDesc),
TapscriptRoot: req.TapscriptRoot,
},
pushMSat: req.PushMSat,
pendingChanID: req.PendingChanID,
reservationID: id,
wallet: wallet,
chanFunder: req.ChanFunder,
initAuxLeaves: fn.MapOption(func(desc AuxFundingDesc) CommitAuxLeaves {
return desc.InitAuxLeaves
})(req.AuxFundingDesc),
}, nil
}

Expand Down
56 changes: 25 additions & 31 deletions lnwallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,25 +91,21 @@ func (p *PsbtFundingRequired) Error() string {
}

// AuxFundingDesc stores a series of attributes that may be used to modify the
// way the channel funding occurs
// way the channel funding occurs. This struct contains information that can
// only be derived once both sides have received and sent their contributions
// to the channel (keys, etc).
type AuxFundingDesc struct {
// CustomFundingBlob is a custom blob that'll be stored in the database
// within the OpenChannel struct. This should represent information
// static to the channel lifetime.
CustomFundingBlob tlv.Blob

// TapscriptRoot is the root of the tapscript tree that will be used to
// create the funding output.
TapscriptRoot chainhash.Hash

// CustomLocalCommitBlob is a custom blob that'll be stored in the
// first commitment entry for the local party.
CustomLocalCommitBlob tlv.Blob

// CustomRemoteCommitBlob is a custom blob that'll be stored in the
// first commitment entry for the remote party.
//
// TODO(roasbeef): have this just use the leaf fetcher?
CustomRemoteCommitBlob tlv.Blob

// InitAuxLeaves is the set of aux leaves that'll be used for the very
Expand Down Expand Up @@ -229,9 +225,9 @@ type InitFundingReserveMsg struct {
// channel that will be useful to our future selves.
Memo []byte

// AuxFundingDesc is an optional descriptor that can be used to modify
// the way channel funding occurs.
AuxFundingDesc fn.Option[AuxFundingDesc]
// TapscriptRoot is an optional tapscript root that if provided, will
// be used to create the combined key for musig2 based channels.
TapscriptRoot fn.Option[chainhash.Hash]

// err is a channel in which all errors will be sent across. Will be
// nil if this initial set is successful.
Expand Down Expand Up @@ -268,7 +264,6 @@ type fundingReserveCancelMsg struct {
type addContributionMsg struct {
pendingFundingID uint64

// TODO(roasbeef): Should also carry SPV proofs in we're in SPV mode
contribution *ChannelContribution

// NOTE: In order to avoid deadlocks, this channel MUST be buffered.
Expand Down Expand Up @@ -439,8 +434,6 @@ type LightningWallet struct {
quit chan struct{}

wg sync.WaitGroup

// TODO(roasbeef): handle wallet lock/unlock
}

// NewLightningWallet creates/opens and initializes a LightningWallet instance.
Expand Down Expand Up @@ -485,7 +478,6 @@ func (l *LightningWallet) Startup() error {
}

l.wg.Add(1)
// TODO(roasbeef): multiple request handlers?
go l.requestHandler()

return nil
Expand Down Expand Up @@ -1439,7 +1431,6 @@ func (l *LightningWallet) initOurContribution(reservation *ChannelReservation,
// transaction via coin selection are freed allowing future reservations to
// include them.
func (l *LightningWallet) handleFundingCancelRequest(req *fundingReserveCancelMsg) {
// TODO(roasbeef): holding lock too long
l.limboMtx.Lock()
defer l.limboMtx.Unlock()

Expand All @@ -1464,11 +1455,6 @@ func (l *LightningWallet) handleFundingCancelRequest(req *fundingReserveCancelMs
)
}

// TODO(roasbeef): is it even worth it to keep track of unused keys?

// TODO(roasbeef): Is it possible to mark the unused change also as
// available?

delete(l.fundingLimbo, req.pendingFundingID)

pid := pendingReservation.pendingChanID
Expand Down Expand Up @@ -1642,16 +1628,24 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
// and remote key which will be needed to calculate the multisig
// funding output in a next step.
pendingChanID := pendingReservation.pendingChanID

walletLog.Debugf("Advancing PSBT funding flow for "+
"pending_id(%x), binding keys local_key=%v, "+
"remote_key=%x", pendingChanID,
&ourContribution.MultiSigKey,
theirContribution.MultiSigKey.PubKey.SerializeCompressed())

fundingIntent.BindKeys(
&ourContribution.MultiSigKey,
theirContribution.MultiSigKey.PubKey,
)

// We might have a tapscript root, so we'll bind that now to
// ensure we make the proper funding output.
fundingIntent.BindTapscriptRoot(
pendingReservation.partialState.TapscriptRoot,
)

// Exit early because we can't continue the funding flow yet.
req.err <- &PsbtFundingRequired{
Intent: fundingIntent,
Expand Down Expand Up @@ -1724,16 +1718,17 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
// the commitment transaction for the remote party, and verify their incoming
// partial signature.
func genMusigSession(ourContribution, theirContribution *ChannelContribution,
signer input.MuSig2Signer,
fundingOutput *wire.TxOut) *MusigPairSession {
signer input.MuSig2Signer, fundingOutput *wire.TxOut,
tapscriptRoot fn.Option[chainhash.Hash]) *MusigPairSession {

return NewMusigPairSession(&MusigSessionCfg{
LocalKey: ourContribution.MultiSigKey,
RemoteKey: theirContribution.MultiSigKey,
LocalNonce: *ourContribution.LocalNonce,
RemoteNonce: *theirContribution.LocalNonce,
Signer: signer,
InputTxOut: fundingOutput,
LocalKey: ourContribution.MultiSigKey,
RemoteKey: theirContribution.MultiSigKey,
LocalNonce: *ourContribution.LocalNonce,
RemoteNonce: *theirContribution.LocalNonce,
Signer: signer,
InputTxOut: fundingOutput,
TapscriptTweak: tapscriptRoot,
})
}

Expand Down Expand Up @@ -1783,6 +1778,7 @@ func (l *LightningWallet) signCommitTx(pendingReservation *ChannelReservation,
musigSessions := genMusigSession(
ourContribution, theirContribution,
l.Cfg.Signer, fundingOutput,
pendingReservation.partialState.TapscriptRoot,
)
pendingReservation.musigSessions = musigSessions
}
Expand Down Expand Up @@ -2166,6 +2162,7 @@ func (l *LightningWallet) verifyCommitSig(res *ChannelReservation,
res.musigSessions = genMusigSession(
res.ourContribution, res.theirContribution,
l.Cfg.Signer, fundingOutput,
res.partialState.TapscriptRoot,
)
}

Expand Down Expand Up @@ -2256,9 +2253,6 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs

// As we're about to broadcast the funding transaction, we'll take note
// of the current height for record keeping purposes.
//
// TODO(roasbeef): this info can also be piped into light client's
// basic fee estimation?
_, bestHeight, err := l.Cfg.ChainIO.GetBestBlock()
if err != nil {
msg.err <- err
Expand Down

0 comments on commit 078f756

Please sign in to comment.