lnwallet: update newOutgoingHtlcResolution for taproot chans

For taproot channels, we need to thread through the control block in the
sign descriptor. We also ensure that the proper sign method is set. We
leverage the new input.Signature generalization be able to support
handling both schnorr and ECDSA signatures for the second level output.
This commit is contained in:
Olaoluwa Osuntokun 2023-03-01 21:42:44 -08:00
parent ee59e3f181
commit a0a3c7aa89
No known key found for this signature in database
GPG Key ID: 3BBD59E99B280306

View File

@ -6563,20 +6563,34 @@ func newOutgoingHtlcResolution(signer input.Signer,
if !localCommit { if !localCommit {
// With the script generated, we can completely populated the // With the script generated, we can completely populated the
// SignDescriptor needed to sweep the output. // SignDescriptor needed to sweep the output.
signDesc := input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcWitnessScript,
Output: &wire.TxOut{
PkScript: htlcPkScript,
Value: int64(htlc.Amt.ToSatoshis()),
},
HashType: txscript.SigHashAll,
}
if chanType.IsTaproot() {
signDesc.SignMethod = input.TaprootScriptSpendSignMethod
ctrlBlock := input.MakeTaprootCtrlBlock(
htlcWitnessScript, keyRing.RevocationKey,
htlcScriptInfo.ScriptTree,
)
signDesc.ControlBlock, err = ctrlBlock.ToBytes()
if err != nil {
return nil, err
}
}
return &OutgoingHtlcResolution{ return &OutgoingHtlcResolution{
Expiry: htlc.RefundTimeout, Expiry: htlc.RefundTimeout,
ClaimOutpoint: op, ClaimOutpoint: op,
SweepSignDesc: input.SignDescriptor{ SweepSignDesc: signDesc,
KeyDesc: localChanCfg.HtlcBasePoint, CsvDelay: HtlcSecondLevelInputSequence(chanType),
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcWitnessScript,
Output: &wire.TxOut{
PkScript: htlcPkScript,
Value: int64(htlc.Amt.ToSatoshis()),
},
HashType: txscript.SigHashAll,
},
CsvDelay: HtlcSecondLevelInputSequence(chanType),
}, nil }, nil
} }
@ -6604,17 +6618,22 @@ func newOutgoingHtlcResolution(signer input.Signer,
// that's capable of generating the signature required to spend the // that's capable of generating the signature required to spend the
// HTLC output using the timeout transaction. // HTLC output using the timeout transaction.
txOut := commitTx.TxOut[htlc.OutputIndex] txOut := commitTx.TxOut[htlc.OutputIndex]
prevFetcher := txscript.NewCannedPrevOutputFetcher(
txOut.PkScript, txOut.Value,
)
hashCache := txscript.NewTxSigHashes(timeoutTx, prevFetcher)
timeoutSignDesc := input.SignDescriptor{ timeoutSignDesc := input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint, KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak, SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcWitnessScript, WitnessScript: htlcWitnessScript,
Output: txOut, Output: txOut,
HashType: txscript.SigHashAll, HashType: txscript.SigHashAll,
SigHashes: input.NewTxSigHashesV0Only(timeoutTx), PrevOutputFetcher: prevFetcher,
InputIndex: 0, SigHashes: hashCache,
InputIndex: 0,
} }
htlcSig, err := ecdsa.ParseDERSignature(htlc.Signature) htlcSig, err := input.ParseSignature(htlc.Signature)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -6622,12 +6641,38 @@ func newOutgoingHtlcResolution(signer input.Signer,
// With the sign desc created, we can now construct the full witness // With the sign desc created, we can now construct the full witness
// for the timeout transaction, and populate it as well. // for the timeout transaction, and populate it as well.
sigHashType := HtlcSigHashType(chanType) sigHashType := HtlcSigHashType(chanType)
timeoutWitness, err := input.SenderHtlcSpendTimeout( var timeoutWitness wire.TxWitness
htlcSig, sigHashType, signer, &timeoutSignDesc, timeoutTx, if chanType.IsTaproot() {
) // TODO(roasbeef): make sure default elsewhere
timeoutSignDesc.SignMethod = input.TaprootScriptSpendSignMethod
timeoutSignDesc.HashType = txscript.SigHashDefault
timeoutWitness, err = input.SenderHTLCScriptTaprootTimeout(
htlcSig, sigHashType, signer, &timeoutSignDesc,
timeoutTx, keyRing.RevocationKey,
htlcScriptInfo.ScriptTree,
)
if err != nil {
return nil, err
}
// The control block is always the final element of the witness
// stack. We set this here as eventually the sweeper will need
// to re-sign, so it needs the isolated control block.
//
// TODO(roasbeef): move this into input.go?
ctlrBlkIdx := len(timeoutWitness) - 1
timeoutSignDesc.ControlBlock = timeoutWitness[ctlrBlkIdx]
} else {
timeoutWitness, err = input.SenderHtlcSpendTimeout(
htlcSig, sigHashType, signer, &timeoutSignDesc,
timeoutTx,
)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
timeoutTx.TxIn[0].Witness = timeoutWitness timeoutTx.TxIn[0].Witness = timeoutWitness
// If this is an anchor type channel, the sign details will let us // If this is an anchor type channel, the sign details will let us
@ -6639,12 +6684,42 @@ func newOutgoingHtlcResolution(signer input.Signer,
// Finally, we'll generate the script output that the timeout // Finally, we'll generate the script output that the timeout
// transaction creates so we can generate the signDesc required to // transaction creates so we can generate the signDesc required to
// complete the claim process after a delay period. // complete the claim process after a delay period.
htlcSweepScript, err := SecondLevelHtlcScript( var (
chanType, isCommitFromInitiator, keyRing.RevocationKey, htlcSweepScript *ScriptInfo
keyRing.ToLocalKey, csvDelay, leaseExpiry, signMethod input.SignMethod
ctrlBlock []byte
) )
if err != nil { if !chanType.IsTaproot() {
return nil, err htlcSweepScript, err = SecondLevelHtlcScript(
chanType, isCommitFromInitiator, keyRing.RevocationKey,
keyRing.ToLocalKey, csvDelay, leaseExpiry,
)
if err != nil {
return nil, err
}
} else {
secondLevelScriptTree, err := input.TaprootSecondLevelScriptTree(
keyRing.RevocationKey, keyRing.ToLocalKey, csvDelay,
)
if err != nil {
return nil, err
}
htlcSweepScript = &ScriptInfo{
PkScript: secondLevelScriptTree.PkScript,
WitnessScript: secondLevelScriptTree.SuccessTapLeaf.Script,
}
signMethod = input.TaprootScriptSpendSignMethod
controlBlock := input.MakeTaprootCtrlBlock(
htlcSweepScript.WitnessScript, keyRing.RevocationKey,
secondLevelScriptTree.TapscriptTree,
)
ctrlBlock, err = controlBlock.ToBytes()
if err != nil {
return nil, err
}
} }
localDelayTweak := input.SingleTweakBytes( localDelayTweak := input.SingleTweakBytes(
@ -6667,7 +6742,9 @@ func newOutgoingHtlcResolution(signer input.Signer,
PkScript: htlcSweepScript.PkScript, PkScript: htlcSweepScript.PkScript,
Value: int64(secondLevelOutputAmt), Value: int64(secondLevelOutputAmt),
}, },
HashType: txscript.SigHashAll, HashType: txscript.SigHashAll,
SignMethod: signMethod,
ControlBlock: ctrlBlock,
}, },
}, nil }, nil
} }