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 { 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,
scriptInfo.ScriptTree,
)
signDesc.ControlBlock, err = ctrlBlock.ToBytes()
if err != nil {
return nil, err
}
}
return &IncomingHtlcResolution{ return &IncomingHtlcResolution{
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
} }
// Otherwise, we'll need to go to the second level to sweep this HTLC. // Otherwise, we'll need to go to the second level to sweep this HTLC.
//
// First, we'll reconstruct the original HTLC success transaction, // First, we'll reconstruct the original HTLC success transaction,
// taking into account the fee rate used. // taking into account the fee rate used.
htlcFee := HtlcSuccessFee(chanType, feePerKw) 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 // Once we've created the second-level transaction, we'll generate the
// SignDesc needed spend the HTLC output using the success transaction. // SignDesc needed spend the HTLC output using the success transaction.
txOut := commitTx.TxOut[htlc.OutputIndex] txOut := commitTx.TxOut[htlc.OutputIndex]
prevFetcher := txscript.NewCannedPrevOutputFetcher(
txOut.PkScript, txOut.Value,
)
hashCache := txscript.NewTxSigHashes(successTx, prevFetcher)
successSignDesc := input.SignDescriptor{ successSignDesc := 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(successTx), 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
} }
@ -6838,12 +6857,36 @@ func newIncomingHtlcResolution(signer input.Signer,
// the success transaction. Don't specify the preimage yet. The preimage // the success transaction. Don't specify the preimage yet. The preimage
// will be supplied by the contract resolver, either directly or when it // will be supplied by the contract resolver, either directly or when it
// becomes known. // becomes known.
var successWitness wire.TxWitness
sigHashType := HtlcSigHashType(chanType) sigHashType := HtlcSigHashType(chanType)
successWitness, err := input.ReceiverHtlcSpendRedeem( if chanType.IsTaproot() {
htlcSig, sigHashType, nil, signer, &successSignDesc, successTx, // TODO(roasbeef): make sure default elsewhere
) successSignDesc.HashType = txscript.SigHashDefault
if err != nil { successSignDesc.SignMethod = input.TaprootScriptSpendSignMethod
return nil, err
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 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 // Finally, we'll generate the script that the second-level transaction
// creates so we can generate the proper signDesc to sweep it after the // creates so we can generate the proper signDesc to sweep it after the
// CSV delay has passed. // CSV delay has passed.
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
}
// TODO(roasbeef): conslidate logic to reduce vertical noise
} }
localDelayTweak := input.SingleTweakBytes( localDelayTweak := input.SingleTweakBytes(
@ -6883,7 +6958,9 @@ func newIncomingHtlcResolution(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
} }
@ -6956,7 +7033,8 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
ourCommit, isCommitFromInitiator, chanType, ourCommit, isCommitFromInitiator, chanType,
) )
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("incoming resolution "+
"failed: %v", err)
} }
incomingResolutions = append(incomingResolutions, *ihr) incomingResolutions = append(incomingResolutions, *ihr)
@ -6969,7 +7047,8 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
isCommitFromInitiator, chanType, isCommitFromInitiator, chanType,
) )
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("outgoing resolution "+
"failed: %v", err)
} }
outgoingResolutions = append(outgoingResolutions, *ohr) outgoingResolutions = append(outgoingResolutions, *ohr)