lnwallet: add tapscript tree to ScriptInfo

In this commit, we add the tapscript tree to the ScriptInfo struct, as
in many cases the caller needs the tree in order to generate the control
block or obtain the taptweak which is needed to spend revoked outputs.
This commit is contained in:
Olaoluwa Osuntokun 2023-03-01 21:38:53 -08:00
parent a74c30fbdd
commit a128b74dc1
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306
2 changed files with 59 additions and 29 deletions

View file

@ -801,7 +801,6 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
ourP2WSH, theirP2WSH []byte
ourWitnessScript, theirWitnessScript []byte
pd PaymentDescriptor
err error
chanType = lc.channelState.ChanType
)
@ -815,26 +814,30 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
htlc.Amt.ToSatoshis(), lc.channelState.LocalChanCfg.DustLimit,
)
if !isDustLocal && localCommitKeys != nil {
ourP2WSH, ourWitnessScript, err = genHtlcScript(
scriptInfo, err := genHtlcScript(
chanType, htlc.Incoming, true, htlc.RefundTimeout,
htlc.RHash, localCommitKeys,
)
if err != nil {
return pd, err
}
ourP2WSH = scriptInfo.PkScript
ourWitnessScript = scriptInfo.WitnessScript
}
isDustRemote := HtlcIsDust(
chanType, htlc.Incoming, false, feeRate,
htlc.Amt.ToSatoshis(), lc.channelState.RemoteChanCfg.DustLimit,
)
if !isDustRemote && remoteCommitKeys != nil {
theirP2WSH, theirWitnessScript, err = genHtlcScript(
scriptInfo, err := genHtlcScript(
chanType, htlc.Incoming, false, htlc.RefundTimeout,
htlc.RHash, remoteCommitKeys,
)
if err != nil {
return pd, err
}
theirP2WSH = scriptInfo.PkScript
theirWitnessScript = scriptInfo.WitnessScript
}
// Reconstruct the proper local/remote output indexes from the HTLC's
@ -1563,7 +1566,7 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
wireMsg.Amount.ToSatoshis(), remoteDustLimit,
)
if !isDustRemote {
theirP2WSH, theirWitnessScript, err := genHtlcScript(
scriptInfo, err := genHtlcScript(
lc.channelState.ChanType, false, false,
wireMsg.Expiry, wireMsg.PaymentHash,
remoteCommitKeys,
@ -1572,8 +1575,8 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
return nil, err
}
pd.theirPkScript = theirP2WSH
pd.theirWitnessScript = theirWitnessScript
pd.theirPkScript = scriptInfo.PkScript
pd.theirWitnessScript = scriptInfo.WitnessScript
}
// For HTLC's we're offered we'll fetch the original offered HTLC
@ -2572,7 +2575,7 @@ func createHtlcRetribution(chanState *channeldb.OpenChannel,
// HTLC script. Otherwise, is this was an outgoing HTLC that we sent,
// then from the PoV of the remote commitment state, they're the
// receiver of this HTLC.
htlcPkScript, htlcWitnessScript, err := genHtlcScript(
scriptInfo, err := genHtlcScript(
chanState.ChanType, htlc.Incoming, false,
htlc.RefundTimeout, htlc.RHash, keyRing,
)
@ -2585,9 +2588,9 @@ func createHtlcRetribution(chanState *channeldb.OpenChannel,
KeyDesc: chanState.LocalChanCfg.
RevocationBasePoint,
DoubleTweak: commitmentSecret,
WitnessScript: htlcWitnessScript,
WitnessScript: scriptInfo.WitnessScript,
Output: &wire.TxOut{
PkScript: htlcPkScript,
PkScript: scriptInfo.PkScript,
Value: int64(htlc.Amt),
},
HashType: txscript.SigHashAll,
@ -6542,15 +6545,17 @@ func newOutgoingHtlcResolution(signer input.Signer,
Index: uint32(htlc.OutputIndex),
}
// First, we'll re-generate the script used to send the HTLC to
// the remote party within their commitment transaction.
htlcScriptHash, htlcScript, err := genHtlcScript(
// First, we'll re-generate the script used to send the HTLC to the
// remote party within their commitment transaction.
htlcScriptInfo, err := genHtlcScript(
chanType, false, localCommit, htlc.RefundTimeout, htlc.RHash,
keyRing,
)
if err != nil {
return nil, err
}
htlcPkScript := htlcScriptInfo.PkScript
htlcWitnessScript := htlcScriptInfo.WitnessScript
// If we're spending this HTLC output from the remote node's
// commitment, then we won't need to go to the second level as our
@ -6564,9 +6569,9 @@ func newOutgoingHtlcResolution(signer input.Signer,
SweepSignDesc: input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcScript,
WitnessScript: htlcWitnessScript,
Output: &wire.TxOut{
PkScript: htlcScriptHash,
PkScript: htlcPkScript,
Value: int64(htlc.Amt.ToSatoshis()),
},
HashType: txscript.SigHashAll,
@ -6602,7 +6607,7 @@ func newOutgoingHtlcResolution(signer input.Signer,
timeoutSignDesc := input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcScript,
WitnessScript: htlcWitnessScript,
Output: txOut,
HashType: txscript.SigHashAll,
SigHashes: input.NewTxSigHashesV0Only(timeoutTx),
@ -6688,7 +6693,7 @@ func newIncomingHtlcResolution(signer input.Signer,
// First, we'll re-generate the script the remote party used to
// send the HTLC to us in their commitment transaction.
htlcScriptHash, htlcScript, err := genHtlcScript(
scriptInfo, err := genHtlcScript(
chanType, true, localCommit, htlc.RefundTimeout, htlc.RHash,
keyRing,
)
@ -6696,6 +6701,9 @@ func newIncomingHtlcResolution(signer input.Signer,
return nil, err
}
htlcPkScript := scriptInfo.PkScript
htlcWitnessScript := scriptInfo.WitnessScript
// If we're spending this output from the remote node's commitment,
// then we can skip the second layer and spend the output directly.
if !localCommit {
@ -6706,9 +6714,9 @@ func newIncomingHtlcResolution(signer input.Signer,
SweepSignDesc: input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcScript,
WitnessScript: htlcWitnessScript,
Output: &wire.TxOut{
PkScript: htlcScriptHash,
PkScript: htlcPkScript,
Value: int64(htlc.Amt.ToSatoshis()),
},
HashType: txscript.SigHashAll,
@ -6737,7 +6745,7 @@ func newIncomingHtlcResolution(signer input.Signer,
successSignDesc := input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcScript,
WitnessScript: htlcWitnessScript,
Output: txOut,
HashType: txscript.SigHashAll,
SigHashes: input.NewTxSigHashesV0Only(successTx),

View file

@ -190,6 +190,10 @@ type ScriptInfo struct {
// output is being signed. For p2wkh it should be set equal to the
// PkScript.
WitnessScript []byte
// ScriptTree is the script tree that stores all the scripts that are
// committed to by the above PkScript, if it's a P2TR script template.
ScriptTree *txscript.IndexedTapScriptTree
}
// CommitScriptToSelf constructs the public key script for the output on the
@ -225,9 +229,11 @@ func CommitScriptToSelf(chanType channeldb.ChannelType, initiator bool,
"pkscript: %w", err)
}
// TODO(rosabeef): recator to be able to get script key
return &ScriptInfo{
WitnessScript: toLocalScriptTree.SettleLeaf.Script,
PkScript: toLocalPkScript,
ScriptTree: toLocalScriptTree.TapscriptTree,
}, nil
// If we are the initiator of a leased channel, then we have an
@ -310,20 +316,24 @@ func CommitScriptToRemote(chanType channeldb.ChannelType, initiator bool,
// we use a NUMS key to force the remote party to take a script path,
// with the sole tap leaf enforcing the 1 CSV delay.
case chanType.IsTaproot():
toRemoteKey, err := input.TaprootCommitScriptToRemote(
toRemoteScriptTree, err := input.NewRemoteCommitScriptTree(
remoteKey,
)
if err != nil {
return nil, 0, err
}
toRemotePkScript, err := input.PayToTaprootScript(toRemoteKey)
toRemotePkScript, err := input.PayToTaprootScript(
toRemoteScriptTree.TaprootKey,
)
if err != nil {
return nil, 0, err
}
return &ScriptInfo{
PkScript: toRemotePkScript,
WitnessScript: toRemoteScriptTree.SettleLeaf.Script,
PkScript: toRemotePkScript,
ScriptTree: toRemoteScriptTree.TapscriptTree,
}, 1, nil
// If this channel type has anchors, we derive the delayed to_remote
@ -533,20 +543,23 @@ func CommitScriptAnchors(chanType channeldb.ChannelType,
// since these are fully revealed once the commitment hits the chain.
case chanType.IsTaproot():
anchorScript = func(key *btcec.PublicKey) (*ScriptInfo, error) {
anchorKey, err := input.TaprootOutputKeyAnchor(key)
anchorScriptTree, err := input.NewAnchorScriptTree(
key,
)
if err != nil {
return nil, err
}
anchorPkScript, err := input.PayToTaprootScript(
anchorKey,
anchorScriptTree.TaprootKey,
)
if err != nil {
return nil, err
}
return &ScriptInfo{
PkScript: anchorPkScript,
PkScript: anchorPkScript,
ScriptTree: anchorScriptTree.TapscriptTree,
}, nil
}
@ -1078,6 +1091,7 @@ func genTaprootHtlcScript(isIncoming, ourCommit bool, timeout uint32,
var (
taprootKey *btcec.PublicKey
secondLevelScript []byte
tapScriptTree *txscript.IndexedTapScriptTree
)
// Generate the proper redeem scripts for the HTLC output modified by
@ -1096,6 +1110,7 @@ func genTaprootHtlcScript(isIncoming, ourCommit bool, timeout uint32,
return nil, err
}
tapScriptTree = scriptTree.TapscriptTree
taprootKey = scriptTree.TaprootKey
// As this is an HTLC on our commitment transaction, the second
@ -1116,6 +1131,7 @@ func genTaprootHtlcScript(isIncoming, ourCommit bool, timeout uint32,
return nil, err
}
tapScriptTree = scriptTree.TapscriptTree
taprootKey = scriptTree.TaprootKey
// In this case, this is an incoming HTLC on the commitment
@ -1136,6 +1152,7 @@ func genTaprootHtlcScript(isIncoming, ourCommit bool, timeout uint32,
return nil, err
}
tapScriptTree = scriptTree.TapscriptTree
taprootKey = scriptTree.TaprootKey
// This is an outgoing HTLC on our commitment transaction, so
@ -1155,6 +1172,7 @@ func genTaprootHtlcScript(isIncoming, ourCommit bool, timeout uint32,
return nil, err
}
tapScriptTree = scriptTree.TapscriptTree
taprootKey = scriptTree.TaprootKey
// This is an outgoing HTLC on the remote party's commitment
@ -1174,6 +1192,7 @@ func genTaprootHtlcScript(isIncoming, ourCommit bool, timeout uint32,
return &ScriptInfo{
PkScript: p2trOutput,
WitnessScript: secondLevelScript,
ScriptTree: tapScriptTree,
}, nil
}
@ -1182,7 +1201,7 @@ func genTaprootHtlcScript(isIncoming, ourCommit bool, timeout uint32,
// HTLC is being applied to their commitment transaction or ours.
func genHtlcScript(chanType channeldb.ChannelType, isIncoming, ourCommit bool,
timeout uint32, rHash [32]byte,
keyRing *CommitmentKeyRing) ([]byte, []byte, error) {
keyRing *CommitmentKeyRing) (*ScriptInfo, error) {
var (
scriptInfo *ScriptInfo
@ -1200,10 +1219,10 @@ func genHtlcScript(chanType channeldb.ChannelType, isIncoming, ourCommit bool,
)
}
if err != nil {
return nil, nil, err
return nil, err
}
return scriptInfo.PkScript, scriptInfo.WitnessScript, nil
return scriptInfo, nil
}
// addHTLC adds a new HTLC to the passed commitment transaction. One of four
@ -1220,13 +1239,16 @@ func addHTLC(commitTx *wire.MsgTx, ourCommit bool,
timeout := paymentDesc.Timeout
rHash := paymentDesc.RHash
witnessProgram, witnessScript, err := genHtlcScript(
scriptInfo, err := genHtlcScript(
chanType, isIncoming, ourCommit, timeout, rHash, keyRing,
)
if err != nil {
return err
}
witnessProgram := scriptInfo.PkScript
witnessScript := scriptInfo.WitnessScript
// Add the new HTLC outputs to the respective commitment transactions.
amountPending := int64(paymentDesc.Amount.ToSatoshis())
commitTx.AddTxOut(wire.NewTxOut(amountPending, witnessProgram))