multi: skip InitRemoteMusigNonces if we've already called it

Prior to this commit, taproot channels had a bug:

- If a disconnect happened before peer.AddNewChannel was called,
  then the subsequent reconnect would call peer.AddNewChannel and
  attempt the ChannelReestablish dance.

- peer.AddNewChannel would call NewLightningChannel with
  populated nonce ChannelOpts. This in turn would call
  InitRemoteMusigNonces which would create a new musig pair session
  and set the channel's pendingVerificationNonce to nil.

- During the reestablish dance, ProcessChanSyncMsg would be called.
  This would also call InitRemoteMusigNonces, except it would fail
  since pendingVerificationNonce was set to nil in the previous
  invocation.

To fix this, we add a new functional option to signal to the init logic
that it doesn't need to call InitRemoteMusigNonces in   in
ProcessChanSyncMsg.
This commit is contained in:
Eugene Siegel
2023-10-13 08:00:49 -07:00
committed by Olaoluwa Osuntokun
parent 32c8b82c36
commit dc42b160a0
2 changed files with 48 additions and 15 deletions

View File

@ -1344,6 +1344,9 @@ type LightningChannel struct {
// fundingOutput is the funding output (script+value).
fundingOutput wire.TxOut
// opts is the set of options that channel was initialized with.
opts *channelOpts
sync.RWMutex
}
@ -1351,6 +1354,14 @@ type LightningChannel struct {
// is created.
type ChannelOpt func(*channelOpts)
// channelOpts is the set of options used to create a new channel.
type channelOpts struct {
localNonce *musig2.Nonces
remoteNonce *musig2.Nonces
skipNonceInit bool
}
// WithLocalMusigNonces is used to bind an existing verification/local nonce to
// a new channel.
func WithLocalMusigNonces(nonce *musig2.Nonces) ChannelOpt {
@ -1367,10 +1378,15 @@ func WithRemoteMusigNonces(nonces *musig2.Nonces) ChannelOpt {
}
}
// channelOpts is the set of options used to create a new channel.
type channelOpts struct {
localNonce *musig2.Nonces
remoteNonce *musig2.Nonces
// WithSkipNonceInit is used to modify the way nonces are handled during
// channel initialization for taproot channels. If this option is specified,
// then when we receive the chan reest message from the remote party, we won't
// modify our nonce state. This is needed if we create a channel, get a channel
// ready message, then also get the chan reest message after that.
func WithSkipNonceInit() ChannelOpt {
return func(o *channelOpts) {
o.skipNonceInit = true
}
}
// defaultChannelOpts returns the set of default options for a new channel.
@ -1429,6 +1445,7 @@ func NewLightningChannel(signer input.Signer,
RemoteFundingKey: state.RemoteChanCfg.MultiSigKey.PubKey,
taprootNonceProducer: taprootNonceProducer,
log: build.NewPrefixLog(logPrefix, walletLog),
opts: opts,
}
switch {
@ -4263,6 +4280,12 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
"not sent")
case lc.channelState.ChanType.IsTaproot() && msg.LocalNonce != nil:
if lc.opts.skipNonceInit {
// Don't call InitRemoteMusigNonces if we have already
// done so.
break
}
err := lc.InitRemoteMusigNonces(&musig2.Nonces{
PubNonce: *msg.LocalNonce,
})
@ -8763,6 +8786,9 @@ func (lc *LightningChannel) InitRemoteMusigNonces(remoteNonce *musig2.Nonces,
lc.pendingVerificationNonce = nil
lc.opts.localNonce = nil
lc.opts.remoteNonce = nil
return nil
}