Skip to content

Commit 69a1cf4

Browse files
committed
lnwallet: ensure we re-sign retransmitted commits for taproot channels
In this commit, we fix an existing bug with the taproot channel type that can cause force closes if a peer disconnects while attempting to send the commitment signature. Before this commit, since the `PartialSig` we send is never committed to disk, the version read wouldn't contain the musig2 partial sig. We never write these signatures to disk, as each time we make a new session, we need to generate fresh nonces to avoid nonce-reuse. Due to the above interaction, if we went to re-send a signature after a disconnection, the `CommitSig` message we sent wouldn't actually contain a `PartialSigWithNonce`, causing a protocol error.
1 parent e8c5e7d commit 69a1cf4

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

lnwallet/channel.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4151,6 +4151,27 @@ func (lc *LightningChannel) SignNextCommitment() (*NewCommitState, error) {
41514151
}, nil
41524152
}
41534153

4154+
// resignMusigCommit is used to resign a commitment transaction for taproot
4155+
// channels when we need to retransmit a signature after a channel reestablish
4156+
// message. Taproot channels use musig2, which means we must use fresh nonces
4157+
// each time. After we receive the channel reestablish message, we learn the
4158+
// nonce we need to use for the remote party. As a result, we need to generate
4159+
// the partial signature again with the new nonce.
4160+
func (lc *LightningChannel) resignMusigCommit(commitTx *wire.MsgTx,
4161+
) (lnwire.OptPartialSigWithNonceTLV, error) {
4162+
4163+
remoteSession := lc.musigSessions.RemoteSession
4164+
musig, err := remoteSession.SignCommit(commitTx)
4165+
if err != nil {
4166+
var none lnwire.OptPartialSigWithNonceTLV
4167+
return none, err
4168+
}
4169+
4170+
partialSig := lnwire.MaybePartialSigWithNonce(musig.ToWireSig())
4171+
4172+
return partialSig, nil
4173+
}
4174+
41544175
// ProcessChanSyncMsg processes a ChannelReestablish message sent by the remote
41554176
// connection upon re establishment of our connection with them. This method
41564177
// will return a single message if we are currently out of sync, otherwise a
@@ -4428,12 +4449,23 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
44284449
commitUpdates = append(commitUpdates, logUpdate.UpdateMsg)
44294450
}
44304451

4452+
// If this is a taproot channel, then we need to regenerate the
4453+
// musig2 signature for the remote party, using their fresh
4454+
// nonce.
4455+
if lc.channelState.ChanType.IsTaproot() {
4456+
partialSig, err := lc.resignMusigCommit(
4457+
commitDiff.Commitment.CommitTx,
4458+
)
4459+
if err != nil {
4460+
return nil, nil, nil, err
4461+
}
4462+
4463+
commitDiff.CommitSig.PartialSig = partialSig
4464+
}
4465+
44314466
// With the batch of updates accumulated, we'll now re-send the
44324467
// original CommitSig message required to re-sync their remote
44334468
// commitment chain with our local version of their chain.
4434-
//
4435-
// TODO(roasbeef): need to re-sign commitment states w/
4436-
// fresh nonce
44374469
commitUpdates = append(commitUpdates, commitDiff.CommitSig)
44384470

44394471
// NOTE: If a revocation is not owed, then updates is empty.

0 commit comments

Comments
 (0)