Merge pull request #8104 from Roasbeef/taproot-chans-nonce-double-init
multi: skip InitRemoteMusigNonces if we've already called it
This commit is contained in:
6 files changed
+138
-17
No files matched your search
@@ -23,6 +23,9 @@
|
|||||||
bit when sending `update_fail_malformed_htlc`. This avoids a force close
|
bit when sending `update_fail_malformed_htlc`. This avoids a force close
|
||||||
with other implementations.
|
with other implementations.
|
||||||
|
|
||||||
|
* A bug that would cause taproot channels to sometimes not display as active
|
||||||
|
[has been fixed](https://github.com/lightningnetwork/lnd/pull/8104).
|
||||||
|
|
||||||
# New Features
|
# New Features
|
||||||
## Functional Enhancements
|
## Functional Enhancements
|
||||||
|
|
||||||
@@ -67,4 +70,5 @@
|
|||||||
|
|
||||||
# Contributors (Alphabetical Order)
|
# Contributors (Alphabetical Order)
|
||||||
* Eugene Siegel
|
* Eugene Siegel
|
||||||
|
* Olaoluwa Osuntokun
|
||||||
* Yong Yu
|
* Yong Yu
|
||||||
@@ -462,6 +462,10 @@ var allTestCases = []*lntest.TestCase{
|
|||||||
Name: "taproot",
|
Name: "taproot",
|
||||||
TestFunc: testTaproot,
|
TestFunc: testTaproot,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "simple taproot channel activation",
|
||||||
|
TestFunc: testSimpleTaprootChannelActivation,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "wallet import account",
|
Name: "wallet import account",
|
||||||
TestFunc: testWalletImportAccount,
|
TestFunc: testWalletImportAccount,
|
||||||
|
|||||||
@@ -768,3 +768,57 @@ func testFundingExpiryBlocksOnPending(ht *lntest.HarnessTest) {
|
|||||||
chanPoint := lntest.ChanPointFromPendingUpdate(update)
|
chanPoint := lntest.ChanPointFromPendingUpdate(update)
|
||||||
ht.CloseChannel(alice, chanPoint)
|
ht.CloseChannel(alice, chanPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testSimpleTaprootChannelActivation ensures that a simple taproot channel is
|
||||||
|
// active if the initiator disconnects and reconnects in between channel opening
|
||||||
|
// and channel confirmation.
|
||||||
|
func testSimpleTaprootChannelActivation(ht *lntest.HarnessTest) {
|
||||||
|
simpleTaprootChanArgs := lntest.NodeArgsForCommitType(
|
||||||
|
lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Make the new set of participants.
|
||||||
|
alice := ht.NewNode("alice", simpleTaprootChanArgs)
|
||||||
|
defer ht.Shutdown(alice)
|
||||||
|
bob := ht.NewNode("bob", simpleTaprootChanArgs)
|
||||||
|
defer ht.Shutdown(bob)
|
||||||
|
|
||||||
|
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)
|
||||||
|
|
||||||
|
// Make sure Alice and Bob are connected.
|
||||||
|
ht.EnsureConnected(alice, bob)
|
||||||
|
|
||||||
|
// Create simple taproot channel opening parameters.
|
||||||
|
params := lntest.OpenChannelParams{
|
||||||
|
FundMax: true,
|
||||||
|
CommitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||||
|
Private: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alice opens the channel to Bob.
|
||||||
|
pendingChan := ht.OpenChannelAssertPending(alice, bob, params)
|
||||||
|
|
||||||
|
// We'll create the channel point to be able to close the channel once
|
||||||
|
// our test is done.
|
||||||
|
chanPoint := &lnrpc.ChannelPoint{
|
||||||
|
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
|
||||||
|
FundingTxidBytes: pendingChan.Txid,
|
||||||
|
},
|
||||||
|
OutputIndex: pendingChan.OutputIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We disconnect and reconnect Alice and Bob before the channel is
|
||||||
|
// confirmed. Our expectation is that the channel is active once the
|
||||||
|
// channel is confirmed.
|
||||||
|
ht.DisconnectNodes(alice, bob)
|
||||||
|
ht.EnsureConnected(alice, bob)
|
||||||
|
|
||||||
|
// Mine six blocks to confirm the channel funding transaction.
|
||||||
|
ht.MineBlocksAndAssertNumTxes(6, 1)
|
||||||
|
|
||||||
|
// Verify that Alice sees an active channel to Bob.
|
||||||
|
ht.AssertChannelActive(alice, chanPoint)
|
||||||
|
|
||||||
|
// Our test is done and Alice closes her channel to Bob.
|
||||||
|
ht.CloseChannel(alice, chanPoint)
|
||||||
|
}
|
||||||
@@ -352,6 +352,31 @@ func (h *HarnessTest) AssertTopologyChannelOpen(hn *node.HarnessNode,
|
|||||||
func (h *HarnessTest) AssertChannelExists(hn *node.HarnessNode,
|
func (h *HarnessTest) AssertChannelExists(hn *node.HarnessNode,
|
||||||
cp *lnrpc.ChannelPoint) *lnrpc.Channel {
|
cp *lnrpc.ChannelPoint) *lnrpc.Channel {
|
||||||
|
|
||||||
|
return h.assertChannelStatus(hn, cp, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssertChannelActive checks if a channel identified by the specified channel
|
||||||
|
// point is active.
|
||||||
|
func (h *HarnessTest) AssertChannelActive(hn *node.HarnessNode,
|
||||||
|
cp *lnrpc.ChannelPoint) *lnrpc.Channel {
|
||||||
|
|
||||||
|
return h.assertChannelStatus(hn, cp, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssertChannelInactive checks if a channel identified by the specified channel
|
||||||
|
// point is inactive.
|
||||||
|
func (h *HarnessTest) AssertChannelInactive(hn *node.HarnessNode,
|
||||||
|
cp *lnrpc.ChannelPoint) *lnrpc.Channel {
|
||||||
|
|
||||||
|
return h.assertChannelStatus(hn, cp, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertChannelStatus asserts that a channel identified by the specified
|
||||||
|
// channel point exists from the point-of-view of the node and that it is either
|
||||||
|
// active or inactive depending on the value of the active parameter.
|
||||||
|
func (h *HarnessTest) assertChannelStatus(hn *node.HarnessNode,
|
||||||
|
cp *lnrpc.ChannelPoint, active bool) *lnrpc.Channel {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
channel *lnrpc.Channel
|
channel *lnrpc.Channel
|
||||||
err error
|
err error
|
||||||
@@ -364,11 +389,12 @@ func (h *HarnessTest) AssertChannelExists(hn *node.HarnessNode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the channel is active, exit early if it is.
|
// Check whether the channel is active, exit early if it is.
|
||||||
if channel.Active {
|
if channel.Active == active {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("channel point not active")
|
return fmt.Errorf("expected channel_active=%v, got %v",
|
||||||
|
active, channel.Active)
|
||||||
}, DefaultTimeout)
|
}, DefaultTimeout)
|
||||||
|
|
||||||
require.NoErrorf(h, err, "%s: timeout checking for channel point: %v",
|
require.NoErrorf(h, err, "%s: timeout checking for channel point: %v",
|
||||||
|
|||||||
+30
-4
@@ -1344,6 +1344,9 @@ type LightningChannel struct {
|
|||||||
// fundingOutput is the funding output (script+value).
|
// fundingOutput is the funding output (script+value).
|
||||||
fundingOutput wire.TxOut
|
fundingOutput wire.TxOut
|
||||||
|
|
||||||
|
// opts is the set of options that channel was initialized with.
|
||||||
|
opts *channelOpts
|
||||||
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1351,6 +1354,14 @@ type LightningChannel struct {
|
|||||||
// is created.
|
// is created.
|
||||||
type ChannelOpt func(*channelOpts)
|
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
|
// WithLocalMusigNonces is used to bind an existing verification/local nonce to
|
||||||
// a new channel.
|
// a new channel.
|
||||||
func WithLocalMusigNonces(nonce *musig2.Nonces) ChannelOpt {
|
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.
|
// WithSkipNonceInit is used to modify the way nonces are handled during
|
||||||
type channelOpts struct {
|
// channel initialization for taproot channels. If this option is specified,
|
||||||
localNonce *musig2.Nonces
|
// then when we receive the chan reest message from the remote party, we won't
|
||||||
remoteNonce *musig2.Nonces
|
// 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.
|
// 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,
|
RemoteFundingKey: state.RemoteChanCfg.MultiSigKey.PubKey,
|
||||||
taprootNonceProducer: taprootNonceProducer,
|
taprootNonceProducer: taprootNonceProducer,
|
||||||
log: build.NewPrefixLog(logPrefix, walletLog),
|
log: build.NewPrefixLog(logPrefix, walletLog),
|
||||||
|
opts: opts,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@@ -4263,6 +4280,12 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
|
|||||||
"not sent")
|
"not sent")
|
||||||
|
|
||||||
case lc.channelState.ChanType.IsTaproot() && msg.LocalNonce != nil:
|
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{
|
err := lc.InitRemoteMusigNonces(&musig2.Nonces{
|
||||||
PubNonce: *msg.LocalNonce,
|
PubNonce: *msg.LocalNonce,
|
||||||
})
|
})
|
||||||
@@ -8763,6 +8786,9 @@ func (lc *LightningChannel) InitRemoteMusigNonces(remoteNonce *musig2.Nonces,
|
|||||||
|
|
||||||
lc.pendingVerificationNonce = nil
|
lc.pendingVerificationNonce = nil
|
||||||
|
|
||||||
|
lc.opts.localNonce = nil
|
||||||
|
lc.opts.remoteNonce = nil
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-11
@@ -3824,17 +3824,6 @@ func (p *Brontide) addActiveChannel(c *lnpeer.NewChannel) error {
|
|||||||
chanPoint := &c.FundingOutpoint
|
chanPoint := &c.FundingOutpoint
|
||||||
chanID := lnwire.NewChanIDFromOutPoint(chanPoint)
|
chanID := lnwire.NewChanIDFromOutPoint(chanPoint)
|
||||||
|
|
||||||
// If not already active, we'll add this channel to the set of active
|
|
||||||
// channels, so we can look it up later easily according to its channel
|
|
||||||
// ID.
|
|
||||||
lnChan, err := lnwallet.NewLightningChannel(
|
|
||||||
p.cfg.Signer, c.OpenChannel,
|
|
||||||
p.cfg.SigPool, c.ChanOpts...,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to create LightningChannel: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we've reached this point, there are two possible scenarios. If
|
// If we've reached this point, there are two possible scenarios. If
|
||||||
// the channel was in the active channels map as nil, then it was
|
// the channel was in the active channels map as nil, then it was
|
||||||
// loaded from disk and we need to send reestablish. Else, it was not
|
// loaded from disk and we need to send reestablish. Else, it was not
|
||||||
@@ -3842,6 +3831,24 @@ func (p *Brontide) addActiveChannel(c *lnpeer.NewChannel) error {
|
|||||||
// fresh channel.
|
// fresh channel.
|
||||||
shouldReestablish := p.isLoadedFromDisk(chanID)
|
shouldReestablish := p.isLoadedFromDisk(chanID)
|
||||||
|
|
||||||
|
chanOpts := c.ChanOpts
|
||||||
|
if shouldReestablish {
|
||||||
|
// If we have to do the reestablish dance for this channel,
|
||||||
|
// ensure that we don't try to call InitRemoteMusigNonces twice
|
||||||
|
// by calling SkipNonceInit.
|
||||||
|
chanOpts = append(chanOpts, lnwallet.WithSkipNonceInit())
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not already active, we'll add this channel to the set of active
|
||||||
|
// channels, so we can look it up later easily according to its channel
|
||||||
|
// ID.
|
||||||
|
lnChan, err := lnwallet.NewLightningChannel(
|
||||||
|
p.cfg.Signer, c.OpenChannel, p.cfg.SigPool, chanOpts...,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create LightningChannel: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Store the channel in the activeChannels map.
|
// Store the channel in the activeChannels map.
|
||||||
p.activeChannels.Store(chanID, lnChan)
|
p.activeChannels.Store(chanID, lnChan)
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user