mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-05-03 16:30:18 +02:00
input: add tapscript utils for the sender HTLC script
Unlike the old HTLC scripts, we now need to handle the various control block interactions. As is, we opt to simply re-compute the entire tree when needed, as the tree only has two leaves.
This commit is contained in:
parent
734dc0f085
commit
7e7de11cfd
@ -492,6 +492,163 @@ func SenderHtlcSpendTimeout(receiverSig Signature,
|
|||||||
return witnessStack, nil
|
return witnessStack, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SenderHTLCTapLeafTimeout returns the full tapscript leaf for the timeout
|
||||||
|
// path of the sender HTLC. This is a small script that allows the sender to
|
||||||
|
// timeout the HTLC after a period of time:
|
||||||
|
//
|
||||||
|
// <local_key> OP_CHECKSIGVERIFY
|
||||||
|
// <remote_key> OP_CHECKSIG
|
||||||
|
func SenderHTLCTapLeafTimeout(senderHtlcKey,
|
||||||
|
receiverHtlcKey *btcec.PublicKey) (txscript.TapLeaf, error) {
|
||||||
|
|
||||||
|
builder := txscript.NewScriptBuilder()
|
||||||
|
|
||||||
|
builder.AddData(schnorr.SerializePubKey(senderHtlcKey))
|
||||||
|
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
|
||||||
|
builder.AddData(schnorr.SerializePubKey(receiverHtlcKey))
|
||||||
|
builder.AddOp(txscript.OP_CHECKSIG)
|
||||||
|
|
||||||
|
timeoutLeafScript, err := builder.Script()
|
||||||
|
if err != nil {
|
||||||
|
return txscript.TapLeaf{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return txscript.NewBaseTapLeaf(timeoutLeafScript), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SenderHTLCTapLeafSuccess returns the full tapscript leaf for the success
|
||||||
|
// path of the sender HTLC. This is a small script that allows the receiver to
|
||||||
|
// redeem the HTLC with a pre-image:
|
||||||
|
//
|
||||||
|
// OP_SIZE 32 OP_EQUALVERIFY OP_HASH160
|
||||||
|
// <RIPEMD160(payment_hash)> OP_EQUALVERIFY
|
||||||
|
// <remote_htlcpubkey> OP_CHECKSIG
|
||||||
|
// OP_CHECKSEQUENCEVERIFY
|
||||||
|
func SenderHTLCTapLeafSuccess(receiverHtlcKey *btcec.PublicKey,
|
||||||
|
paymentHash []byte) (txscript.TapLeaf, error) {
|
||||||
|
|
||||||
|
builder := txscript.NewScriptBuilder()
|
||||||
|
|
||||||
|
// Check that the pre-image is 32 bytes as required.
|
||||||
|
builder.AddOp(txscript.OP_SIZE)
|
||||||
|
builder.AddInt64(32)
|
||||||
|
builder.AddOp(txscript.OP_EQUALVERIFY)
|
||||||
|
|
||||||
|
// Check that the specified pre-images matches what we hard code into
|
||||||
|
// the script.
|
||||||
|
builder.AddOp(txscript.OP_HASH160)
|
||||||
|
builder.AddData(Ripemd160H(paymentHash))
|
||||||
|
builder.AddOp(txscript.OP_EQUALVERIFY)
|
||||||
|
|
||||||
|
// Verify the remote party's signature, then make them wait 1 block
|
||||||
|
// after confirmation to properly sweep.
|
||||||
|
builder.AddData(schnorr.SerializePubKey(receiverHtlcKey))
|
||||||
|
builder.AddOp(txscript.OP_CHECKSIG)
|
||||||
|
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||||
|
|
||||||
|
successLeafScript, err := builder.Script()
|
||||||
|
if err != nil {
|
||||||
|
return txscript.TapLeaf{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return txscript.NewBaseTapLeaf(successLeafScript), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HtlcScriptTree...
|
||||||
|
type HtlcScriptTree struct {
|
||||||
|
// TaprootKey...
|
||||||
|
TaprootKey *btcec.PublicKey
|
||||||
|
|
||||||
|
// SuccessTapLeaf...
|
||||||
|
SuccessTapLeaf txscript.TapLeaf
|
||||||
|
|
||||||
|
// TimeoutTapLeaf...
|
||||||
|
TimeoutTapLeaf txscript.TapLeaf
|
||||||
|
|
||||||
|
// TapscriptTree...
|
||||||
|
TapscriptTree *txscript.IndexedTapScriptTree
|
||||||
|
}
|
||||||
|
|
||||||
|
// senderHtlcTapScriptTree builds the tapscript tree which is used to anchor
|
||||||
|
// the HTLC key for HTLCs on the sender's commitment.
|
||||||
|
func senderHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
|
||||||
|
revokeKey *btcec.PublicKey, payHash []byte) (*HtlcScriptTree, error) {
|
||||||
|
|
||||||
|
// First, we'll obtain the tap leaves for both the success and timeout
|
||||||
|
// path.
|
||||||
|
successTapLeaf, err := SenderHTLCTapLeafSuccess(
|
||||||
|
receiverHtlcKey, payHash,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
timeoutTapLeaf, err := SenderHTLCTapLeafTimeout(
|
||||||
|
senderHtlcKey, receiverHtlcKey,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// With the two leaves obtained, we'll now make the tapscript tree,
|
||||||
|
// then obtain the root from that
|
||||||
|
tapscriptTree := txscript.AssembleTaprootScriptTree(
|
||||||
|
successTapLeaf, timeoutTapLeaf,
|
||||||
|
)
|
||||||
|
|
||||||
|
tapScriptRoot := tapscriptTree.RootNode.TapHash()
|
||||||
|
|
||||||
|
// With the tapscript root obtained, we'll tweak the revocation key
|
||||||
|
// with this value to obtain the key that HTLCs will be sent to.
|
||||||
|
htlcKey := txscript.ComputeTaprootOutputKey(
|
||||||
|
revokeKey, tapScriptRoot[:],
|
||||||
|
)
|
||||||
|
|
||||||
|
return &HtlcScriptTree{
|
||||||
|
TaprootKey: htlcKey,
|
||||||
|
SuccessTapLeaf: successTapLeaf,
|
||||||
|
TimeoutTapLeaf: timeoutTapLeaf,
|
||||||
|
TapscriptTree: tapscriptTree,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SenderHTLCScriptTaproot constructs the taproot witness program (schnorr key)
|
||||||
|
// for an outgoing HTLC on the sender's version of the commitment transaction.
|
||||||
|
// This method returns the top level tweaked public key that commits to both
|
||||||
|
// the script paths.
|
||||||
|
//
|
||||||
|
// The returned key commits to a tapscript tree with two possible paths:
|
||||||
|
//
|
||||||
|
// - Timeout path:
|
||||||
|
// <local_key> OP_CHECKSIGVERIFY
|
||||||
|
// <remote_key> OP_CHECKSIG
|
||||||
|
//
|
||||||
|
// - Success path:
|
||||||
|
// OP_SIZE 32 OP_EQUALVERIFY
|
||||||
|
// OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
|
||||||
|
// <remote_htlcpubkey> OP_CHECKSIG
|
||||||
|
// OP_CHECKSEQUENCEVERIFY
|
||||||
|
//
|
||||||
|
// The timeout path can be spent with a witness of (sender timeout):
|
||||||
|
//
|
||||||
|
// <receiver sig> <local sig> <timeout_script> <control_block>
|
||||||
|
//
|
||||||
|
// The success path can be spent with a valid control block, and a witness of
|
||||||
|
// (receiver redeem):
|
||||||
|
//
|
||||||
|
// <receiver sig> <preimage> <success_script> <control_block>
|
||||||
|
//
|
||||||
|
// The top level keyspend key is the revocation key, which allows a defender to
|
||||||
|
// unilaterally spend the created output.
|
||||||
|
func SenderHTLCScriptTaproot(senderHtlcKey, receiverHtlcKey,
|
||||||
|
revokeKey *btcec.PublicKey, payHash []byte) (*HtlcScriptTree, error) {
|
||||||
|
|
||||||
|
// Given all the necessary parameters, we'll return the HTLC script
|
||||||
|
// tree that includes the top level output script, as well as the two
|
||||||
|
// tap leaf paths.
|
||||||
|
return senderHtlcTapScriptTree(
|
||||||
|
senderHtlcKey, receiverHtlcKey, revokeKey, payHash,
|
||||||
|
)
|
||||||
|
}
|
||||||
// ReceiverHTLCScript constructs the public key script for an incoming HTLC
|
// ReceiverHTLCScript constructs the public key script for an incoming HTLC
|
||||||
// output payment for the receiver's version of the commitment transaction. The
|
// output payment for the receiver's version of the commitment transaction. The
|
||||||
// possible execution paths from this script include:
|
// possible execution paths from this script include:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user