lnwallet: update NewAnchorResolution to support taproot anchors

This commit is contained in:
Olaoluwa Osuntokun 2023-03-01 21:40:44 -08:00
parent a128b74dc1
commit ee59e3f181
No known key found for this signature in database
GPG Key ID: 3BBD59E99B280306
2 changed files with 70 additions and 16 deletions

View File

@ -885,7 +885,7 @@ func (c *chainWatcher) handlePossibleBreach(commitSpend *chainntnfs.SpendDetail,
// TODO(roasbeef): make keyring for taproot chans to pass in instead of // TODO(roasbeef): make keyring for taproot chans to pass in instead of
// nil // nil
anchorRes, err := lnwallet.NewAnchorResolution( anchorRes, err := lnwallet.NewAnchorResolution(
c.cfg.chanState, commitSpend.SpendingTx, nil, c.cfg.chanState, commitSpend.SpendingTx, nil, false,
) )
if err != nil { if err != nil {
return false, fmt.Errorf("unable to create anchor "+ return false, fmt.Errorf("unable to create anchor "+

View File

@ -6400,7 +6400,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
} }
anchorResolution, err := NewAnchorResolution( anchorResolution, err := NewAnchorResolution(
chanState, commitTxBroadcast, keyRing, chanState, commitTxBroadcast, keyRing, false,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -6992,7 +6992,8 @@ func (lc *LightningChannel) ForceClose() (*LocalForceCloseSummary, error) {
localCommitment.CommitHeight, localCommitment.CommitHeight,
) )
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("unable to gen force close "+
"summary: %w", err)
} }
// Set the channel state to indicate that the channel is now in a // Set the channel state to indicate that the channel is now in a
@ -7098,14 +7099,15 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel,
chanState.IsInitiator, leaseExpiry, chanState.IsInitiator, leaseExpiry,
) )
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("unable to gen htlc resolution: %w", err)
} }
anchorResolution, err := NewAnchorResolution( anchorResolution, err := NewAnchorResolution(
chanState, commitTx, keyRing, chanState, commitTx, keyRing, true,
) )
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("unable to gen anchor "+
"resolution: %w", err)
} }
return &LocalForceCloseSummary{ return &LocalForceCloseSummary{
@ -7386,7 +7388,7 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions,
) )
localRes, err := NewAnchorResolution( localRes, err := NewAnchorResolution(
lc.channelState, lc.channelState.LocalCommitment.CommitTx, lc.channelState, lc.channelState.LocalCommitment.CommitTx,
localKeyRing, localKeyRing, true,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -7401,7 +7403,7 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions,
) )
remoteRes, err := NewAnchorResolution( remoteRes, err := NewAnchorResolution(
lc.channelState, lc.channelState.RemoteCommitment.CommitTx, lc.channelState, lc.channelState.RemoteCommitment.CommitTx,
remoteKeyRing, remoteKeyRing, false,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -7423,7 +7425,7 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions,
remotePendingRes, err := NewAnchorResolution( remotePendingRes, err := NewAnchorResolution(
lc.channelState, lc.channelState,
remotePendingCommit.Commitment.CommitTx, remotePendingCommit.Commitment.CommitTx,
pendingRemoteKeyRing, pendingRemoteKeyRing, false,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -7437,26 +7439,34 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions,
// NewAnchorResolution returns the information that is required to sweep the // NewAnchorResolution returns the information that is required to sweep the
// local anchor. // local anchor.
func NewAnchorResolution(chanState *channeldb.OpenChannel, func NewAnchorResolution(chanState *channeldb.OpenChannel,
commitTx *wire.MsgTx, commitTx *wire.MsgTx, keyRing *CommitmentKeyRing,
keyRing *CommitmentKeyRing) (*AnchorResolution, error) { isLocalCommit bool) (*AnchorResolution, error) {
// Return nil resolution if the channel has no anchors. // Return nil resolution if the channel has no anchors.
if !chanState.ChanType.HasAnchors() { if !chanState.ChanType.HasAnchors() {
return nil, nil return nil, nil
} }
// Derive our local anchor script. // Derive our local anchor script. For taproot channels, rather than
localAnchor, _, err := CommitScriptAnchors( // use the same multi-sig key for both commitments, the anchor script
// will differ depending on if this is our local or remote
// commitment.
localAnchor, remoteAnchor, err := CommitScriptAnchors(
chanState.ChanType, &chanState.LocalChanCfg, chanState.ChanType, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, keyRing, &chanState.RemoteChanCfg, keyRing,
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
if chanState.ChanType.IsTaproot() && !isLocalCommit {
localAnchor, remoteAnchor = remoteAnchor, localAnchor
}
// Look up the script on the commitment transaction. It may not be // Look up the script on the commitment transaction. It may not be
// present if there is no output paying to us. // present if there is no output paying to us.
found, index := input.FindScriptOutputIndex(commitTx, localAnchor.PkScript) found, index := input.FindScriptOutputIndex(
commitTx, localAnchor.PkScript,
)
if !found { if !found {
return nil, nil return nil, nil
} }
@ -7477,12 +7487,56 @@ func NewAnchorResolution(chanState *channeldb.OpenChannel,
HashType: txscript.SigHashAll, HashType: txscript.SigHashAll,
} }
// For taproot outputs, we'll need to ensure that the proper sign
// method is used, and the tweak as well.
if chanState.ChanType.IsTaproot() {
signDesc.SignMethod = input.TaprootKeySpendSignMethod
signDesc.HashType = txscript.SigHashDefault
signDesc.PrevOutputFetcher = txscript.NewCannedPrevOutputFetcher(
localAnchor.PkScript, int64(anchorSize),
)
// For anchor outputs with taproot channels, the key desc is
// also different: we'll just re-use our local delay base point
// (which becomes our to local output).
if isLocalCommit {
// In addition to the sign method, we'll also need to
// ensure that the single tweak is set, as with the
// current formulation, we'll need to use two levels of
// tweaks: the normal LN tweak, and the tapscript
// tweak.
signDesc.SingleTweak = keyRing.LocalCommitKeyTweak
signDesc.KeyDesc = chanState.LocalChanCfg.DelayBasePoint
} else {
// When we're playing the force close of a remote
// commitment, as this is a "tweakless" channel type,
// we don't need a tweak value at all.
signDesc.KeyDesc = chanState.LocalChanCfg.PaymentBasePoint
}
// TODO(roasbeef): need to be payment point if remote, delay
// point otherwise?
// Finally, as this is a keyspend method, we'll need to also
// include the taptweak as well.
tapscriptRoot := localAnchor.ScriptTree.RootNode.TapHash()
signDesc.TapTweak = tapscriptRoot[:]
}
var witnessWeight int64
if chanState.ChanType.IsTaproot() {
witnessWeight = input.TaprootKeyPathWitnessSize
} else {
witnessWeight = input.WitnessCommitmentTxWeight
}
// Calculate commit tx weight. This commit tx doesn't yet include the // Calculate commit tx weight. This commit tx doesn't yet include the
// witness spending the funding output, so we add the (worst case) // witness spending the funding output, so we add the (worst case)
// weight for that too. // weight for that too.
utx := btcutil.NewTx(commitTx) utx := btcutil.NewTx(commitTx)
weight := blockchain.GetTransactionWeight(utx) + weight := blockchain.GetTransactionWeight(utx) + witnessWeight
input.WitnessCommitmentTxWeight
// Calculate commit tx fee. // Calculate commit tx fee.
fee := chanState.Capacity fee := chanState.Capacity