lnwallet: update newIncomingHtlcResolution for taproot chans

Similar to the outgoing resolutions, the main change here is ensuring
the sign method and control block are properly set for the various spend
types.
This commit is contained in:
Olaoluwa Osuntokun 2023-03-01 21:43:37 -08:00
parent a0a3c7aa89
commit ad5305b99c
No known key found for this signature in database
GPG Key ID: 3BBD59E99B280306

View File

@ -6786,24 +6786,38 @@ func newIncomingHtlcResolution(signer input.Signer,
if !localCommit {
// With the script generated, we can completely populated the
// 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,
scriptInfo.ScriptTree,
)
signDesc.ControlBlock, err = ctrlBlock.ToBytes()
if err != nil {
return nil, err
}
}
return &IncomingHtlcResolution{
ClaimOutpoint: op,
SweepSignDesc: input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcWitnessScript,
Output: &wire.TxOut{
PkScript: htlcPkScript,
Value: int64(htlc.Amt.ToSatoshis()),
},
HashType: txscript.SigHashAll,
},
CsvDelay: HtlcSecondLevelInputSequence(chanType),
SweepSignDesc: signDesc,
CsvDelay: HtlcSecondLevelInputSequence(chanType),
}, nil
}
// Otherwise, we'll need to go to the second level to sweep this HTLC.
//
// First, we'll reconstruct the original HTLC success transaction,
// taking into account the fee rate used.
htlcFee := HtlcSuccessFee(chanType, feePerKw)
@ -6819,17 +6833,22 @@ func newIncomingHtlcResolution(signer input.Signer,
// Once we've created the second-level transaction, we'll generate the
// SignDesc needed spend the HTLC output using the success transaction.
txOut := commitTx.TxOut[htlc.OutputIndex]
prevFetcher := txscript.NewCannedPrevOutputFetcher(
txOut.PkScript, txOut.Value,
)
hashCache := txscript.NewTxSigHashes(successTx, prevFetcher)
successSignDesc := input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcWitnessScript,
Output: txOut,
HashType: txscript.SigHashAll,
SigHashes: input.NewTxSigHashesV0Only(successTx),
InputIndex: 0,
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcWitnessScript,
Output: txOut,
HashType: txscript.SigHashAll,
PrevOutputFetcher: prevFetcher,
SigHashes: hashCache,
InputIndex: 0,
}
htlcSig, err := ecdsa.ParseDERSignature(htlc.Signature)
htlcSig, err := input.ParseSignature(htlc.Signature)
if err != nil {
return nil, err
}
@ -6838,12 +6857,36 @@ func newIncomingHtlcResolution(signer input.Signer,
// the success transaction. Don't specify the preimage yet. The preimage
// will be supplied by the contract resolver, either directly or when it
// becomes known.
var successWitness wire.TxWitness
sigHashType := HtlcSigHashType(chanType)
successWitness, err := input.ReceiverHtlcSpendRedeem(
htlcSig, sigHashType, nil, signer, &successSignDesc, successTx,
)
if err != nil {
return nil, err
if chanType.IsTaproot() {
// TODO(roasbeef): make sure default elsewhere
successSignDesc.HashType = txscript.SigHashDefault
successSignDesc.SignMethod = input.TaprootScriptSpendSignMethod
successWitness, err = input.ReceiverHTLCScriptTaprootRedeem(
htlcSig, sigHashType, nil, signer, &successSignDesc,
successTx, keyRing.RevocationKey, scriptInfo.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(successWitness) - 1
successSignDesc.ControlBlock = successWitness[ctlrBlkIdx]
} else {
successWitness, err = input.ReceiverHtlcSpendRedeem(
htlcSig, sigHashType, nil, signer, &successSignDesc,
successTx,
)
if err != nil {
return nil, err
}
}
successTx.TxIn[0].Witness = successWitness
@ -6856,12 +6899,44 @@ func newIncomingHtlcResolution(signer input.Signer,
// Finally, we'll generate the script that the second-level transaction
// creates so we can generate the proper signDesc to sweep it after the
// CSV delay has passed.
htlcSweepScript, err := SecondLevelHtlcScript(
chanType, isCommitFromInitiator, keyRing.RevocationKey,
keyRing.ToLocalKey, csvDelay, leaseExpiry,
var (
htlcSweepScript *ScriptInfo
signMethod input.SignMethod
ctrlBlock []byte
)
if err != nil {
return nil, err
if !chanType.IsTaproot() {
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
}
// TODO(roasbeef): conslidate logic to reduce vertical noise
}
localDelayTweak := input.SingleTweakBytes(
@ -6883,7 +6958,9 @@ func newIncomingHtlcResolution(signer input.Signer,
PkScript: htlcSweepScript.PkScript,
Value: int64(secondLevelOutputAmt),
},
HashType: txscript.SigHashAll,
HashType: txscript.SigHashAll,
SignMethod: signMethod,
ControlBlock: ctrlBlock,
},
}, nil
}
@ -6956,7 +7033,8 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
ourCommit, isCommitFromInitiator, chanType,
)
if err != nil {
return nil, err
return nil, fmt.Errorf("incoming resolution "+
"failed: %v", err)
}
incomingResolutions = append(incomingResolutions, *ihr)
@ -6969,7 +7047,8 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
isCommitFromInitiator, chanType,
)
if err != nil {
return nil, err
return nil, fmt.Errorf("outgoing resolution "+
"failed: %v", err)
}
outgoingResolutions = append(outgoingResolutions, *ohr)